我一直在读K& R关于C的书,发现C中的指针算法允许访问超出数组末尾的一个元素。我知道C允许用记忆做几乎任何事情,但我只是不明白,这种特性的目的是什么?
答案 0 :(得分:20)
C不允许访问到超出数组末尾的内存。但是,它允许指针指向超出数组末尾的一个元素。区别很重要。
因此,这没关系:
char array[N];
char *p;
char *end;
for (p = array, end = array + N; p < end; ++p)
do_something(p);
(执行*end
将是一个错误。)
这表明了这个特性有用的原因:在数组结束后指向(不存在的)元素的指针对于比较很有用,例如在循环中。
从技术上讲,这就是C标准允许的一切。但是,实际上,C实现(编译器和运行时)不会检查是否访问超出数组末尾的内存,无论它是一个元素还是更多元素。必须有边界检查,这将减慢程序执行速度。最适合(系统编程,通用库)的程序类型往往比速度比安全和安全边界检查更有益。
这意味着C可能不是通用应用程序编程的好工具。
答案 1 :(得分:16)
通常,表示“结束”位置是有用的,这是一个超过实际分配的位置,因此您可以编写如下代码:
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标准说分配是不允许的。
答案 2 :(得分:0)
如果您读取或写入超出分配的内存,那么 C 标准会说它的“未定义行为”。 这意味着几乎任何事情都有可能发生,可能是现在,可能是一周后,也可能是 5 年后,或者可能永远不会发生,而您却侥幸逃脱。
我的老板有几句格言: “没有正确的 C 程序,只有尚未出错的程序” “关于内存损坏,你能说的唯一明智的话就是什么都没有。”
他总是对的。
答案 3 :(得分:-2)
你可以远远超过数组1 例如`
int main()
{
char *string = "string";
int i = 0;
for(i=0; i< 10;i++)
{
printf("%c\n", string[i]);
}
return 0;
}
将在单词字符串结束后打印垃圾,无论是手中的内存还是其他内容。