【问题标题】:Access element beyond the end of an array in C访问C中数组末尾之外的元素
【发布时间】:2009-06-20 05:27:26
【问题描述】:

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

【问题讨论】:

标签: c pointer-arithmetic


【解决方案1】:

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

因此,这没关系:

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

for (p = array, end = array + N; p < end; ++p)
    do_something(p);

(执行*end 会出错。)

这说明了此功能有用的原因:指向数组末尾(不存在的)元素的指针对于比较很有用,例如在循环中。

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

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

【讨论】:

    【解决方案2】:

    通常,表示“结束”位置是有用的,它是实际分配之后的位置,因此您可以编写如下代码:

     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 标准规定不允许分配。

    【讨论】:

      【解决方案3】:

      如果您在分配的内存之外读取或写入,则 C 标准会说它的“未定义行为”。 这意味着几乎任何事情都可能发生,可能是现在,可能在一周内,或者可能在 5 年后,或者可能永远不会发生,而你却侥幸逃脱。

      我的老板有几句格言: “没有正确的 C 程序,只有一个还没有出错的程序” “关于内存损坏,你能说的唯一明智的事情就是什么。”

      他永远是对的。

      【讨论】:

        【解决方案4】:

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

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

        将在字符串结束后打印垃圾,无论之前放在内存中的任何内容。

        【讨论】:

        • 它可能会打印垃圾,格式化你的硬盘,或者让恶魔飞出你的鼻子;这就是未定义行为的本质。
        • 好吧,仅仅从内存位置读取不太可能格式化您的硬盘驱动器或导致恶魔飞出您的鼻子。然而,给它写信……
        • 即使读取错误的指针也可能导致您的程序在未来崩溃。见blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx
        • 如果是内存映射设备I/O口,光读肯定会导致坏事发生。当然,这在内核之外是不可能的。
        • 或者在嵌入式系统中。我的硬件设计伙伴喜欢构建只写和只读端口,不加选择的访问会导致硬件执行通常只会在演示中显示症状的意外事情。
        猜你喜欢
        • 2020-08-16
        • 2013-02-11
        • 2011-01-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-09
        相关资源
        最近更新 更多