下面我在C中创建了一个简单的链接列表。代码目前正在产生一个分段错误,我觉得很奇怪,因为我正在复制我们当前书中的一个例子。我对代码做的唯一事情是将代码放入方法“addToList”。我知道分段错误来自方法addToList,但我不知道我在哪里犯了错误。
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int val;
struct node *next;
} Node;
void addToList(Node *, int);
void printList(Node *);
void main() {
int x;
Node *head = malloc(sizeof(Node));
for (x = 1; x < 4); x++) {
printf("Enter an integer: ");
x = scanf("%d");
addToList(head, x);
}
printList(head);
}
void addToList(Node *head, int val) {
Node *current = head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof(Node));
current->next->val = val;
current->next->next = NULL;
}
void printList(Node *head) {
Node *current = head;
while (current != NULL) {
printf("%d->", current->val);
current = current->next;
}
printf("\n");
}
任何帮助告诉我什么是错的或者我犯错的地方都会非常感激。
答案 0 :(得分:3)
仔细查看您的代码:
int main(void) {
int x;
Node *head = malloc(sizeof(Node));
for (x = 1; x < 4); x++) {
...
addToList(head, x);
}
...
}
您没有初始化内存,因此head->val
和head->next
不是
初始化。因为那个
while (current->next != NULL) {
current = current->next;
}
将循环不确定的次数。第一个current->next
是最多的
可能不是NULL
,所以current = current->next
会被执行。此时current
指向无处,因此未定义的行为在您的情况下会导致段错误。
你必须像这样初始化内存:
Node *head = malloc(sizeof *head);
if(head == NULL)
// error handling
head->next = NULL;
但你也可以使用calloc
,它也将内存设置为0,因此你不必初始化值(在这种情况下):
Node *head = calloc(1, sizeof *head);
if(head == NULL)
// error handling
您应始终检查malloc
/ calloc
/ realloc
的返回值。
另请注意,main
函数的签名可以是以下之一:
int main(void);
int main(int argc, char **argv);
int main(int argc, char *argv[]);
修改强>
我现在注意到的另一个错误:
x = scanf("%d");
这不是scanf
的工作方式。你必须传递一个指针,scanf
保存
通过传递的指针扫描值。 scanf
返回匹配的数量
成功的价值,在这种情况下,成功将是1:
int num;
int ret = scanf("%d", &num);
if(ret != 1)
{
fprintf(stderr, "Could not read value from the user\n");
continue; // to contiune looping
// you could also do a break; and stop the looping, or
// exit(1), etc.
}
// error with scanf
也不要对循环迭代和用户输入使用相同的变量x
,
否则你正在搞乱循环。
修改强>
用户user3629249在评论中写道
良好的信息,但结果将是链表中的第一个条目将包含垃圾。 最好通过以下方式宣布:
Node *head = NULL
;并且函数addToList()
检查NULL并相应地继续。
没错,head
元素不会以这种方式保存任何数字。
选项1:双指针
这里addToList
收到一个双指针。 head
的初始化发生
当*head
指向NULL
时。该函数为其分配内存,进行初始化
记忆,保存价值和回报。在addToList
的并发调用中
*head
不会是NULL
,因此addToList
会查找列表的结尾。
我对malloc
和realloc
的方式做了一些小改动。我还补充说
freeList
的实现应该用来释放内存:
void addToList(Node **head, int val) {
if(head == NULL)
{
fprintf(stderr, "head cannot be NULL\n");
return;
}
if(*head == NULL)
{
*head = calloc(1, sizeof **head);
head[0]->val = val;
head[0]->next = NULL;
return;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof *current->next);
if(current->next == NULL)
return;
current->next->val = val;
current->next->next = NULL;
}
int main(void)
{
int x;
Node *head = NULL;
for (x = 1; x < 4; x++)
{
int val;
printf("Enter an integer: ");
if(scanf("%d", &val) != 1)
{
fprintf(stderr, "Could not read from user. Skipping entry\n");
continue;
}
addToList(&head, val);
}
printList(head);
freeList(head);
return 0;
}
void freeList(Node *head)
{
if(head == NULL)
return;
Node *current = head;
Node *next;
while(next = current->next)
{
free(current);
current = next;
}
free(current); // the last one
free(head);
}
选项2:addToList
返回指向头部的指针
这里addToList
指向头部。如果是NULL
,则分配
内存和初始化如上所示。如果head
不是NULL
,那么。{
函数查找最后一个元素,并返回head
。出错了
函数返回NULL
。
Node *addToList(Node *head, int val) {
if(head == NULL)
{
head = calloc(1, sizeof **head);
head->val = val;
head->next = NULL;
return head;
}
Node *current = *head;
while (current->next != NULL) {
current = current->next;
}
current->next = malloc(sizeof *current->next);
if(current->next == NULL)
return NULL;
current->next->val = val;
current->next->next = NULL;
return head;
}
int main(void)
{
int x;
Node *head = NULL, *tmp;
for (x = 1; x < 4; x++)
{
int val;
printf("Enter an integer: ");
if(scanf("%d", &val) != 1)
{
fprintf(stderr, "Could not read from user. Skipping entry\n");
continue;
}
tmp = addToList(head, val);
if(tmp == NULL)
{
fprintf(stderr, "Not enough memory\n");
freeList(head);
return 1;
}
head = tmp;
}
printList(head);
freeList(head);
return 0;
}