跟随一些论坛和教程,我写了一个排序链表的代码。代码导致堆芯转储。我认为错误是在第50行之后,我试图在末尾插入节点。你能帮我解决这个问题吗?我不确定我做错了什么。谢谢。
#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
struct node
{
char val;
struct node* next;
};
struct node *start = (struct node*) NULL;
// definition of creating only first node
struct node* create(char* data)
{
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
if (start == NULL)
{
temp->val = data;
temp->next = NULL;
start = temp;
}
printf("List createdn");
}
struct node* insert(char* data)
{
int i, pos;
struct node* tempnode, *ptr;
ptr = start;
while(ptr != NULL)
{
if (data <= ptr->val)
{
printf("!!!Inserting before!!!n");
tempnode = (struct node*)malloc(sizeof(struct node));
tempnode->val = ptr->val;
tempnode->next=ptr->next;
ptr->val = data;
ptr->next=tempnode;
break;
}
else if (data > ptr->val)
{
printf("!!!Going next!!!n");
ptr = ptr->next;
}
if (ptr == NULL) //insert behind the node
{
tempnode = (struct node*)malloc(sizeof(struct node));
tempnode->val = data;
tempnode->next = NULL;
ptr->next = tempnode;
printf("!!!Placed at the end!!!n");
break;
}
}
}
void display()
{
struct node* ptr; // ptr is pointer
ptr = start;
while (ptr != NULL)
{
printf("%s->", ptr->val);
ptr = ptr->next;
}
printf("End of listn");
}
int main()
{
char* data;
int i = 0;
create(0);
FILE* file = fopen("words.txt", "r");
while (i < 10)
{
fscanf(file, "%s", &data);
printf ("data is %sn", &data);
insert(data);
i++;
}
display();
}
在这里,在insert
函数的底部,您已经保证ptr
为NULL,但是您仍然执行ptr->next = ...
。这相当于(*ptr).next = ...
解除NULL指针的引用!
if (ptr == NULL) //insert behind the node
{
tempnode = (struct node*)malloc(sizeof(struct node));
tempnode->val = data;
tempnode->next = NULL;
ptr->next = tempnode;
printf("!!!Placed at the end!!!n");
break;
}
局部变量永远不会初始化,它们的值是不确定的(并且看起来是随机的)。使用未初始化的局部变量会导致未定义行为。
现在看看main
函数中的data
变量:它是未初始化的,因此不能使用,直到您实际使它指向某个地方。既然你不这么做,你就有了未定义行为。在fscanf
调用中也错误地使用它,因为您将指针的地址传递给fscanf
。虽然实参应该是指针,但data
已经是指针了。您只需要为它分配内存。最简单的方法是将其改为数组而不是指针:
char data[128];
还有其他一些问题,比如你使用<=
这样的比较操作符来比较字符串。这将只比较指针。使用strcmp
比较字符串。另一个问题是,即使您修复了上述问题,它也不会像您期望的那样工作,这是因为您对所有节点使用了相同的字符串指针。添加节点时需要复制字符串。这可以通过strdup
函数完成:
ptr->val = strdup(data);
当然,由于使用malloc
为字符串分配内存,您必须手动free
此内存。
我的第一个观察是,您没有在main中为char* data
分配内存。这样做fscanf(file, "%s", data);
时,您正在破坏内存。此外,你想动态分配/释放这个内存不像char data[128]
,因为你希望每个节点有不同的数据。
这段代码有很多问题。它编译时没有警告吗?它能编译吗?
-
在main()中,您在使用
data
之前没有初始化它。 -
create()和insert()都说它们返回
struct node*
,但不返回任何东西。 -
insert()将
char *data
作为参数,但是您在该函数中指定了tmpnode->val = data
。根据你们对struct node
的申报,val
是char
,而不是char *
。 -
在
main()
中,data
是char *
,你将指针的地址传递给fscanf()
。并且您没有为data
分配任何内存,也没有将其初始化为任何非随机的东西,因此您将伪造指针的地址传递给fscanf()。
还有很多,但这是一个好的开始。如果您在编译器中禁用了警告,请再次启用它们——它们会告诉您一些重要的事情。如果你收到警告却忽略了它们,不要再忽略它们了——它们在告诉你一些重要的事情。
我几乎从头开始重新编写代码,我相信可能还有很多事情需要修复,但它确实对输入进行了排序。唯一困扰我的是,Valgrind抛出大量的错误为我的free - memory函数
HEAP SUMMARY:
==8731== in use at exit: 0 bytes in 0 blocks
==8731== total heap usage: 9 allocs, 32 frees, 1,016 bytes allocated
==8731==
==8731== All heap blocks were freed -- no leaks are possible
==8731==
==8731== For counts of detected and suppressed errors, rerun with: -v
==8731== ERROR SUMMARY: 38 errors from 6 contexts (suppressed: 2 from 2)
无论如何,我的解决方案是在这里:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// maximum length for a word
#define LENGTH 45
// default dictionary
#define DICTIONARY "words.txt"
typedef struct node
{
char word[LENGTH + 1];
struct node* next;
}
Word;
Word *head = NULL; //start
Word *cur = NULL; //cursor
Word *cur2 = NULL; //cursor
/****************************************/
/* PROTOTYPES */
/****************************************/
Word* create(char *node);
void display();
void freememory();
/****************************************/
/* FUNCTIONS */
/****************************************/
Word* create(char *node)
{
Word *new_node = NULL;
new_node = (Word*)malloc(sizeof(Word));
strncpy(new_node->word, node, LENGTH);
if(head==NULL)
{
head=new_node;
new_node->next=NULL;
}
else
{
cur = head;
cur2 = cur->next;
while (cur != NULL)
{
if (strcmp(new_node->word, cur->word) > 0 )
{
if (cur->next == NULL)
{
new_node->next = NULL;
cur->next = new_node;
break;
}
else if (strcmp(new_node->word, cur->word) > 0 && strcmp(new_node->word, cur2->word) <= 0)
{
new_node->next = cur->next;
cur->next = new_node;
break;
}
}
else if (strcmp(new_node->word, cur->word) <= 0 )
{
new_node->next = head;
head = new_node;
break;
}
cur = cur->next;
cur2 = cur2->next;
}
}
return head;
}
// output the list
void display()
{
//Word *Wordlist;
cur = head;
while (cur != NULL)
{
printf("%s->", cur->word);
cur = cur->next;
}
printf("End of the list!n");
}
// free allocated memory
void freememory()
{
Word *temp = NULL;
Word *temp2 = NULL;
cur = head;
cur2 = head;
while(cur != NULL)
{
temp = cur;
cur = cur->next;
free(cur);
free(temp);
}
while(cur2 != NULL)
{
temp2 = cur2;
cur2 = cur2->next;
free(cur2);
free(temp2);
}
free(head);
}
/****************************************/
/* M A I N */
/****************************************/
int main()
{
system("clear");
char data[LENGTH];
FILE* file = fopen(DICTIONARY, "r");
// check successful opening of the file
if(file == NULL) {
perror("Error opening file");
return -1;
}
//read data (words) from file
while(fscanf (file, "%s", data) == 1)
{
create(data);
}
display();
freememory();
fclose(file);
return 0;
}