2013-02-23 102 views
2

我一直在努力在C中實現鏈表,所以在有人喊我之前:是的,這是「家庭作業」。我一直在試圖解決和尼克Parlante的「鏈表基」工作 - 在免費提供:http://cslibrary.stanford.edu/103追加在鏈表的末尾

功能:在鏈表的末尾插入元素

我偶然在一個實現問題和管理構建一個解決方法:如果我在LList中使用「EndPointer」,我可以使用返回函數來設置函數的EndPointer,以交付新的ReferencePointer,然後在main中更改它。

碼 - 工作正常,但beeing解決方法:

// within main 
lastPtrRef = _pushEnd(lastPtrRef, i); 

// == function: push to end 
node** _pushEnd(node **endRef, int value) 
{ 
    // 1) allocate stack mem/make room for new element 
    node *newNode = malloc(sizeof(node)); 

    // do the data work 
    newNode->value = value; 

    // 2) make element point to NULL (fo beeing the new last element 
    newNode->next = NULL; 

    // 3) make old last element point to new element 
    *endRef = newNode; 

    return &(newNode->next); // more readable then vers. below 
    // this returns the mem address only of the pointer of the node!!! 
    //return (&((*endRef)->next)); 

} 

============================== ================================================

這是我迄今爲止做的功能內的所有工作,但它實際上不起作用。任何提示,我沒有得到什麼?!

void _pushEnd(node **endRef, int value) 
{ 
// 1) allocate stack mem/make room for new element 
node *newNode = malloc(sizeof(node)); 

// do the data work 
newNode->value = value; 

// 2) make element point to NULL (fo beeing the new last element 
newNode->next = NULL; 

// 3) make old last element point to new element 
*endRef = newNode; 

} 

莫非,那我真的需要一個指針引用指針的指針的內容,真正改變的最後一個元素(範圍:主),所以我目前似乎只有被修改局部變量「endRef」而不是它的內容?!

任何幫助,將不勝感激......


編輯: 的想法是不使用虛擬節點在LLIST的開始追加。

我的結構是這樣的:

typedef struct node  { 
int  value; 
struct node *next;  } node; 

主 - 本地變量(棧):

node *head = NULL; 
node **lastPtrRef = &head; 

編輯: 大多數命題結束了反正返回refPointer。但也許這不是一個壞主意,因爲它不會需要一個refPointer到refPointer。

Thx爲您的所有幫助和許多有用的評論!

+0

,請告訴我們的結構(一個或多個) – 2013-02-23 11:39:04

+1

標識符開始以下劃線後跟一個小寫字母被保留(用於實施?)。我建議你將下劃線從標識符的開始處移動到末尾:'_pushEnd' ==>'pushEnd_'(或者甚至可以全部省略下劃線) – pmg 2013-02-23 11:39:53

+0

@pmg:「以下劃線開頭並帶有小寫字母的標識符被保留「 - 那是什麼意思? sry,我對編碼很陌生,開始用它來標記我自己的功能。 這樣就是不好的編碼風格? – LeTigre 2013-02-23 13:56:00

回答

3

_pushEnd正在告訴main什麼main已經知道:存儲指針的位置。

你有很多選擇,包括:

  • pushEnd得到節點*(未節點**),返回新的指針和主力店在其可變

  • pushEnd得到節點**並自行覆蓋main的值,不需要返回任何東西。

編輯:

示例點1:

node* pushEnd(node* end, int entry); // returns new end. 
int main() { 
    node* end = newlist(); 
    int i=0;for(;i<10;++i) { 
     end = pushEnd(end, i); 
    } 
} 

示例點2:

void pushEnd(node** ptrToEnd, int entry); // changes *ptrToEnd 
int main() { 
    node* end = newlist(); 
    int i=0;for(;i<10;++i) { 
     pushEnd(&end, i); 
    } 
} 
+0

thx,在理解了我實際上用「return(&((* endRef) - > next)做了什麼))」(或者更短:「return&(newNode-> next);」)我最終明白了你的觀點。我只是返回newNode指針部分的地址(作爲mem地址) - 所以我可以跳過檢查,如果已經存在一個節點,因爲引用指針(lastPtrRef)只需要查找指針。所以像100內存/變量圖後,似乎我終於明白了你的觀點。 等待:我實際上是在你的第一行中做你的建議,我不是嗎?正如我可以在指針參考中退後一步,不是嗎? – LeTigre 2013-02-24 09:50:49

