指针运算与一个过去的数组元素然后解除引用,结果会是什么?

时间:2017-05-31 17:00:04

标签: c arrays clion pointer-arithmetic

如果我取消引用数组并添加超出数组中可用元素的5,那么打印的值是多少?我在我的IDE中返回32767,这没什么意义。

#include <stdio.h>

int main(void)
{

    int i;
    int meatBalls[5] = {1, 2, 3, 4, 5};

    printf("%12s %18s %6s\n", "Element", "Address", "Value");

    for(i=0; i < 5; i++) {
        printf("meatBalls[%d] \t %p \t %d \n", i, &meatBalls[i], meatBalls[i]);
    }

    printf("\nmeatBalls \t\t %p \n", meatBalls); /*already a pointer*/

    /*dereference meatBalls and it will update to the value e.g. 1*/

    printf("\n*meatBalls \t\t %d \n", *meatBalls); /*dereference with asterisk*/

    printf("\n*(meatBalls+2) \t\t %d \n", *(meatBalls+2)); /*dereference but also go through the array from 0 + 2*/

    printf("\n*(meatBalls+4) \t\t %d \n", *(meatBalls+4));

    printf("\n*(meatBalls+5) \t\t %d \n", *(meatBalls+5)); /*what is the number that this returns?*/

    return 0;
}

这是当前的输出,让我质疑“32767”:

     Element            Address  Value
meatBalls[0]     0x7fff5b714640      1 
meatBalls[1]     0x7fff5b714644      2 
meatBalls[2]     0x7fff5b714648      3 
meatBalls[3]     0x7fff5b71464c      4 
meatBalls[4]     0x7fff5b714650      5 

meatBalls        0x7fff5b714640 

*meatBalls       1 

*(meatBalls+2)       3 

*(meatBalls+4)       5 

*(meatBalls+5)       32767 

2 个答案:

答案 0 :(得分:6)

TL; DR: 不知道,不能说。

详细说明,在你的代码中

  printf("\n*(meatBalls+5) \t\t %d \n", *(meatBalls+5));
当您尝试访问超出限制内存时,

会导致undefined behavior

请注意强调访问。在这种情况下,指针算法是明确定义的(一个超过最后一个元素),尝试访问导致UB的原因。

引用C11,章节§6.5.6(强调我的

  

[...]如果表达式P指向最后一个   数组对象的元素,表达式(P)+1指向一个超过最后一个元素的元素   数组对象,如果表达式Q指向一个数组对象的最后一个元素,   表达式(Q)-1指向数组对象的最后一个元素。 如果两个指针都有   操作数和结果指向同一个数组对象的元素,或者指向最后一个数组对象的元素   数组对象的元素,评估不应产生溢出; 否则,   行为未定义。 如果结果指向一个超过数组对象的最后一个元素的那个,那么   不得用作被评估的一元*运算符的操作数。

也就是说,%p期望其参数为void*,并且由于printf()是一个可变参数函数,因此不会进行默认参数提升。因此,您需要将所有参数都转换为%p(void *)

答案 1 :(得分:2)

访问数组边界之外的元素是未定义的行为;所以你可以获得任何价值,但你的程序也可能崩溃。以下是C standard定义未定义行为的方式:

  

3.4.3未定义的行为

     

行为,在使用不可移植或错误的程序结构或错误数据时,为此   国际标准没有要求。

     

注意:可能未定义   行为的范围从完全忽略情况   不可预知的结果,在翻译或程序期间表现   以文件化的方式执行环境特征   (有或没有发出诊断信息),终止   翻译或执行(发布诊断   消息)。

这就是标准定义您的访问是未定义行为的地方:

  

J.2未定义的行为

     

1在以下情况下,行为未定义:

     

...

     
      
  • 数组下标超出范围,即使某个对象显然也是如此   可以使用给定的下标访问(如左值表达式)   a 1 [7]给出a [4] [5]中的声明)
  •