为什么指向数组第一个元素的指针在取消引用后,计算结果为第三个元素? [重复]

问题描述 投票:0回答:1

当我尝试在 printf() 内部执行此操作时,它会取消对第三个元素的引用,我还尝试使用后增量和预增量来取消对该指针的引用。

这是我的代码:

#include <stdio.h>
int main()
{                                                                                                                
    int arr[4] = {1, 2, 3, 4};
    int *ptr = &arr[0];
    
    printf("ptr = %p, &arr[0] = %p\n", ptr, &arr); // same addrs
    printf("*ptr = %d\n", *ptr); // 1, as expected

    // PROBLEM IS HERE:
    printf("%d, %d, %d\n", *ptr, *ptr++, *++ptr); // 3, 2, 2  

    return 0;
}

我尝试过一些有趣的事情,例如将元素添加到数组中,将 printf 中的表达式顺序更改为, 但这给了我另一个令人困惑的答案:

*++ptr, *ptr++, *ptr // 3, 1, 1

但是,当我按顺序尝试 printfs 时,可以这么说:

printf("*ptr = %d\n", *ptr);
printf("*ptr++ = %d\n", *ptr++);
printf("*++ptr = %d\n", *++ptr);

一切都按预期进行。

我对最后一个 printf 中的初始脚本的期望:

  1. *ptr = 1 显然,因为它是第一个元素
  2. *ptr++ = 1 首先我们取消引用,然后后递增才完成它的事情
  3. *++ptr = 3 在之前的递增之后,我们位于第二个元素,现在预递增首先进行,因此我们位于第三个元素的 addr,并且,取消引用给我们 3 - 第三个元素的值。

那么,为什么我得到了3、2、2?

c pointers printf post-increment pre-increment
1个回答
0
投票

你的程序正在调用未定义的行为,这意味着任何事情都可能发生,因此你不能依赖任何特定的行为。实际发生的情况可能取决于几个因素,例如您使用的编译器、编译器的版本、编译器使用的设置等。

行为未定义的原因是因为 ISO C11 标准§6.5 ¶2 规定了以下内容:

如果标量对象上的副作用相对于同一标量对象上的不同副作用或使用同一标量对象的值的值计算是无序的,则该行为是未定义的。

在您的程序中,在

printf 的各个参数的评估之间不存在 序列点

。其中两个参数(
*ptr++
*++ptr
)会更改 
ptr
 的值(作为副作用),另外一个参数计算 
ptr
 的值。因此,根据上面引用的 ISO C 标准的段落,您的程序的行为是未定义的。

请参阅此相关问题以获取更多信息:

为什么这些构造使用预增量和后增量未定义行为?

© www.soinside.com 2019 - 2024. All rights reserved.