C 奇数空指针行为

C 奇数空指针行为,c,pointers,linked-list,C,Pointers,Linked List,我正在尝试使用链表实现堆栈。我的堆栈构造函数createStack()创建一个空(虚拟)元素,并返回指向该元素(堆栈顶部)的双指针。我的push()方法检查堆栈是否有伪元素;如果它这样做,它将填充虚拟对象并返回,否则它将为新元素分配内存并执行必要的指针更新 我的问题是,我的*堆栈->下一个指针显然指向了NULL(0x0),两行之后它不等于NULL(0x17),但不知何故通过了NULL测试。在调用内部,它再次等于(0x17),但这次它没有通过NULL测试,这是应该的 所以我的问题是,这个指针到底是

我正在尝试使用链表实现堆栈。我的堆栈构造函数
createStack()
创建一个空(虚拟)
元素
,并返回指向该元素(堆栈顶部)的双指针。我的
push()
方法检查堆栈是否有伪元素;如果它这样做,它将填充虚拟对象并返回,否则它将为新元素分配内存并执行必要的指针更新

我的问题是,我的
*堆栈->下一个
指针显然指向了
NULL(0x0)
,两行之后它不等于
NULL(0x17)
,但不知何故通过了
NULL
测试。在调用内部,它再次等于
(0x17)
,但这次它没有通过
NULL
测试,这是应该的

所以我的问题是,这个指针到底是怎么回事?它是如何/为什么从
(0x0)
更改为
(0x17)
,如果它等于
(0x17)
它是如何通过
==NULL
测试的

//main.c
int main () {

    struct Element **stack;

    stack = createStack();

    printf("stack: %p\n", stack );

    printf("*stack->next: %p\n", (*stack)->next );

    if ( (*stack)->next == NULL )
        printf("yes the pointer is null\n" );

    printf("*stack->next: %p\n", (*stack)->next );

    if ( (*stack)->next == NULL )
        printf("yes the pointer is null\n" );

    push ( stack, 1000 );

//stack.c

struct Element {
    int value;
    struct Element *next;
};

int push ( struct Element **stack, int el ) {

    if ( (*stack)->next == NULL) {
        // first element, fill dummy element and return
        printf("first value: %i !", el);
        (*stack)->value = el;
        return 1;
    }

    printf("the pointer is not null\n");

    struct Element *newElement = malloc( sizeof( struct Element ) );

    if ( !newElement )
        return -1;

    newElement->value = el;

    //add element to front of list
    newElement->next = *stack;

    //update pointer to new first element
    *stack = newElement;

    return 1;
}

struct Element** createStack() { 

    struct Element *dummy = malloc( sizeof( struct Element ) );

    if (dummy == NULL )
        printf("malloc failed...");

    dummy->value = 99;
    dummy->next = NULL;

    struct Element **stack;

    stack = &dummy;

    return stack;
}
上面的代码生成以下输出:

stack: 0x7fff6c385ba8
*stack->next: 0x0
yes the pointer is null
*stack->next: 0x17
yes the pointer is null
the pointer is not null

暂时忘记您正在使用指针和指向指针的指针,假设您的
createStack()
例程如下所示:

int *createInt() {
    int dummy = 1;
    return &dummy;
}
函数在堆栈上为局部变量
dummy
分配(临时)空间,为其赋值,然后返回指向它的指针。这正是
createStack()
所做的,只是
dummy
恰好是一种更复杂的数据类型


问题在于,当函数返回并从堆栈中弹出其局部变量时,分配给
dummy
本身的内存被释放。因此,该函数返回一个指向可重用内存的指针。然后,当数据在后续函数调用期间从堆栈中推送和弹出时,它可以(并且确实)更改。

当该函数返回时,
createStack()
中的变量
dummy
不再存在-因此返回的指针指向不再存在的变量

这就是为什么您会看到奇怪的行为-
printf()
很可能在以前包含
dummy
的内存上进行写入,因此当您尝试通过悬挂指针检查该内存时,您会看到它意外地改变

您可以通过更改
createStack()
以返回
struct元素*
值来修复代码:

struct Element *createStack(void)
{  
    struct Element *dummy = malloc( sizeof( struct Element ) );

    if (dummy == NULL )
        printf("malloc failed...");
    else {
        dummy->value = 99;
        dummy->next = NULL;
    }

    return dummy;
}
并更改
main()
以适应(
push()
可以保持不变):


createStack
函数中,您将返回导致未定义行为的局部变量的地址:

struct Element** createStack() {

        struct Element *dummy = malloc( sizeof( struct Element ) );    
        ...
        struct Element **stack;    
        stack = &dummy;    
        return stack;
}
相反,您只需在main中有一个指向
struct元素的指针
,并从
createStack
函数返回指向新创建节点的指针:

struct Element *stack = createStack();
push ( &stack, 1000 );
并将指针
堆栈的地址传递给
ush
函数:

struct Element *stack = createStack();
push ( &stack, 1000 );