访问元素超出C中数组的末尾

nai*_*aen 13 c pointer-arithmetic

我一直在阅读K&R关于C的书,发现C中的指针算法允许访问超出数组末尾的一个元素.我知道C允许用记忆做几乎任何事情,但我只是不明白,这种特性的目的是什么?

小智 21

C不允许访问超出数组末尾的内存.但是,它允许指针指向超出数组末尾的一个元素.区别很重要.

这样就可以了:

char array[N];
char *p;
char *end;

for (p = array, end = array + N; p < end; ++p)
    do_something(p);
Run Code Online (Sandbox Code Playgroud)

(这样做*end会出错.)

这显示了此功能有用的原因:在数组结束后指向(不存在的)元素的指针对于比较(例如循环)非常有用.

从技术上讲,这就是C标准允许的一切.但是,实际上,C实现(编译器和运行时)不会检查是否访问超出数组末尾的内存,无论它是一个元素还是更多元素.必须有边界检查,这将减慢程序执行速度.最适合(系统编程,通用库)的程序C类型的速度往往比安全和安全边界检查所带来的更多.

这意味着C可能不是通用应用程序编程的好工具.


Tod*_*ner 16

通常,表示"结束"位置是有用的,这是一个超出实际分配的位置,因此您可以编写如下代码:

 char * end = begin + size;
 for (char * curr = begin; curr < /* or != */ end ; ++curr) {
    /* do something in the loop */
 }
Run Code Online (Sandbox Code Playgroud)

C标准明确说明这个元素是一个有效的内存地址,但解除引用它仍然不是一个好主意.

为什么有这个保证?假设你有一台机器有2 ^ 16字节的内存,地址0000-FFFF,16位指针.假设您创建了一个16字节的数组.内存可以在FFF0分配吗?

连续释放16个字节,但是:

begin + size == FFF0 + 10 (16 in hex) == 10000
Run Code Online (Sandbox Code Playgroud)

由于指针大小,它包装到0000.现在循环条件:

curr < end == FFF0 < 0000 == false
Run Code Online (Sandbox Code Playgroud)

循环不会迭代数组,而是无效.这会破坏很多代码,所以C标准说分配是不允许的.