【问题标题】:would that be wrong? And if so why is it? The output is 2500那会是错的吗?如果是这样,为什么会这样?输出为 2500
【发布时间】:2016-04-01 02:09:45
【问题描述】:

以下代码的输出是 2500。它包含指针。有人可以对此给出适当的解释吗?为什么它打印为2500?是通过指针声明还是有其他原因?

#include <stdio.h>

/* Two functions include and they are operated by main function */

int *f(int x) {
    /* Creates an variable */
    int p;
    p = x;
    return &p;
}

/* Here the initialization of the function g */
int *g(int x) {
    /* Creates an variable */
    int y;
    y = x;
    return &y;
}

/* This creates two pointers called x and y */
int main() {
    int *x, *y;
    /* Here call the functions f and g */
    x = f(100);
    /* Here call the function g */
    y = g(2500);
    /* How does it print 2500? */
    /* print the value of x */
    printf("%d \n", *x);
    return 0;
}

【问题讨论】:

  • @DanLowe 谢谢。为此并修复错字:)
  • 编译所有警告和调试信息(例如,gcc -Wall -Wextra -g,如果使用GCC...)然后使用调试器 (gdb)

标签: c pointers return-value


【解决方案1】:

您得到奇怪输出的原因是未定义的行为。您正在返回自动局部变量的地址,一旦函数结束,该变量将不再存在。

虽然,输出的解释可以用函数调用的堆栈帧来给出。由于最后一次调用函数g,传递给它的参数是2500,所以函数g的参数x被分配到堆栈上,2500被压入堆栈。当这个函数返回时,这个值从堆栈中弹出(虽然g的堆栈帧在返回给调用者后是无效的)并且它可能从它的堆栈帧中返回这个2500

【讨论】:

  • 如果我在调用g之后像调用f一样改变函数调用,那么输出将是100或其他值?
  • 很可能是100。但是,当有 UB 时,所有的赌注都没有了。
  • 如果我们打印 printf("%d \n", *y);然后答案是什么?有什么假设吗?
  • 结果几乎相同,但不要忘记 UB 在这里起作用。所以,没有什么可以确切地说出来。
  • @ThilinaViraj;阅读undefined behavior
【解决方案2】:

在您的两个函数中,您都尝试在函数中返回 local 变量的地址。一旦函数完成执行并且控制权返回给调用者,返回的地址就会变得无效(即变量超出范围)并且任何使用返回值的尝试都会调用undefined behavior

如果您必须从函数返回地址并在调用者中使用它,您将需要一个已通过动态内存分配器函数(如 malloc() 和 family)分配内存的指针。

【讨论】:

  • 如果我在调用g之后像调用f一样改变函数调用,那么输出将是100或其他值?
  • @ThilinaViraj 问题是,一旦你点击了 UB,什么都没有,绝对没有任何保证。在你的代码中使用 UB,你不能期望你的代码做任何理智或有意义的事情。
  • 是的。但是您可以做出假设并获得最终答案。我说的对吗?
  • @ThilinaViraj 不,你不能。请阅读我链接的关于 UB 的文章。
  • @Sourav Ghosh:如果您必须从函数返回地址并在调用者中使用它,那么使用静态局部变量也是有效的,因为这样做非常好。
【解决方案3】:

我认为可以使用堆栈来解释发生的事情。调用函数 f 时,堆栈的行为如下。 “ret”是返回地址。

2|   |    2|   |    2|   |    2| p |   
1|   | -> 1|   | -> 1|ret| -> 1|ret|
0|   |    0|100|    0|100|    0|100|

现在堆栈指针位于 2,并且该地址(p 的地址)被返回并分配给 main 中的 *x。当它从 f 返回时,所有堆栈值都被弹出,但实际上发生的只是减少堆栈指针的值。因此,推送的值仍然存在。 再次调用函数g,栈如下。

2| p  |    2| p  |    2| p  |    2| y  |
1|ret | -> 1|ret | -> 1|ret | -> 1|ret |
0|100 |    0|2500|    0|2500|    0|2500|

和函数f一样,返回p的地址并赋值给main中的*y。但请注意,它也与 p, 2 相同。因此 main 中的 *x 和 *y 都指向同一个位置。函数 g 将该地址的值设置为 2500,因此 *x 和 *y 都打印 2500。

希望这会有所帮助。 :)

【讨论】:

    猜你喜欢
    • 2018-11-10
    • 1970-01-01
    • 2012-07-17
    • 1970-01-01
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多