2011年10月12日 星期三

[筆記]變數的宣告造成實作linked-list的問題: 使用C

在實作linked-list時遇到了很大的麻煩,一直無法正確的建立資料node,以下為原始碼。

struct Node{
        int index;
        char *name;
        struct Node *nextNode;
};

void insertNode(struct Node *list, char *new_name, int new_index){
        struct Node *curr;
        struct Node newNode;
        curr = list;
        //find last node
        while(1){
                if(curr->nextNode!=NULL){
                        curr = curr->nextNode;
                }else break;
        }
        curr->nextNode = &newNode;
        newNode.name = new_name;
        newNode.index = new_index;
        newNode.nextNode = NULL;
}

觀察得到以下:
  1. 在main主程式中新增node時,可以正確地建立。
  2. 將insert 功能包成一個function時,則無法正確地建立正確的資料。
    1. 但是只有structure 中的字串無法正確建立,int 變數型態則是正確的。
  3. 以gdb觀察變數的位址與值,觀察到在insert function內,可以成功地建立node,但是回到main function 時,讀取該node的值時卻是錯的。
基於以上幾點的觀察,以及搜尋到關於"pointer", "variable in stack/heap"相關的資訊文章後終於找到問題的所在:
  1. 變數在記憶體中的分配
  2. 變數的宣告方式
原實作方式為在function中宣告node,但沒注意到該node是被存放在stack中,一但回到main function,該變數的內容無法被保証不被更改。因此應該改以存放於heap的變數宣告方式,才能夠確保資料的正確建立。

void insertNode(struct Node *list, char *new_name, int new_index){
        struct Node *curr;
        struct Node *newNode;
        newNode = malloc(sizeof(struct Node));
        curr = list;
        //find last node
        while(1){
                if(curr->nextNode!=NULL){
                        curr = curr->nextNode;
                }else break;
        }
        curr->nextNode = newNode;
        newNode->name = new_name;
        newNode->index = new_index;
        newNode->nextNode = NULL;
}


讀到self-referenced structure/linked list的時候將重點放在insert/delete node的行為描述,而忽略了變數的宣告方式會影響實作的結果。理清了宣告malloc的用意,原以為兩種等效的方法本值上的差異。