有人可以帮助理解以下代码的输出如何是 15 15 吗?
#include <stdio.h>
void foo(int **p1);
int main()
{
int i = 10;
int *p = &i;
foo(&p); //address of constant pointer p passed to function
printf("%d\n", *p);
}
void foo(int **p1)
{
int j = 15;
*p1 = &j; //I don't get this line
printf("%d\n", **p1);
}
假设addr(i)=ff2,addr(指针p)=ff4,addr(j)=ff6
i=10,j=15
p= 地址(i),因此 p= ff2
p1=地址(p),所以p1=ff4
最佳答案
暂时忽略未定义的行为1,这就是正在发生的事情,或者至少是示例的意图。
首先,您有一个包含值 10
的整数对象 i
:
+----+
i: | 10 |
+----+
您创建一个指向i
的指针对象p
:
+---+ +----+
p: | | ----> i: | 10 |
+---+ +----+
您将p
的地址传递给foo
。函数参数p1
指向p
:
+---+ +---+ +----+
p1: | | ----> p: | | ----> i: | 10 |
+---+ +---+ +----+
在 foo
中,您创建值为 15
的整数对象 j
:
+----+
j: | 15 |
+----+
现在,这是有趣的部分 - 通过取消引用 p1
并赋值,将 p
设置为指向 j
j
到结果的地址。 *p1 == p
,因此通过扩展 *p1 = &j
实际上与编写 p = &j
相同。在该行之后,您将遇到以下情况:
+---+ +---+ +----+
p1: | | ----> p: | | ----> j: | 15 |
+---+ +---+ +----+
这就是为什么在 foo
中打印 **p1
的值会输出 15。p1 == &p
,因此 *p1 = = p == &j
,所以**p1 == *p == j == 15
。
现在,当函数 foo
退出时,j
不再存在,因此 p
不再是有效指针 - 它不再指向事件对象。由于它不再有效,因此取消引用它的行为是未定义;您的代码可能会崩溃,或者可能会损坏数据,或者可能看起来按预期工作,或者完全执行其他操作。
逻辑对象j
不再存在,但它曾经占用的内存仍然存在,并且将包含最后写入它的内容,即值15
。只要没有其他东西覆盖该内存,您就会继续看到*p == 15
。但这种行为并没有得到保证,您不应该依赖它。
正如 Vlad 和其他人指出的那样,这远不是此代码的唯一问题。但同样,这基本上就是正在发生的事情。
<小时/>- 包括但不限于:
foo
的隐式声明(返回int
的函数)与显式定义之间的类型不匹配foo
(返回void
的函数),尝试通过非const 写入
表达式并取消引用无效指针。const
限定指针
关于c - 无法理解指向指针输出的指针 : 15 15,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47316476/