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

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

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

这样就可以了:

char array[N]; char *p; char *end; for (p = array, end = array + N; p < end; ++p) do_something(p); 

(做*end将是一个错误。)

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

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

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

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

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

C标准明确指出这个元素是一个有效的内存地址,但是取消引用它仍然不是一个好主意。

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

连续有16个字节,但是:

 begin + size == FFF0 + 10 (16 in hex) == 10000 

由于指针大小而包装到0000。 现在循环条件:

 curr < end == FFF0 < 0000 == false 

循环不会迭代数组,而是什么都不做。 这会破坏很多代码,所以C标准说分配是不允许的。

例如,你可以远远超过数组1

 int main() { char *string = "string"; int i = 0; for(i=0; i< 10;i++) { printf("%c\n", string[i]); } return 0; } 

将在单词字符串结束后打印垃圾,无论手中存在什么内存。