【问题标题】:Why does after derefrencing the pointer prints different values?为什么取消引用指针后会打印不同的值?
【发布时间】:2018-07-23 18:40:37
【问题描述】:
#include <stdio.h>

int main()
{
    int i = 10;
    int *p = &i;
    foo(&p);
    printf("%d ", *p);
    printf("%d ", *p);
}

void foo(int **const p)
{
    int j = 11;
    *p = &j;
    printf("%d ", **p);
}

上面的code打印:

11 11 Undefined-value

为什么第三次打印未定义的值? 为什么最后不打印11

【问题讨论】:

  • 这是未定义的行为,您只能保证获得前 11 个。其他两个打印语句可以打印任何内容
  • 我得到了 11 11 和一个未定义的值
  • 有时你会得到 11 11 和一个未定义的值。有时你不会。
  • 此链接显示在main 中对printf 的第一次调用原则上已经存在问题,并让您尝试答案中提供的修复:taas.trust-in-soft.com/tsnippet/t/c545ff40
  • 如果没有其他原因,它是否值得包含在 wiki 中,它只是作为未定义行为危险的非常明显的演示?

标签: c pointers memory-address


【解决方案1】:

foo 内部,您将*p(与main 中的p 相同)设置为局部变量的地址。当foo 返回时,该变量超出范围,因此该地址不会指向任何有意义的地方。

返回局部变量的地址并随后取消引用该地址调用undefined behavior

至于可能发生了什么,当你从foo返回后第一次阅读*p时,j驻留在堆栈上的地址还没有被重用,因为没有其他函数已被调用。然后,当您调用printf 时,该地址确实会在printf 的堆栈帧中重用。然后下次读取*p 时,它会包含最后一个函数调用放在那里的任何内容。

不过,重申一下,这是未定义的行为,因此您不能依赖这种情况。使用不同的编译器甚至具有不同优化设置的相同编译器进行编译可能会改变未定义行为的表现方式。

作为未定义行为的示例,当我使用带有 -O0 的 gcc 进行编译时,我得到以下输出:

11 11 11 

使用 -O1:

11 11 0

使用-O2:

11 0 0

使用-O3:

11 0 0

请注意,在一种情况下,我们得到了“预期”的输出,而在其他情况下,我们却没有,而且方式不同。

您可以通过将j 定义为static 或在文件范围(即在函数之外)来避免此问题,在这种情况下,变量的生命周期是整个程序的生命周期,因此其地址始终有效。

【讨论】:

    【解决方案2】:

    试试这个(不要将int j定义为局部变量):

    #include <stdio.h>
    
    void foo(int **const p);
    int j = 11;          // define int j outside of the function as public
    
    int main()
    {
        int i = 10;
        int *p = &i;
        foo(&p);
    
        printf("%d ", *p);
        printf("%d ", *p);
    }
    
    void foo(int **const p)
    {
        *p = &j;
        printf("%d ", **p);
    }
    

    输出将是:

    11 11 11
    

    当您在void foo(int **const p) 中定义int j = 11; 时,会执行以下步骤:

    1. *pj地址
    2. 所以**p 将是11foo 函数返回

    现在因为int j;是本地的,所以j内存会在foo调用后被销毁!

    **p 指向一个未定义的内容,在这种状态下你会得到Undefined-value 的输出。

    【讨论】:

    • @Sanj.K 如果这对你有帮助,请接受这个答案。
    • **p 不指向未定义的地址。它指向一个内容未定义的地址。无论如何,这不是重点。关键是当您取消引用该地址时未定义的行为。
    猜你喜欢
    • 2015-03-07
    • 1970-01-01
    • 1970-01-01
    • 2011-02-24
    • 2013-04-21
    • 2020-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多