指针在printf之后改变值

时间:2017-03-11 13:48:49

标签: c pointers gcc printf clang

所以今天我试图在C中实现简单的堆栈,但是我遇到了以下无法解决或解释原因的问题。

#include<stdio.h>

typedef struct stack_element stack_element;
typedef struct stack stack;

struct stack_element
{
    void* data;
    stack_element* next;
};

struct stack
{
    stack_element* top;
    int size;
    int max_size;
};

void push(stack* this, stack_element to_add)
{
    if(this->top == NULL)
    {
        this->top = &to_add;
        this->top->next = this->top;
        printf("%p\n", this->top);
        printf("%p\n", this->top->next);
        printf("First\n");
        return;
    }
}

void debug(stack* this)
{
    if(this->top == NULL) return;
    printf("Sample 1 %p\n", this->top);
    printf("Sample 2 %p\n\n", this->top->next);
}

int main()
{
    stack_element* tmp = malloc(sizeof(stack_element));
    stack* st = malloc(sizeof(stack)); 
    tmp->data = 1;
    push(st, *tmp);
    printf("Sample 1 %p\n", st->top);
    printf("Sample 2 %p\n\n", st->top->next);
    debug(st);
    printf("Sample 1 %p\n", st->top);
    printf("Sample 2 %p\n\n", st->top->next);
    printf("END\n");
    return 0;
}

上面的代码给出了一些奇怪的结果,如果我改变编译器也会有不同的结果。

我尝试过的第一个编译器是gcc,它提供了以下输出:

0x7ffd6d96d3b0
0x7ffd6d96d3b0
First
Sample 1 0x7ffd6d96d3b0
Sample 2 0x7ffd6d96d3b0

Sample 1 0x7ffd6d96d3b0
Sample 2 0x400670

Sample 1 0x7ffd6d96d3b0
Sample 2 0x40068d

END

第二个结果来自clang:

0x7ffd6d05fb30
0x7ffd6d05fb30
First
Sample 1 0x7ffd6d05fb30
Sample 2 0x7ffd6d05fb30

Sample 1 0x7ffd6d05fb30
Sample 2 0x2042030

Sample 1 0x7ffd6d05fb30
Sample 2 0x2042030

END

我的第一个问题是为什么当我从void debug中打印出来时,样本2甚至会发生变化?我也试图注释掉调试函数调用,结果也很奇怪。在gcc样本中,所有样本都是匹配的,但是在clang中,样本2的差异没有明显的原因。

我的第二个问题是为什么在编译此代码时编译器之间存在差异?

希望我已经发布了有关我遇到的问题的足够信息,如果没有写评论发布更多信息。

1 个答案:

答案 0 :(得分:3)

您的struct stack_element函数按值获取第二个参数,因此它会创建this->top = &to_add;的本地副本。这意味着行top将指针push重定向为指向本地变量(具有自动存储持续时间)。函数top结束变量的生命周期结束后,将this->top->next更改为悬空指针。因此,解除引用st->top->next(和push)会调用未定义的行为

您最有可能做的是将void push(stack* this, stack_element* to_add)的第二个参数作为指针:this->top = &to_add; 并更改该行:

this->top = to_add;

malloc

注意:您在push内使用top的建议是另一种可能,但这可能会产生不明确的代码,因为它需要调用者知道free需要{{1}} 1}} d以避免内存泄漏。或者你也可以提供一个&#34;析构函数&#34;该函数将负责所有内存管理,将其隐藏在调用者之外。