+0

所以我實際上可以從節點**到節點*。但是我將需要節點**來改變節點指向的位置,不是嗎?我不需要返回兩個值,如果我將節點**更改爲節點*? – LeTigre 2013-02-24 10:00:57

+0

你讓這個太複雜了,我會擴大我的答案,給我一分鐘。 – 2013-02-24 11:11:25

3
*endRef = newNode; 

之前你做,你必須使舊endRef->nextnewNode

if (*endRef) 
    (*endRef)->next = newNode; 

*endRef = newNode; 
+0

嘿,thx的答覆。我希望我能正確地得到你,但是當我這樣做時,我會遇到段錯誤。我認爲你的代碼需要在列表開頭的虛擬節點或非空列表,因爲「(* endRef) - > next = newNode」在頭指針中找不到.next。 – LeTigre 2013-02-23 14:06:48

+0

@LeTigre沒錯,'* endRef'必須是非NULL。我編輯過。 – cnicutar 2013-02-23 14:07:47

1

我覺得你的問題是與返回的行:

return (&((*endRef)->next)); 

正如你已經這樣做了*endRef = newNode;之前,現在是返回剛纔創建的節點的下一個元素的方向。

+0

嘿Nox,這部分代碼實際上是在工作。我只是想擺脫主要不得不交出最後節點的新地址... - 我希望我正確地得到了你... – LeTigre 2013-02-23 14:13:36

+0

@LeTigre對不起,似乎我完全明白你的問題是什麼。 – Noxbru 2013-02-23 16:30:47

1
struct node { 
    struct node *next; 
    int value; 
    }; 

struct node *root = NULL 
    , **lastPtrRef = &root; 

// within main 
lastPtrRef = pushEnd(lastPtrRef, i); 

//function: push to end; return new pointer to tail->next 

struct node **pushEnd(struct node **p, int value) 
{ 
    struct node *p; 

    // 0) is it really the end ?  
    while (*pp) {pp = &(*pp)->next; } 

    // 1) allocate 
    p = malloc(sizeof *p); 

    // do the data work 
    p->value = value; 

    // 2) make element point to NULL (fo beeing the new last element 
    p->next = NULL; 

    // 3) make old last element point to new element 
    *pp = p; 

    return &p->next; 

} 

或刪除變量p,因爲它不需要:

struct node **pushEnd(struct node **p, int value) 
{ 

    while (*pp) {pp = &(*pp)->next; } 

    *pp = malloc(sizeof **pp); 
    (*pp)->value = value; 
    (*pp)->next = NULL; 

    return &(*pp)->next; 

} 
+0

thx很多。其實,我有點尷尬,因爲我沒有得到你從哪裏得到「pp」/「* pp」的地方。 Sry,也許我只是對所有這些都有所瞭解,但函數首部當地人以及第一個節點定義只定義了「p」。 就這一點而言,對於像我這樣的新手來說,給出的第一個版本看起來有點像你所做的。問題在於,你的代碼似乎期待第一個節點。 (因爲你的回報不會在一個簡單的頭指針上工作嗎?)就像我說的,我可能就是因爲我對p和pp的困惑而沒有得到你的例子,但我不適合我... – LeTigre 2013-02-23 14:35:38

+0

簡單:我剛剛改名爲「 lastPtrRef「變量爲pp。由於它是該函數的形式參數,因此它的作用域僅限於該函數,因此它可以具有相對較短的名稱。 (類似於「newNode」 - >「p」)。該代碼不期望「第一個節點」,它應該與您的版本完全相同。初始循環只是追逐 - > next指針鏈,直到找到NULL。在你最初的情況下,這個NULL將在循環的第一次迭代中找到(* pp將爲零)。 – wildplasser 2013-02-23 14:50:39

+0

......這並不重要,它只是在那裏表明它不是嚴格需要維護「global」lastPtrRef變量;該函數可以稱爲'pushEnd &root);',忽略返回值。 (但是每當你添加一個節點時,它會花費幾個週期的課程來找到結尾。) – wildplasser 2013-02-23 14:51:26