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

时间:2009-06-20 05:27:26

标签: c pointer-arithmetic

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

4 个答案:

答案 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;
}

将在单词字符串结束后打印垃圾,无论是手中的内存还是其他内容。