2011-11-24 62 views
1

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

我的问题是,我*stack->next指针显然指向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 

回答

3

忘记为你与指针和指针到指针工作了一会儿,假设你createStack()程序是这样的:

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

堆栈的局部变量dummy上的功能分配(临时)的空间,它分配一个值,然后返回一个指向它的指针。这正是你的createStack()所做的,只不过你的dummy碰巧是一个更复杂的数据类型。

问题是分配给dummy本身的内存在函数返回并从堆栈中弹出其局部变量时被释放。所以这个函数返回一个指向可用于重用的内存的指针。然后它可以(并且)在随后的函数调用期间随着数据被推出并从栈中弹出而改变。

0

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

这就是为什么你看到奇怪的行为 - 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); 
0

createStack功能你返回导致未定义行为的局部变量的地址:

struct Element** createStack() { 

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

相反,你可以有一个指向主struct Element和指针从createStack函数返回到新创建的节点:

struct Element *stack = createStack(); 

而且通过指针stackush函数的地址:

push (&stack, 1000);