当前位置:  开发笔记 > 编程语言 > 正文

数组索引在C中超出范围

如何解决《数组索引在C中超出范围》经验,为你挑选了3个好方法。

为什么C在数组索引超出限制的情况下进行区分

#include 
int main()
{
    int a[10];
    a[3]=4;
    a[11]=3;//does not give segmentation fault
    a[25]=4;//does not give segmentation fault
    a[20000]=3; //gives segmentation fault
    return 0;
}

据我所知,它正在尝试访问分配给进程或线程的内存,如果是a[11]或者a[25]它正在超出堆栈边界a[20000].

为什么编译器或链接器没有出错,他们不知道数组大小?如果没有,那么如何sizeof(a)正常工作?



1> JaredPar..:

问题是C/C++实际上没有对数组进行任何边界检查.这取决于操作系统,以确保您访问有效的内存.

在这种特殊情况下,您将声明一个基于堆栈的数组.根据特定的实现,访问数组边界外部只会访问已分配的堆栈空间的另一部分(大多数操作系统和线程为堆栈保留一定的内存部分).只要您恰好在预先分配的堆栈空间中玩游戏,一切都不会崩溃(注意我没说工作).

最后一行发生的事情是,您现在已经访问了超出为堆栈分配的内存部分.因此,您将索引到未分配给进程或以只读方式分配的内存部分.操作系统看到这一点并向进程发送seg错误.

这是C/C++在边界检查方面如此危险的原因之一.


*real*问题是C和C++ _implementations_通常不检查边界(既不在编译也不在运行时).他们完全被允许这样做.不要因此而责怪语言.
但为什么编译器或链接器没有出错,他们不知道数组大小?如果没有那么sizeof(a)如何正常工作?
作为上述例子,想象一下"a [b] = 1;"的简单情况. - 数组绑定检查必须在运行时完成,这将为每个(或大多数)数组操作花费额外的CPU周期.

2> Johannes Sch..:

段错误不是C程序的预期操作,它会告诉您索引超出范围.相反,它是未定义行为的意外后果.

在C和C++中,如果声明一个类似的数组

type name[size];

您只能访问索引0最多的元素size-1.超出该范围的任何内容都会导致未定义的行为.如果索引接近范围,很可能您会读取自己程序的内存.如果索引大部分超出范围,很可能您的程序将被操作系统杀死.但你无法知道,任何事情都可能发生.

为什么C允许这样做?好吧,C和C++的基本要点是如果性能成本不提供功能.C和C++已经用于高性能关键系统.C已被用作内核和程序的实现语言,其中访问数组边界对于快速访问内存中相邻的对象非常有用.编译器禁止这样做是徒劳的.

为什么不警告呢?好吧,你可以把警告水平提高,并希望编译器的怜悯.这称为实施质量(QoI).如果某些编译器使用开放行为(例如,未定义的行为)来做好事,那么它在这方面具有良好的实现质量.

[js@HOST2 cpp]$ gcc -Wall -O2 main.c
main.c: In function 'main':
main.c:3: warning: array subscript is above array bounds
[js@HOST2 cpp]$

如果它看到你的硬盘格式化,看到数据访问超出范围 - 这对它来说是合法的 - 实现的质量将是相当糟糕的.我很高兴在ANSI C Rationale文档中阅读这些内容.



3> paxdiablo..:

如果您尝试访问您的进程不拥有的内存,通常只会出现分段错误.

什么你在的情况下看到a[11](和a[10]方式)是你的进程内存拥有但不属于a[]阵列.a[25000]到目前为止a[],它可能完全在你的记忆之外.

变化a[11]更加阴险,因为它会默默地影响另一个变量(或者当函数返回时可能导致不同分段错误的堆栈帧).

推荐阅读
wurtjq
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有