函数中空指针初始化时C指针地址的更改
免责声明:我是C语言新手,从其他语言来到这里。我所观察到的东西打破了我的头脑,我甚至没有一个起点来解释所观察到的行为 场景:使用一个自行编写的堆栈实现来了解该语言并比较不同的方法 正在使用的编译器:函数中空指针初始化时C指针地址的更改,c,C,免责声明:我是C语言新手,从其他语言来到这里。我所观察到的东西打破了我的头脑,我甚至没有一个起点来解释所观察到的行为 场景:使用一个自行编写的堆栈实现来了解该语言并比较不同的方法 正在使用的编译器: gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609 最小化代码示例: #include <stdio.h> struct stack_entry { struct stack_entry *next; int *it
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.12) 5.4.0 20160609
最小化代码示例:
#include <stdio.h>
struct stack_entry
{
struct stack_entry *next;
int *item;
};
struct stack
{
struct stack_entry *first;
};
void push_to_stack(struct stack *s_ptr, int *item)
{
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
printf("item_address@push_to_stack %p\n", s_ptr->first->item);
}
void pop_from_stack(struct stack *s_ptr)
{
printf("item_address@pop_from_stack %p\n", s_ptr->first->item);
int* result = NULL;
}
int main()
{
printf("\n--stack test--\n");
struct stack s = {};
struct stack *s_ptr = &s;
int value = 42;
push_to_stack(s_ptr, &value);
printf("item_address@main: %p\n", s_ptr->first->item);
pop_from_stack(s_ptr);
return 0;
}
当人们观察项时_address@pop_from_stack
因某些原因而不同。我预计产出:
--stack test--
item_address@push_to_stack 0x7ffdc30ee19c
item_address@main: 0x7ffdc30ee19c
item_address@pop_from_stack 0x7ffdc30ee19c
要接收预期的输出,我需要删除指针声明+初始化。如果我把它留在原地,就会出现意外的输出。因此,以下是变化:
// int* result = NULL;
但是为什么呢?这完全让我困惑。这将在以后触发未定义的行为:
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;
因为新的\u条目
将在推到\u堆栈()结束时死亡
但是为什么呢?这完全让我困惑
在未进行优化的情况下编译时,该行可能会使编译器在pop\u from\u stack()
帧中为result
分配空间。由于上述未定义的行为,这样的事情会使程序的行为发生变化。s\u ptr->first=&new\u entry
这是一个问题,因为新条目
是一个局部变量。在函数外部无效。在push_to_stack
中,您将new_entry
定义为局部变量。局部(非静态)变量只有其定义的函数的生命周期。一旦函数返回,这些变量就不再存在,所有指向它们的指针都将无效。这应该在任何一本像样的书、教程或课堂上提到。谢谢大家。因此,如果我无意中理解正确,那么当控制流返回到main时,地址保持稳定,因为没有必要清理堆栈来为新变量提供空间。但是,当由于代码块中的局部变量而需要创建新上下文时,这将强制执行。因此地址改变…@s10z要准确地知道,我们需要在您的特定平台中检查生成的程序集,但是是的,任何改变堆栈框架布局的操作都会给您带来不同的行为。不同的平台、编译器和标志也会显示出差异。
struct stack_entry new_entry = {.next = s_ptr->first, .item = item};
s_ptr->first = &new_entry;