1

我看过其他一些关于如何打印链接列表的帖子,但没有一个对我有帮助,所以我决定发布我自己的代码。这是问题所在:

我可以完美地添加一个名字和年龄,但是第二个我添加另一个名字和年龄它会覆盖前一个。

所以如果我输入:

Matt 和 21,然后是 charles 和 34。它只会输出 charles 和 34。如何让它输出所有内容?预先感谢您的帮助!:)

这是我的代码:

#include<stdlib.h>
#include<stdio.h>
#include<malloc.h>
#include<conio.h>
#include<string.h>
#include<ctype.h>
#define pause system ("pause")

// prototype variables
struct node * initnode(char*, int);
void printnode(struct node*);

struct node{
    char name[20];
    int age;
    struct node *next;
};

struct node *head = (struct node*) NULL;
struct node *end = (struct node*) NULL;

struct node* initnode(char *name, int age){
    struct node *ptr;
    ptr = (struct node*) calloc(3, sizeof(struct node));
    if(ptr == NULL) 
        return (struct node*) NULL;
    else {
        strcpy(ptr->name, name);
        ptr->age = age;
        return ptr;
    }
}

void printnode(struct node *ptr) {
    printf("Name -> %s\n", ptr->name);
    printf("Age -> %d\n", ptr->age);
}


main() {
    char name[20];
    int age, choice = 1;
    struct node *ptr;
    while(choice != 3){
        system("cls");
        printf("1. Add a name\n");
        printf("2. List nodes\n");
        printf("3. Exit");
        printf("\nEnter Menu Selection: ");
        scanf("%d", &choice);
        switch(choice) {
        case 1: printf("\nEnter a name: ");
            scanf("%s", name);
            printf("Enter age: ");
            scanf("%d", &age);
            ptr = initnode(name, age);
            break;
        case 2: if(ptr == NULL) {
                printf("Name %s not found\n", name);
            } else 
                printnode(ptr);
            pause;
            break;
        case 3: exit(3);
        default: printf("Invalid Entry");
        }// end of switch


    }// end of main

}

哦,我知道某些“#include”可能没用。我整天都在添加和删除代码。

4

4 回答 4

1

只是一句话:

ptr = (struct node*) calloc(3, sizeof(struct node));

是错误的,因为你正在分配3 * sizeof(struct node),它应该是

ptr = (struct node*) calloc(1, sizeof(struct node));

您的代码缺少很多东西。您没有将创建的节点链接到任何链接列表。在你没有使用的整个代码中next。您必须在此代码上做更多工作。

问题不仅来自链表的打印。问题来自如何创建链表

我可以向您推荐一个可以帮助开发此类程序的链表模板。该模板包含处理链表的函数和宏

  • 在头部添加到链表
  • 在尾部添加到链表
  • 从链表中删除...

您可以从此链接获取链接列表模板(list.h)

以下链接包含如何使用它的示例

请参考以上链接中的这一段

通过很少的修改(删除列表项的硬件预取),我们也可以在我们的应用程序中使用这个列表。此文件的可用版本可在此处下载。

于 2013-04-10T17:02:10.430 回答
1

虽然您已经定义了headend指针,这将构成一个链表,但您实际上并没有使用它们来存储您的新信息。在创建新节点并将其存储在ptr变量中之后,您实际上并没有将其存储在列表中。

我建议添加另一个方法 ,它将这个新创建的节点添加到由和指针addnode定义的链表中。headend

void addnode(struct node *ptr) {
    if (end == NULL) {
        head = ptr;
        end = ptr;
    }
    else {
        end = end->next = ptr;
    }
}

从广义上讲,我们检查列表中是否已有任何项目;如果不是,则列表的开头和结尾都将由同一个节点表示:列表中唯一的一个!否则,我们让当前结束之后的节点成为要添加的节点,然后将我们的全局end指针移动到现在的最后一个节点。

这允许我们维护一个由多个节点组成的链(列表中的条目)。然后,在打印整个列表时,我们必须遵循整个链,从第一个节点 ( head) 到最后一个节点。我们可以通过一个简单的循环来做到这一点:不是简单地调用我们在 中维护printnode()的临时ptr变量main(),而是编写:

struct node *current = head;
while (current != end) {
    printnode(current);
    current = current->next;
}
于 2013-04-10T17:13:59.183 回答
0

这一行在这里:

ptr = initnode(name, age);

这就是为什么您总是覆盖名称/年龄的原因,因为您声明了一个名为的本地节点ptr,并且每次添加一个值时,您都会用下一个节点覆盖该节点。

看到struct node *next;节点结构中的那个元素了吗?您需要将其指向创建的下一个节点以便拥有超过 1 个节点,类似于:

ptr->next = initnode(name, age);

链表有第一个节点的特殊情况,你的第一个节点ptr是空的,所以当你的链表长度为0时,你需要设置ptrfrom init_node(),下次需要设置ptrnext元素,然后你需要更新 ptr 使其成为当前节点:

ptr = ptr->next;

当然,这样做会导致您“松开”列表的开头。这就是你的head用武之地。当你开始时,如果你初始化headptr,那么永远不要动头,你将永远记得你的列表的开始在哪里。

您还有一个变量:

struct node *end = (struct node*) NULL;

您必须在每次添加时不断更新它,以便始终指向添加的最后一个元素……如果您关心的话。通常,如果您要创建一个双链表,则使用endor lastor指针。tail

于 2013-04-10T17:13:22.870 回答
0

我可以完美地添加一个名字和年龄,但是第二个我添加另一个名字和年龄它会覆盖前一个。

您的代码不会覆盖前一个节点,而是用一个新节点替换它并泄漏您之前拥有的节点。(泄漏是您分配的一块内存,然后丢失了任何指向它的指针,因此您永远无法释放它。)这是创建新节点的行:

ptr = initnode(name, age);

如果ptr是指向列表中第一个节点的指针,则应该将新节点添加到列表的末尾,而不是将其分配给ptr.

于 2013-04-10T17:49:56.150 回答