2017-03-11 38 views
0

所以今天我试图在C中实现简单堆栈,但遇到以下问题,我无法解决或解释为什么会发生。指针在printf后更改值

#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 

第二个结果是从铛:

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

Sample 1 0x7ffd6d05fb30 
Sample 2 0x2042030 

Sample 1 0x7ffd6d05fb30 
Sample 2 0x2042030 

END 

我的第一个问题是,为什么是样品2甚至改变时我从void调试printf它?另外我也试过注释调试函数调用,结果也很奇怪。在海湾合作委员会样品如预期所有匹配,但在铛中有没有明显的原因样品2有差异。

我的第二个问题是为什么在编译此代码时编译器之间有甚至不同?

希望我发布了足够的有关我遇到的问题的信息,如果不写信给我发表评论以发布更多信息。

+1

你的'push'函数改变'this-> top'指向栈上的一个值。这个值在函数结束之后超出了范围(结束它的生命周期)创建一个悬挂指针,所以通过'this-> top-> next'来解除引用* undefined behavior * – UnholySheep

+0

那么,malloc新变量是个好主意,附加到这个 - >顶部? – acac97

+0

我通过一个答案添加了一些解释 - 我希望能够说清楚 – UnholySheep

回答

3

您的push函数按值取第二个参数,因此它创建了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需要为freed以避免内存泄漏。或者,你也可以提供一个“析构函数”功能,它将处理所有的内存管理,将其从调用者中隐藏起来。

+0

感谢奇妙的回答UnholySheep。你提出的解决方案就像魅力一样。最重要的是,我学到了一些东西。再次感谢:D – acac97