c - 无法理解指向指针输出的指针 : 15 15

标签 c pointers undefined-behavior

有人可以帮助理解以下代码的输出如何是 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 和其他人指出的那样,这远不是此代码的唯一问题。但同样,这基本上就是正在发生的事情。

<小时/>

  1. 包括但不限于:foo 的隐式声明(返回int的函数)与显式定义之间的类型不匹配 foo(返回 void 的函数),尝试通过非 const 写入 const 限定指针 表达式并取消引用无效指针。

关于c - 无法理解指向指针输出的指针 : 15 15,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47316476/

相关文章:

c - 用 %p 打印空指针是未定义的行为?

c++ - clang 可以在编译时警告未定义的行为吗?

java - Java 中方法调用和参数之间的求值顺序

c - 结构和文件有什么区别?

c - 使用 Xor 交换产生错误结果

c++ - 在函数内部使用 "new"

c - 为什么 scanf 中不需要地址运算符?

c - 每个链接列表都有较小的数组,这在 C 中有意义吗?

c - 在 C 编程中声明一个没有 Size 的数组

C++,从 ‘char’ 到 ‘const char*’ 的无效转换