为什么这个C功能有副作用?

时间:2018-05-09 22:25:57

标签: c malloc

有人可以帮我理解这个C程序有什么问题吗?

#include <stdio.h>
#include <stdlib.h>
struct Box {
    int **value;
};
void nop(void) {
    /* Why does this function have side effects? */
    void *a = malloc(sizeof *a);
    free(a);
}
struct Box *makeBox(void) {
    int *value = NULL;
    struct Box *box = malloc(sizeof *box);
    box->value = &value;
    return box;
}
int main(void) {
    struct Box *box = makeBox();
    printf("Dereferenced: %p\n", *box->value);
    nop();
    printf("Dereferenced: %p\n", *box->value);
}

如果我运行它,它会打印:

Dereferenced: (nil)
Dereferenced: 0x562831863727

但是,如果我注释掉nop函数,我会得到:

Dereferenced: (nil)
Dereferenced: (nil)

有人可以帮我理解为什么调用nop更改*box->value

2 个答案:

答案 0 :(得分:2)

您的程序有未定义的行为。 box->value内的main指针包含不确定的值。在makeBox内部,它曾指向本地变量value,但现在makeBox已完成,并且该局部变量已经消失。尝试将其取消引用为*box->value会导致未定义的行为。这就是你观察到的。

答案 1 :(得分:2)

基本上nop()函数只是因为使用堆栈而产生“副作用”。问题出在makeBox()函数中,该函数设置指向堆栈变量的指针。我在代码段中添加了一些评论:

struct Box *makeBox(void) {
    // value is an integer pointer on the stack
    int *value = NULL;
    struct Box *box = malloc(sizeof *box);
    // box->value is set to the address of the stack location of value
    box->value = &value;
    return box;
}

nop()在堆栈上分配a时,它基本上是在你的另一个指针所在的堆栈上踩踏。这是一个为什么你不能返回指向堆栈变量的指针的例子,因为它不会在分配它的函数范围之外持久存在。