2014-01-22 14 views
2

我剛剛開始學習C並正在研究鏈接列表的簡單實現。當我嘗試打印我的清單時,我意識到一些奇特的東西。即使代碼從未執行,我也會在代碼的一部分發生分割錯誤。怎麼會這樣?分割錯誤,儘管代碼從未執行?

據我所知,while循環從不執行,因爲下一個指針並不指向任何東西。我在想,也許在評估while循環時,它可能會導致它指向導致分段錯誤的東西,但奇怪的是,如果您刪除了行root = root->next,它會執行正常(沒有任何錯誤)。即使它不會進入while循環。那麼如果一行代碼(root = root->next)導致錯誤,如果代碼從未執行?代碼編譯得很好。我在某個地方犯了一個簡單的錯誤嗎?我知道這不是一個適當的鏈接列表實現,它是爲學習目的而進行的。

#include <stdio.h> 
#include <stdlib.h> 

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

typedef struct linkedlist item; 

int main(int argc, char **argv) { 
    item * root; 
    item * current; 

    root = malloc(sizeof(item)); 
    root->value = 500; 

    int i; 
    for(i = 0; i <= 20; i++) { 
     current->next = malloc(sizeof(item)); 
     current = current->next; 
     current->value = i; 
    } 

    while(root->next != 0) { 
     //This is never executed 
     printf("[%d]\n", root->value); 
     //the line below does cause the segmentation error 
     //but how can this affect anything at all if this is never executed? 
     root = root->next; 
    } 
    return 0; 
} 

回答

3

current->next第一行是訪問一個未初始化的指針,你可能忘了循環前初始化currentroot。Derefencing未初始化的指針是未定義的行爲(UB),這意味着任何事情都可能發生,實際上,未初始化的變量將具有與任何內容相對應的值s被存儲在他們的記憶位置。因此,一個未初始化的指針將被設置爲某個半隨機地址,並將指向內存中的一些半隨機內容(可能還有其他程序變量)或無效。

在while循環測試root->next的條件中還有另一個未初始化的指針被解引用。通常,您應確保將每個列表項(包括root)的next字段設置爲0,否則您將無法檢測到鏈接列表的結尾(再次初始化指針,因此再次進入UB並進入練習的價值可能與0不同)。

糾正這類問題在你的代碼的建議:

#include <stdio.h> 
#include <stdlib.h> 

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

typedef struct linkedlist item; 

int main(int argc, char **argv) { 
    item * root; 
    item * current; 

    root = malloc(sizeof(item)); 
    root->value = 500; 
    root->next = 0; 

    current = root; 

    int i; 
    for(i = 0; i <= 20; i++) { 
     current->next = malloc(sizeof(item)); 
     current = current->next; 
     current->value = i; 
     current->next = 0; 
    } 

    while(root->next != 0) { 
     printf("[%d]\n", root->value); 
     root = root->next; 
    } 
    return 0; 
} 
+0

但是,如果我取消對該行的root =根 - >下一步;並在最後輸入一個prinf語句而不會崩潰。 –

+2

root-> next也不會在while循環之前初始化。 – OldProgrammer

+0

@OldProgrammer我可以檢查while循環嗎? while(root-> next!= NULL)? –