2016-06-08 45 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 –