c和数组边界中的指针算术

时间:2011-03-17 15:57:14

标签: c pointers

我正在浏览webpage,其中有一些常见问题解答,我发现了这个陈述。

  

同样,如果一个有10个元素和ip   指向[3],你无法计算或   访问ip + 10或ip - 5. (有   一个特例:你可以,在这   case,compute,但不是access,a   指向不存在元素的指针   就在数组的末尾,   在这种情况下,它是& a [10]。

我对声明感到困惑

  

你无法计算ip + 10

我可以理解访问元素超出界限是未定义的,但计算!!!

我编写了以下代码片段计算(让我知道这是网站对计算的意思)指针越界。

#include <stdio.h>                                                                                                                                                                  

int main()                                                                                                                                                                          
{                                                                                                                                                                                   
        int a[10], i;                                                                                                                                                               
        int *p;                                                                                                                                                                     

        for (i = 0; i<10; i++)                                                                                                                                                      
                a[i] = i;                                                                                                                                                           

        p = &a[3];                                                                                                                                                                  

        printf("p = %p and p+10 = %p\n", p, p+10);                                                                                                                                  
        return 0;                                                                                                                                                                   
}                     

$ ./a.out                                                                                                                                     
p = 0xbfa53bbc and p+10 = 0xbfa53be4     

我们可以看到p + 10指向超过p的10个元素(40个字节)。那么该声明在网页中的确切含义是什么。我错误地解释了什么。

即使在K&amp; R(A.7.7)中也发表了这样的声明:

  

+运算符的结果是   操作数的总和。指向的指针   数组中的对象和任何值   可以添加整数类型。 ......   sum是与...相同类型的指针   原始指针,并指向   同一个数组中的另一个对象,   适当地偏离原来的   宾语。因此,如果P是指向的指针   数组中的对象,表达式P + 1   是指向下一个对象的指针   阵列。 如果和指针指向   在数组范围之外,   除了在第一个位置以外   高端,结果是   未定义。

“未定义”是什么意思。这是否意味着总和将是未定义的,或者它仅仅意味着当我们取消引用它时行为是未定义的。即使我们不取消引用它,只是计算指向元素越界的指针,操作是否未定义。

3 个答案:

答案 0 :(得分:9)

未定义的行为意味着:绝对可能发生任何事情。它可以默默地成功,它可能会无声地失败,它可能会使程序崩溃,它可能会蓝屏您的操作系统,或者它可能会擦除您的硬盘驱动器。其中一些不太可能,但就C语言标准而言,所有这些都是允许的行为

在这种特殊情况下,是的,C标准说即使计算有效数组边界之外的指针的地址而不解除引用,也是未定义的行为。它说这是因为有一些神秘的系统,这样的计算可能会导致某种类型的错误。例如,您可能在可寻址内存的最末端有一个数组,并且构造一个超出该指针的指针会导致特殊地址寄存器溢出,从而产生陷阱或故障。 C标准希望允许这种行为,以便尽可能便携。

但实际上,您会发现构建这样一个无效地址而不解除引用它在绝大多数系统中都有明确定义的行为,这些行为在常见用法中会遇到。除非您尝试取消引用,否则创建无效的内存地址不会产生任何不良影响。但是,当然,最好避免创建那些无效的地址,这样即使在那些神秘的系统上,你的代码也能完美运行。

答案 1 :(得分:4)

网页措辞令人困惑,但在技术上是正确的。 C99 language specification (section 6.5.6)讨论了加法表达式,包括指针算法。子项目8明确规定,计算一个超过数组末尾的指针不应导致溢出,但除此之外,行为未定义。

在更实际的意义上,C编译器通常会让你逃脱它,但你对结果值的处理取决于你。如果你试图将结果指针取消引用一个值,就像K&amp; R所说的那样,行为是未定义的。

在编程术语中,未定义的意思是“不要那样做”。基本上,它意味着定义语言如何工作的规范在这种情况下没有定义适当的行为。因此,理论上任何事情都可能发生。通常情况下,您的程序中会出现一个无声或嘈杂(段错误)的错误,但许多程序员喜欢开玩笑导致其他可能的结果导致未定义的行为,例如删除所有文件。

答案 2 :(得分:2)

在以下情况中,行为将是未定义的

int a[3];
(a + 10) ; // this is UB too as you are computing &a[10]
*(a+10) = 10; // Ewwww!!!!