【问题标题】:Weird pointer behaviour in WindowsWindows 中奇怪的指针行为
【发布时间】:2021-07-01 05:47:15
【问题描述】:

我一直在尝试理解指针,特别是指针[i] 表示法,它相当于 *(pointer + i),即取消引用下一个地址的值,所以如果它是一个 int 指针而不是下一个4 字节地址。我尝试在下面运行以下代码:

#include <stdio.h>

int main(void){
  int x = 10;
  int y = 20;

  int* z = &y;
  printf("address of x: %u ", &x);
  printf("address of y: %u", &y); 
  printf("value at address: %u \n", *(z+1));

}

我注意到 'y' 在 'x' 之前存储了 4 个字节,并认为我可以通过 z[1] 或 *(z+1) 返回存储在 x 地址的值,这很好。

但是,当我删除前 2 个 printf 时,我最终输出的是地址而不是实际值 (10),以下是此案例的代码:

#include <stdio.h>

int main(void){
  int x = 10;
  int y = 20;

  int* z = &y;
  printf("value at address: %u \n", *(z+1));

}

我假设 *(z+1) 不再指代与变量 'x' 相同的内存区域,但我很困惑为什么代码中的这种更改会导致这种情况。

一开始我以为是一次性的,所以我尝试了多次,每次都得到相同的结果。

更令人困惑的是代码如何在 ubuntu 和 macos 上按预期工作,但在 windows 上却没有。

任何有关这方面的帮助都会很棒,谢谢。

【问题讨论】:

  • 您是否尝试过使用调试器对这两种情况执行堆栈跟踪?
  • 你确定第二个例子中打印的值不只是一些垃圾值吗?
  • 可能是这样,但我仍然不知道为什么删除这 2 个打印件会导致这种情况。
  • 为什么编译器会浪费内存并保留在您的程序中从未使用过的x?该变量很可能在您的可执行文件中根本不存在。您还可以通过在 printf 中使用无效的格式说明符并越界访问内存来调用未定义的行为。
  • 打印指针,你必须使用%p而不是%u

标签: c pointers memory-address


【解决方案1】:

这里我只能回答你的部分问题并介绍我的 观察。

这是修改后的代码。

#include <stdio.h>

int main(void) {
  int x = 10;
  int y = 20;
  int *intp = &y;

  //  printf("address of x is %p.\n", &x);
  //  printf("address of y is %p.\n", &y);
  printf("*(intp + 1) is %u.\n", *(intp + 1));
  printf("*(intp)     is %u.\n", *(intp));
  printf("*(intp - 1) is %u.\n", *(intp - 1));
  printf("difference of addresses: &x - &y = %d.\n", &x - &y);

  return 0;
}

我得到*(intp) 的一致结果, *(intp - 1)&amp;x - &amp;y,而 *(intp + 1) 会改变。输出之一是

*(intp + 1) is 2028820428.
*(intp)     is 20.
*(intp - 1) is 10.
difference of addresses: &x - &y = -1.

但是,如果我使用 &amp;x 注释掉该行,

//  printf("difference of addresses: &x - &y = %d.\n", &x - &y);

输出会是一致的,如下

*(intp + 1) is 10.
*(intp)     is 20.
*(intp - 1) is 0.

我的想法是,在我的 Linux 上的 gcc 10.2.0 上,

  • 在第一种情况下,当使用&amp;x 时,x 是 存储在比y 低4 个字节的地址。作为 int 在我的电脑上是 4 个字节,&amp;x - &amp;y 总是-1
  • 第二种情况,不使用&amp;x时,x 存储在比y 高4 个字节的地址。

所以编译器确实设置了空间来存储xy,即使不使用 x。但是我 不知道为什么他们的立场在这两种情况下会有所不同。编译器 可以尝试优化代码,但我对此知之甚少。

另外,如果你想尝试使用gdb 来测试 地址,你可以试试

gcc -g thecode.c
gdb a.out
(gdb) break main
(gdb) run
(gdb) p &x
(gdb) p &y
(gdb) p &x + 1
(gdb) step
(gdb) (press enter directly to use the last same command...)
(gdb) quit

【讨论】:

  • *intp 是一个int,使用%u 打印它会调用UB。而&amp;x - &amp;y 是一个ptrdiff_t,您还可以通过使用%d 而不是%td 打印它来调用UB
猜你喜欢
  • 2020-01-22
  • 2020-11-28
  • 2012-05-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-31
  • 2019-04-27
  • 1970-01-01
相关资源
最近更新 更多