奇数空指针行为

时间:2011-11-24 02:55:50

标签: c pointers linked-list

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

我遇到的问题是我的*stack->next指针显然指向了NULL (0x0),然后两行后它不等于NULL (0x17)但是以某种方式通过了NULL {1}}测试。在推送它的调用内部再次等于(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

3 个答案:

答案 0 :(得分:3)

暂时忘记你正在使用指针和指针指向,并假设你的createStack()例程看起来像这样:

int *createInt() {
    int dummy = 1;
    return &dummy;
}

该函数在堆栈上为局部变量dummy分配(临时)空间,为其赋值,然后返回指向它的指针。这正是您的createStack()所做的,只是您的dummy恰好是更复杂的数据类型。

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

答案 1 :(得分:0)

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

这就是为什么你看到奇怪的行为 - printf()可能正在写入以前包含dummy的内存,所以当你试图通过你的悬空指针检查那个内存时,你会看到它意外地改变了

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

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()可以保持不变):

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 );

答案 2 :(得分:0)

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

struct Element** createStack() {

        struct Element *dummy = malloc( sizeof( struct Element ) );    
        ...
        struct Element **stack;    
        stack = &dummy;    
        return stack;
}

相反,你可以在main中有一个指向struct Element的指针,并从createStack函数返回指向新创建的节点的指针:

struct Element *stack = createStack();

并将指针stack的地址传递给ush函数:

push ( &stack, 1000 );