2011-11-24 59 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);