2016-06-08 43 views
0

我必須做一個鏈接列表程序,有很多功能,比如刪除,添加和修改數字。我的功能不記憶鏈接列表頭

在我的代碼中,當我在選擇1的函數中放入一個數字後,當我想要顯示所有數字時,我將頭放在參數中,但是在Visual Studio中看到函數的參數don'沒有任何東西。我可以做的,以傳遞參數鏈表的頭,我的功能Displaynbr

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

struct Mynbr 
{ 
    int nbr; 
    struct Mynbr* next; 
} typedef Mynbr; 

void Menu(); 
void choiceMenu(int choice, Mynbr* first); 
Mynbr* Addnumber(Mynbr* first); 
void Displaynbr(Mynbr* first); 

int main(void) 
{ 
    Mynbr* head = NULL; 
    int choice = 0; 

    while (choice!=5) 
    { 
     Menu(); 
     printf("Your choice : "); scanf("%d", &choice); 
     choiceMenu(choice, head); 
    } 
    system("PAUSE"); 
    return 0; 
} 

void Menu() 
{ 
    printf("\n1.Add number to the list\n"); 
    printf("2.Delete number from the list\n"); 
    printf("3.Search number in the list\n"); 
    printf("4.Display all the numbers from the list\n"); 
    printf("5.Exit\n"); 
} 

void choiceMenu(int choice, Mynbr* first) 
{ 
    switch (choice) 
    { 
    case 1: 
     Addnumber(first); 
     break; 
    case 2: 
     break; 
    case 3: 
     break; 
    case 4: 
     Displaynbr(first); 
     break; 
    case 5: 
     break; 
    } 
} 

Mynbr* Addnumber(Mynbr* first) 
{ 
    printf("\n===Function to add a number===\n"); 
    Mynbr* head_nbr = first; 
    if (!head_nbr) 
    { 
     head_nbr = (Mynbr*)malloc(sizeof(Mynbr)); 
     printf("Enter a number :"); scanf("%d", &(head_nbr->nbr)); 
     head_nbr->next = NULL; 
    } 
    return head_nbr; 
} 

void Displaynbr(Mynbr* first) 
{ 
    printf("\n===Function to display number===\n"); 
    Mynbr* curr = first; 
    if (curr->next) 
    { 
     printf("The number is : %d", curr->nbr); 
     Displaynbr(first->next); 
    } 
} 
+0

C11草案標準n1570:* 6.5.2.2函數調用4參數可以是任何完整對象類型的表達式。在爲函數調用 做準備時,將對參數進行評估,併爲每個參數分配相應參數的值。 93)函數可能會改變其參數的值,但這些改變不會影響參數的值。* tl; dr:C是按值傳遞的值。 – EOF

+1

題外話:你不需要投入malloc的返回 – sokkyoku

回答

0

的功能有原型的

Mynbr* Addnumber(Mynbr* first) 

它是由Addnumber(first)主叫什麼。主要來說,first指針指向的值將由於函數的更改而更新。但是,第一個指針本身不會被更新。即指針將保持爲NULL。如果它之前是NULL。

要解決這個問題,你需要調用的函數在主這樣

first = Addnumber(first); 

此外,您AddNumber功能需要修復。對於列表中的第二個或更大的元素,您不會添加數字。

Mynbr* Addnumber(Mynbr* first){ 
    printf("\n===Function to add a number===\n"); 
    Mynbr* head_nbr; 
    head_nbr = malloc(sizeof(Mynbr)); 
    printf("Enter a number :"); scanf("%d", &(head_nbr->nbr)); 
    if (!first) 
    { 
    head_nbr->next = NULL; 
    } 
    else 
    { 
    head_nbr->next = first; 
    } 
    return head_nbr; 
} 

該函數在變量head_nbr建議的列表的起始處添加。最後添加,你將不得不作出適當的修改。

+0

它實際上並不在'main'中,但是如何對代碼進行格式化,混淆是可以理解的。我已修復格式 – sokkyoku

