我正在编写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;
}
}
我已经尝试过启动和newnode
局部变量,但它不起作用。
答案 0 :(得分: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));
答案 1 :(得分:0)
您的代码有几点需要改进,所以让我们逐一介绍。首先,您看到的行为是因为链接列表中所有节点的结构成员name
和type
指向相同的内存位置,即name1
和{{1} } 分别。
type1
此处,struct list {
char *name;
char *type;
// other members
};
是指向字符的指针,因此name
。在type
中的do while
循环中,您在每次迭代中分别将每个节点的名称和类型读入数组main
和name1
。因此,type1
和name1
的先前值会被覆盖,从而丢失。现在,您要为每个新创建的节点的相应成员分配type1
和name1
。
type1
因此,所有节点的// 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
和malloc
完全相同。阅读更多相关信息here。
现在让我们从程序的顶部开始讨论其他事情。
strcpy
已弃用,不是标准版。请改用malloc.h
。更多here。stdlib.h
函数的两个签名:main
,另一个是int main(void);
更多here。int main(int argc, char *argv[]);
读取字符串时,应防止缓冲区溢出。如果用户输入的名称和类型超过9个字符,则会导致未定义的行为甚至崩溃。您应该将scanf
替换为scanf("%s", name1)
。格式字符串中的scanf("%9s", name1)
表示9
最多可读取9个非空白字符。一个字符空间留给它自动添加的终止空字节。scanf
的{{1}}的返回值。如果malloc
无法分配内存,那么您的程序就会崩溃。NULL
中不需要malloc
阻止。它永远不会被输入,除非在循环的第一次迭代中它使else if
不是你想要的。 do while loop
应始终为start->previous = start
。