【问题标题】:Strange behavior of int **p? [duplicate]int **p 的奇怪行为? [复制]
【发布时间】:2012-10-03 13:46:00
【问题描述】:

可能重复:
How are two-dimensional arrays formatted in memory?

int map[3][3] = {1,2,3,4,5,6,7,8,9};
int **p = map;
printf( "%d", *p+1 );

谁能告诉我为什么结果是 5 ? 如果

printf( "%d", *p+2);

结果是 9 ? (Visual C++编译)

【问题讨论】:

  • 不是完全重复,但答案是完美的:)
  • 我想指出,这个例子甚至不能编译,至少在 Visual Studio 2010 中是这样。编译器给你一个错误,告诉你不能将二维数组分配给双指针.
  • 无论谁对我的回答投了反对票,请解释其中技术上不正确的地方 - 因为反对票不应该表明除了技术错误(或垃圾邮件,我的回答不是)之外的任何其他内容。
  • 但是 *(p + i) 会输出正确的数字 (i=1,2,...8)@devshorts 很棘手。

标签: c visual-c++


【解决方案1】:

要修改 H2C03 的答案...

您的第一个 deref 会将您带入数组 1 维度。具体来说,它会让您指向“1”的条目。

这里的大多数人似乎并没有完全弄清楚接下来会发生什么。此时 'p' 仍被视为指针。它认为它包含地址“1”。当您执行“+1”时,您实际上正在获得指针算术。由于 sizeof(int) (通常)为 4,因此您只需打印矩阵 +4 的第一个元素。因此 +2 转换为 +8 因为指针运算总是根据指针指向的“事物”的大小来完成。所以你得到 5 和 9。

将显示代码的快速解除。

mov eax, DWORD PTR ?p@@3PAPAHA      ; p
mov ecx, DWORD PTR [eax]            ; deref of p (which is '1')
add ecx, 4                          ; let's just +4 it and push it as the arg to printf
push    ecx
push    OFFSET $SG3670
call    _printf

【讨论】:

  • 谢谢,指针运算,就这样
【解决方案2】:

因为数组不是指针。双指针不等同于二维数组,因为数组在内存中是连续的。您的数组已创建并填充如下数据:

map[0][0] = 1
map[0][1] = 2
map[0][2] = 3
map[1][0] = 4
map[1][1] = 5
map[1][2] = 6
map[2][0] = 7
map[2][1] = 8
map[2][2] = 9

当您将其分配给双指针时,您做错了几件事。例如:

printf("%d", *p + 1);

没有做你认为它做的事。这是未定义的行为,因为*p 的类型是int *,但%d 格式说明符需要int。基本上,不要试图将数组视为指针,因为它们不一样。请阅读relevant part of the C FAQ 以了解如何正确处理这种情况。基本上,在这种情况下使用一维指针并正确索引就足够了。

演示:

【讨论】:

  • 我最初对您投了反对票,因为您说可以使用简单的指针线性访问它们。这是不正确的。您更新了答案,包括必须将它们作为数组数组引用,并且我删除了我的反对票。
  • @devshorts 不,这不是错误的。如果将数组的基地址分配给单指针,它将起作用。你试图让它工作,但你只考虑数组而不是指针。而且“必须将它们作为数组数组引用”甚至不在我的回答中。
  • 它不在答案中,但当时这就是您的示例有效地做的事情。我很感谢你修改你的答案
  • 在您的编辑中,您搞砸了代码块中的索引,之前它们是正确的,现在它们是错误的(两次 map[1][2]map[2][3] 而不是 map[2][1])。
  • @DanielFischer Hell,老实说,我还没有触及那部分!感谢您指出这一点,现在已修复。此外,图像的链接和 C 常见问题解答也被搞砸了! (发生了什么事?)
猜你喜欢
  • 2019-07-07
  • 1970-01-01
  • 2012-02-10
  • 1970-01-01
  • 2011-08-25
  • 2011-05-23
  • 2017-10-16
  • 2018-10-26
  • 2015-01-09
相关资源
最近更新 更多