1

你是不是從很遠,卻忘了一個重要的規則: 當你在一個函數改變一個參數的值,呼叫者的值保持不變

因此AddNumber(幾乎)正確返回列表頭地址的新值,但立即丟棄它。

因此,這裏有一些修正:

AddNumber應該能夠將號碼添加到一個空或非空列表(注:它目前導致LIFO):

Mynbr* Addnumber(Mynbr* first){ 
    printf("\n===Function to add a number===\n"); 
    Mynbr* head_nbr = first; 
    head_nbr = (Mynbr*)malloc(sizeof(Mynbr)); 
    printf("Enter a number :"); scanf("%d", &(head_nbr->nbr)); 
    head_nbr->next = first; // just link to initial head, be it null or not 

    return head_nbr; 
} 

不應該丟棄新的頭 - 你可以將其返回給調用者像你這樣的AddNumber或使用雙間接:

void choiceMenu(int choice, Mynbr** first){ 
    switch (choice){ 
case 1: 
    *first = Addnumber(*first); 
    break; 

case 2: 
    break; 
case 3: 
    break; 
case 4: 
    Displaynbr(*first); 
    break; 
case 5: 
    break; 
    } 
} 

(不要忘記更改初始宣佈和調用它:choiceMenu(choice, &head)

最後但並非最不重要的,DisplayNumber正確測試爲curr->next而不是curr

void Displaynbr(Mynbr* first){ 
    printf("\n===Function to display number===\n"); 
    Mynbr* curr = first; 
    if (curr) { 
     printf("The number is : %d", curr->nbr); 
     Displaynbr(first->next); 
    } 
} 

但這仍顯示===功能顯示數字===列表中的每個值。正是在這裏,最好使用簡單的迭代來代替遞歸:

void Displaynbr(Mynbr* first){ 
    printf("\n===Function to display number===\n"); 
    Mynbr* curr = first; 
    while (curr) { 
     printf("The number is : %d\n", curr->nbr); 
     curr = curr->next; 
    } 
} 

或使用for循環:

void Displaynbr(Mynbr* first){ 
    printf("\n===Function to display number===\n"); 
    Mynbr* curr; 
    for (curr=first; curr != NULL; curr=curr->next) { 
     printf("The number is : %d\n", curr->nbr); 
    } 
} 

遞歸版本甚至可以更簡潔通過刪除無用的局部變量(感謝@sokkyoku爲提示):

void Displaynbr(Mynbr* first){ 
    printf("\n===Function to display number===\n"); 
    if (first) { 
     printf("The number is : %d", first->nbr); 
     Displaynbr(first->next); 
    } 
} 

如果你想改變AddNumber有一個FIFO列表,您需要在列表的末尾添加新元素。代碼變爲:

Mynbr* Addnumber(Mynbr* first){ 
    printf("\n===Function to add a number===\n"); 
    Mynbr* head_nbr = malloc(sizeof(Mynbr)); 
    printf("Enter a number :"); scanf("%d", &(head_nbr->nbr)); 
    head_nbr->next = NULL; 
    if (first == NULL) first = head_nbr; 
    else { 
     Mynbr* last = first; 
     while (last->next != NULL) last = last->next; 
     last->next = head_nbr; 
    } 
    return first; 
} 

但它會更有效地在這種情況下的指針保持在列表的最後一個元素,而不是瀏覽列表中找到它的。

+1

請注意,對Addnumber的更改會導致列表爲LIFO,而FIFO可能是預期的。 此外,爲什麼還要在'Displaynbr'的遞歸版本中使用'curr'變量,你可以直接使用'first' – sokkyoku

+1

@sokkyoku:謝謝注意:-) –

+0

非常感謝你的幫助,但是我想不明白這部分代碼。爲什麼下一個鏈接到第一個? head_nbr-> next = first; //只是鏈接到初始頭部,無論它是否爲空。此外,爲什麼你不檢查是否第一次在Addnumber()是否爲NULL –