指针在printf之后更改值 [英] Pointer changes value after printf
问题描述
所以今天我试图用C实现简单的堆栈,但是遇到了以下问题,我无法解决或解释为什么发生。
So today I was trying to implement simple stack in C, but I have encountered following issue that I can't resolve or explain why is happening.
#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;
}
上面的代码给出了一些奇怪的结果,如果我更换编译器,结果也会不同。
Code above gives some strange results, and also different ones if I change compiler.
我尝试过的第一个编译器是gcc,它给出以下输出:
First compiler I've tried is gcc and it gives following output:
0x7ffd6d96d3b0
0x7ffd6d96d3b0
First
Sample 1 0x7ffd6d96d3b0
Sample 2 0x7ffd6d96d3b0
Sample 1 0x7ffd6d96d3b0
Sample 2 0x400670
Sample 1 0x7ffd6d96d3b0
Sample 2 0x40068d
END
第二个结果来自c:
0x7ffd6d05fb30
0x7ffd6d05fb30
First
Sample 1 0x7ffd6d05fb30
Sample 2 0x7ffd6d05fb30
Sample 1 0x7ffd6d05fb30
Sample 2 0x2042030
Sample 1 0x7ffd6d05fb30
Sample 2 0x2042030
END
我的第一个问题是为什么当我从无效位置打印时,示例2甚至会发生变化调试吗?我也试图注释掉调试函数调用和结果ar e也很奇怪。在gcc中,样本均符合预期,但在clang中,样本2没有明显的原因存在差异。
My first question is why is Sample 2 even changing when I printf it from void debug? Also I have tried to comment out debug function call and results are also strange. In gcc samples are as expected all are matching, but in clang there is difference in sample 2 for no obvious reason.
我的第二个问题是为什么甚至
希望我已经发布了有关我所遇到的问题的足够信息,如果没有在评论中写信给我,以发布更多信息。
Hope I have posted enough information about the issue I am having, if not write me in comment to post more information.
推荐答案
您的 push
函数按值采用第二个参数,因此它会创建 struct stack_element
的本地副本。这意味着 this-> top =& to_add;
行将指针 top
重定向为指向局部变量(具有自动存储期限)。函数 push
结束后,变量的生存期结束,将 top
更改为悬空指针。因此,取消引用 this-> top-> next
(和 st-> top-> next
)调用未定义的行为。
Your push
function takes the second parameter by value, so it creates a local copy of the struct stack_element
. That means the line this->top = &to_add;
redirects the pointer top
to point at a local variable (with automatic storage duration). After the function push
ends that variable's lifetime ends, changing top
into a dangling pointer. Thus the dereferencing this->top->next
(and st->top->next
) invoke undefined behavior.
您最想做的是为 push $ c输入第二个参数$ c>作为指针:
void push(stack * this,stack_element * to_add)
并更改行:
What you most likely intended to do was take the second parameter for push
as a pointer: void push(stack* this, stack_element* to_add)
and change the line:
this->top = &to_add;
到
this->top = to_add;
注意:您建议在内部使用 malloc
push
是另一种可能性,但是可能会产生不清楚的代码,因为这将要求调用者知道 top
需要免费
d以避免内存泄漏。另外,您还可以提供一个析构函数函数,该函数负责所有内存管理,将其隐藏在调用者面前。
NOTE: Your suggestion of using malloc
inside push
is another possibility, however that might create unclear code, as it would require the caller to know that top
needs to be free
d in order to avoid memory leaks. Alternatively you could also provide a "destructor" function which would take care of all memory management, hiding it from the caller.
这篇关于指针在printf之后更改值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!