【问题标题】:Printing a linked list in C program在 C 程序中打印链表
【发布时间】:2013-04-10 16:59:21
【问题描述】:

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

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

所以如果我输入:

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”可能没用。我整天都在添加和删除代码。

【问题讨论】:

  • 看起来您甚至都没有在构建链接列表。例如,headend 从不被引用。
  • 哦,你不需要在 C 程序中强制转换 malloc 的返回值。除此之外,NULL 的所有演员都是怎么回事?
  • 您的转换是正确的,您不需要显式转换,在 C 编程中,完整它可能有时会导致错误...但这也是 不是你的答案
  • 这句话真的有意义吗? case 2: if(ptr == NULL) { printf("Name %s not found\n", name); }
  • @EAGER_STUDENT,这取决于 printf 的实现。在这种情况下,我的这里打印(null)

标签: c pointers linked-list printf


【解决方案1】:

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

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

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

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

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

struct node *current = head;
while (current != end) {
    printnode(current);
    current = current->next;
}

【讨论】:

  • 我得到“addnode”将是一个新功能,但它会去哪里?
  • 如果你声明一个原型,它可以放在文件顶层的任何地方(即不在任何其他函数内);否则它必须在 main 函数之前。
  • 但是当你在 main 中调用它时,在我的案例 1 中,函数调用会在“ptr = initnode(name, age);”下面吗?还是会进入案例 2?
  • 啊,对不起;你是对的,它会在你创建新节点之后进入案例 1。
【解决方案2】:

只是一个评论:

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

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

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

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

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

我可以向你推荐一个链表模板,它可以帮助开发这样的程序。该模板包含处理链表的函数和宏

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

你可以从这个link获取链表模板(list.h)

以下link 包含一个如何使用它的示例

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

几乎没有修改(删除列表的硬件预取 items)我们也可以在我们的应用程序中使用这个列表。可用版本 可在此处下载此文件。

【讨论】:

    【解决方案3】:

    这里的这一行:

    ptr = initnode(name, age);
    

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

    在你的节点结构中看到struct node *next; 元素了吗?您需要将其指向创建的下一个节点才能拥有多个节点,类似于:

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

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

    ptr = ptr->next;
    

    当然,这样做会导致您“松开”列表的开头。这就是您的head 的来源。当您开始时,如果您将head 初始化为ptr,那么永远不要动头,您将永远记住列表的开头在哪里。

    你还有一个变量:

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

    您必须在每次添加时不断更新它,以便始终指向最后添加的元素...如果您关心的话。通常endlasttail 指针用于创建双链表。

    【讨论】:

      【解决方案4】:

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

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

      ptr = initnode(name, age);
      

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-21
        • 1970-01-01
        • 2015-03-22
        • 2014-05-25
        • 2021-01-23
        • 1970-01-01
        • 2020-12-16
        • 2016-06-15
        相关资源
        最近更新 更多