链接列表不接受下一个元素(C语言)
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链接列表不接受下一个元素(C语言)相关的知识,希望对你有一定的参考价值。
我是C语言的新手,我正在开发一个Linked List示例。
initialize()
函数似乎工作正常,但在第一次调用insert()
之后程序崩溃了。
我认为问题来自于将新元素添加到链表时,就好像它溢出或者它不接受列表的新第一个元素。
我研究了一个类似的例子,其链接列表只有一个int
元素,并且工作正常。
代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Element Element;
struct Element
{
char f_name[10];
char l_name[10];
float score;
Element* next;
};
typedef struct Liste Liste;
struct Liste
{
Element* first;
};
Element* read()
{
Element* element = (Element*) malloc(sizeof(element));
if(element==NULL)
exit(EXIT_FAILURE);
printf("Please provide first name : \n");
scanf(" %s", element->f_name);
printf("Please provide last name : \n");
scanf(" %s", element->l_name);
printf("Please provide score : \n");
scanf("%f", &(element->score));
return element;
}
Liste* initialize()
{
Liste* liste = (Liste*) malloc(sizeof(liste));
Element* element = (Element*) malloc(sizeof(element));
if(liste==NULL || element==NULL)
exit(EXIT_FAILURE);
element = read();
element->next = NULL;
liste->first = element;
return liste;
}
void insert(Liste* liste)
{
Element* nouveau = (Element*) malloc(sizeof(nouveau));
if(liste==NULL || nouveau==NULL)
exit(EXIT_FAILURE);
nouveau = read();
nouveau->next = liste->first;
liste->first = nouveau;
}
int main()
{
Liste* maListe = (Liste*) malloc(sizeof(maListe));
maListe = initialize();
insert(maListe);
insert(maListe);
insert(maListe);
return 0;
}
我在这个方面做错了什么?我该如何解决?
谢谢。
我认为你的问题是你写了sizeof(element)
,你需要有sizeof(Element)
。你有两个不同的地方。
请注意,“element”是指针类型的变量,因此它具有指针的大小(可能是8个字节),而“Element”是具有更大尺寸的struct类型。所以,当你只分配太小的sizeof(element)
字节时。
通过valgrind运行程序很容易找到这种错误。
虽然您已经有了SegFault的答案,但还有一些方面可以清理和重构代码,以便更有效地协同工作。由于您使用列表结构liste
来保存指向first
中列表开头的指针,因此您还可以添加另一个指针last
以指向列表中的最后一个节点,并且无需在每次插入时迭代到最后一个节点。使用last
(或tail
)指针,您的新节点始终插入last->next
。例如,你Liste
结构可能是:
typedef struct Liste Liste;
struct Liste {
Element *first, *last;
};
你的列表函数应该分别做一件事,这意味着initialize()
应该只分配和初始化Liste
节点及其指针。 read()
应该分配并读取并返回一个指向已填充节点的有效指针,或者在失败时返回NULL。 insert()
应该这样做,从Liste
获取read()
列表addressm和节点并将其插入列表中。将这些功能放在一起你可以做到:
Element *read()
{
Element *element = malloc (sizeof(*element)); /* allocate */
if (element == NULL) /* validate */
return NULL;
element->next = NULL; /* initialize */
printf ("\nPlease provide first name : ");
if (scanf ("%9s", element->f_name) != 1) /* validate EVERY input */
goto badread;
printf ("Please provide last name : ");
if (scanf ("%9s", element->l_name) != 1)
goto badread;
printf ("Please provide score : ");
if (scanf ("%f", &element->score) != 1)
goto badread;
return element; /* return allocated and initialized element */
badread:; /* just a simple goto label for handling read error */
free (element); /* free memory of node if error */
return NULL;
}
(注意:使用goto
将您发送到正常返回之外的标签,您可以为填充期间失败的节点释放内存。)
/* initialize the list, don't worry about the elements */
Liste *initialize (void)
{
Liste *liste = malloc(sizeof *liste);
if (liste == NULL) {
perror ("malloc-liste"); /* give some meaningful error */
exit (EXIT_FAILURE);
}
liste->first = liste->last = NULL;
return liste;
}
void insert (Liste *liste, Element *nouveau)
{
if (liste == NULL || nouveau == NULL)
exit (EXIT_FAILURE);
if (!liste->first) /* inserting 1st node */
liste->first = liste->last = nouveau;
else { /* inserting all others */
liste->last->next = nouveau;
liste->last = nouveau;
}
}
(注意:初始化和插入是直接的,你只处理的两个类是你是插入第一个节点,还是所有其他节点。使它非常简单)
完全放在一起,您可以编写完整的测试代码,如下所示添加一个函数来迭代列表打印值,然后一个类似的函数迭代列表释放节点,然后最后列表::
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXN 10 /* if you need a constant, #define one (or more) */
typedef struct Element Element;
struct Element {
char f_name[MAXN];
char l_name[MAXN];
float score;
Element* next;
};
typedef struct Liste Liste;
struct Liste {
Element *first, *last;
};
Element *read()
{
Element *element = malloc (sizeof(*element)); /* allocate */
if (element == NULL) /* validate */
return NULL;
element->next = NULL; /* initialize */
printf ("\nPlease provide first name : ");
if (scanf ("%9s", element->f_name) != 1) /* validate EVERY input */
goto badread;
printf ("Please provide last name : ");
if (scanf ("%9s", element->l_name) != 1)
goto badread;
printf ("Please provide score : ");
if (scanf ("%f", &element->score) != 1)
goto badread;
return element; /* return allocated and initialized element */
badread:; /* just a simple goto label for handling read error */
free (element); /* free memory of node if error */
return NULL;
}
/* initialize the list, don't worry about the elements */
Liste *initialize (void)
{
Liste *liste = malloc(sizeof *liste);
if (liste == NULL) {
perror ("malloc-liste"); /* give some meaningful error */
exit (EXIT_FAILURE);
}
liste->first = liste->last = NULL;
return liste;
}
void insert (Liste *liste, Element *nouveau)
{
if (liste == NULL || nouveau == NULL)
exit (EXIT_FAILURE);
if (!liste->first) /* inserting 1st node */
liste->first = liste->last = nouveau;
else { /* inserting all others */
liste->last->next = nouveau;
liste->last = nouveau;
}
}
void prnlist (Liste *liste)
{
Element *iter = liste->first;
while (iter) { /* just iterate list outputting values */
printf ("%-10s %-10s -> %.2f\n",
iter->f_name, iter->l_name, iter->score);
iter = iter->next;
}
}
void freelist (Liste *liste)
{
Element *iter = liste->first;
while (iter) {
Element *victim = iter;
iter = iter->next; /* iterate to next node BEFORE */
free (victim); /* you free victim */
}
free (liste);
}
int main (void) {
Liste *maListe = initialize(); /* create/initialize list */
Element *node;
while ((node = read())) /* allocate/read */
insert (maListe, node); /* insert */
puts ("\n\nElements in list:\n"); /* output list values */
prnlist (maListe);
freelist (maListe); /* don't forget to free what you allocate */
return 0;
}
示例使用/输出
$ ./bin/ll_liste
Please provide first name : Donald
Please provide last name : Duck
Please provide score : 99.2
Please provide first name : Minnie
Please provide last name : Mouse
Please provide score : 99.7
Please provide first name : Pluto
Please provide last name : Dog
Please provide score : 83.5
Please provide first name :
Elements in list:
Donald Duck -> 99.20
Minnie Mouse -> 99.70
Pluto Dog -> 83.50
内存使用/错误检查
在您编写的任何动态分配内存的代码中,您对分配的任何内存块都有2个职责:(1)始终保留指向内存块起始地址的指针,因此,(2)当它为no时可以释放它需要更久。
您必须使用内存错误检查程序,以确保您不会尝试访问内存或写入超出/超出已分配块的范围,尝试读取或基于未初始化值的条件跳转,最后,确认你释放了你分配的所有内存。
对于Linux,valgrind
是正常的选择。每个平台都有类似的记忆检查器。它们都很简单易用,只需通过它运行程序即可。
$ valgrind ./bin/ll_liste
==10838== Memcheck, a memory error detector
==10838== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==10838== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==10838== Command: ./bin/ll_liste
==10838==
Please provide first name : Donald
Please provide last name : Duck
Please provide score : 99.2
Please provide first name : Minnie
Please provide last name : Mouse
Please provide score : 99.6
Please provide first name : Pluto
Please provide last name : Dog
Please provide score : 87.2
Please provide first name :
Elements in list:
Donald Duck -> 99.20
Minnie Mouse -> 99.60
Pluto Dog -> 87.20
==10838==
==10838== HEAP SUMMARY:
==10838== in use at exit: 0 bytes in 0 blocks
==10838== total heap usage: 5 allocs, 5 frees, 144 bytes allocated
==10838==
==10838== All heap blocks were freed -- no leaks are possible
==10838==
==10838== For counts of detected and suppressed errors, rerun with: -v
==10838== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
始终确认已释放已分配的所有内存并且没有内存错误。
仔细看看,如果您有疑问,请告诉我。
以上是关于链接列表不接受下一个元素(C语言)的主要内容,如果未能解决你的问题,请参考以下文章