【问题标题】:code not printing linked list C代码不打印链表 C
【发布时间】:2014-02-19 16:11:55
【问题描述】:

我正在编写 C 代码来实现链表。但是在打印列表的内容时,它只打印最后一个节点的值。我已经调试了很长时间。请帮忙。

#include <stdio.h>
#include <malloc.h>

struct list {
    char *name;
    char *type;
    int occurance;
    struct list *prev;
    struct list *link;
};

struct list *start=NULL,*ptr,*newnode;

void main() {
    int choice = 0;
    char name1[10], type1[10];
    int occ;

    do {
        printf("Enter name:");
        scanf("%s", name1);
        printf("Enter type:");
        scanf("%s", type1);
        printf("Enter occurance:");
        scanf("%d", &occ);
        newnode = (struct list *)malloc(sizeof(struct list));
        newnode->link = NULL;
        newnode->prev = NULL;
        newnode->name = name1;
        newnode->type = type1;
        newnode->occurance = occ;
        if(newnode == NULL) {
            printf("Memory could not be allocated!");
            // exit(0);
        }
        if(start == NULL) {
            start = newnode;
            ptr = start;
            printf("start is: %s", start->name);
        }
        else if(start->link == NULL) {
            start->link = newnode;
            newnode->prev = start;
            ptr = newnode;
        }
        else {
            ptr->link = newnode;
            newnode->prev = ptr;
            ptr = ptr->link;
        }
        printf("Enter 1 to continue: ");
        scanf("%d", &choice);
    } while(choice == 1);

    // display
    ptr = start;
    while(ptr != NULL) {
        printf("%s ", ptr->name);
        printf("%s ", ptr->type);
        printf("%d \n", ptr->occurance);
        ptr = ptr->link;
    }
}

我也尝试过创建 start 和 newnode 局部变量,但它不起作用。

【问题讨论】:

  • Cqnqrd 的回答有。不过,还有一点:1) 您对newnode==NULL 的检查有点晚了,因为您已经取消引用newnode 来设置其成员。你不需要start-&gt;link==NULL 的“else if”; else{} 块中的相同代码也适用于这种情况。
  • 哦,是的,我现在注意到了,谢谢@dvnrrs
  • main的签名改为int main(void)。另请注意,malloc.h 不是标准的。请改用stdlib.h

标签: c data-structures linked-list


【解决方案1】:

您不能使用等于运算符来分配char *。相反,您必须使用函数strcpy

不要这样做:

newnode->name=name1;
newnode->type=type1;

但是这样做:

strcpy(newnode->name, name1);
strcpy(newnode->type, type1);

目前您的整个char* 都指向同一个内存块。

编辑: 由于您使用的是指针,因此必须在将值从一个指针复制到另一个指针之前分配内存(否则您将遇到段错误)。所以你还需要用malloc分配你的节点名称和类型内存:

//allocate memory of node's name attribute with the same amount as name1 (+1 for null terminating character)
newnode->name = malloc(sizeof(char) * (strlen(name1)+1));
newnode->type= malloc(sizeof(char) * (strlen(type1)+1));

【讨论】:

  • 一点空间(malloced 或数组)也会很有用。 :-)
  • 他必须在strcpy()@ 之前给字符串留一些空间。
  • 没错,但我猜 Op 自己会找到的。 ;-)
  • 抱歉之前的评论,但是 strcpy 导致程序由于分段错误而崩溃
  • @user2538255,您是否阅读过我和 ooga 的 cmets 关于您需要在复制字符串之前分配空间
【解决方案2】:

您的代码中有几处需要改进,所以让我们一一进行。首先,您看到的行为是因为链表中所有节点的结构成员 nametype 指向相同的内存位置,即分别指向 name1type1

struct list {
    char *name;
    char *type;
    // other members
};

这里,name 是一个指向字符的指针,type 也是如此。在maindo while 循环中,您在每次迭代中分别将每个节点的名称和类型读入数组name1type1。因此,name1type1 的先前值被覆盖并因此丢失。现在您将name1type1 分配给每个新创建的节点的相应成员。

// after allocating memory for a new node

newnode->name = name1;  // name1 evaluates to a pointer to name1[0]
newnode->type = type1;  // type1 evaluates to a pointer to type1[0]

因此,所有节点的name 成员都指向name1,它只保留最后读取的字符串,类似地,所有节点的type 成员指向type1,它也具有最后读取的字符串。

既然我们已经讨论了您的程序的行为,那么解决方案是什么?您可以防止每个节点的名称和类型被输入的下一个值覆盖。为此,您每次为新节点读取它们时都为它们分配内存。

newnode->name = strdup(name1); // make a copy of name1 before it's overwritten
newnode->type = strdup(type1);  // make a copy of type1 before it's overwritten

strdup 分配足够的内存来复制传递给它的字符串。它本质上与mallocstrcpy 做同样的事情。阅读更多关于它的信息here

现在让我们从程序的顶部开始讨论其他事情。

  • malloc.h 已弃用且不标准。请改用stdlib.h。更多here
  • C 标准为main 函数规定了两个签名:int main(void);,另一个是int main(int argc, char *argv[]); 更多here
  • 使用scanf 读取字符串时,应注意防止缓冲区溢出。如果用户输入的名称和类型超过 9 个字符,将导致未定义的行为甚至崩溃。您应该将scanf("%s", name1) 替换为scanf("%9s", name1)。格式字符串中的9 表示scanf 最多可以读取9 个非空白字符。为自动添加的终止空字节留一个字符空间。
  • 在调用后立即检查malloc 的返回值是否为NULL。如果malloc 分配内存失败,您的程序将简单地崩溃。
  • 您不需要else if 块中的do while loop。它永远不会被输入,除非在循环的第一次迭代中,当它生成 start-&gt;previous = start 这不是你想要的。 start-&gt;previous 应始终为 NULL

【讨论】:

  • 非常感谢您提供如此详尽而详细的答案...特别是最后提到的改进:)
猜你喜欢
  • 2016-01-21
  • 1970-01-01
  • 2016-06-15
  • 1970-01-01
  • 2017-01-08
  • 1970-01-01
  • 1970-01-01
  • 2014-05-02
  • 1970-01-01
相关资源
最近更新 更多