函数中空指针初始化时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

免责声明:我是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 *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;