首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么取消引用后指针会打印不同的值?

为什么取消引用后指针会打印不同的值?
EN

Stack Overflow用户
提问于 2018-07-23 18:40:37
回答 2查看 90关注 0票数 2
代码语言:javascript
复制
#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打印:

代码语言:javascript
复制
11 11 Undefined-value

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

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-23 18:52:02

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

返回局部变量的地址,然后取消引用该地址调用未定义行为

至于可能发生的事情,当您在从*p返回后第一次读取foo时,由于没有调用其他函数,j驻留在堆栈上的地址还没有被重用。然后调用printf时,该地址确实会在printf的堆栈帧中被重用。然后,下一次读取*p时,它将包含放在那里的最后一个函数调用。

然而,要重申的是,这是未定义的行为,因此不能依赖于这种情况的发生。使用不同的编译器,甚至使用具有不同优化设置的同一编译器进行编译,可以更改未定义的行为如何显示自身。

作为一个未定义行为的示例,在使用-O0编译gcc时,我得到了以下输出:

代码语言:javascript
复制
11 11 11 

使用-O1:

代码语言:javascript
复制
11 11 0

使用-O2:

代码语言:javascript
复制
11 0 0

使用-O3:

代码语言:javascript
复制
11 0 0

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

您可以通过将j定义为static或文件作用域(即函数外部)来避免此问题,在这种情况下,变量的生存期为完整程序的生存期,因此其地址始终有效。

票数 4
EN

Stack Overflow用户

发布于 2018-07-23 18:58:09

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

代码语言:javascript
复制
#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);
}

产出将是:

代码语言:javascript
复制
11 11 11

当您在int j = 11;中定义void foo(int **const p)时,这些步骤如下:

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

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51485315

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档