C 中的链接列表不起作用 Valgrind 错误

Linked List in C not working Valgrind Error

该程序应该将文件中的单词读取到链表中。我使链接列表正常工作,但现在我遇到了另一个错误。使用非常大的文件时出现分段错误。

它适用于较小的列表(3-10 个单词),但不适用于较大的列表。

-----CODE-----
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node //struct for linked list
{
    char* word;
    struct node* next;
}
node;  

int main (void)
{        
    char* dictfile = "large";

    FILE* dict = fopen(dictfile, "r");

    if (dict == NULL)
        return 1;

    node* head = NULL;       

    char* oneword = malloc(sizeof(node));  //to store the word from fgets()

    while ((fscanf (dict, "%s", oneword)) > 0)
    {                                        
        node* temp = (node*)malloc(sizeof(node));

        char* tempword = (char*)malloc(sizeof(node)); //gives me a new pointer to store the string (as pointed out by Antione)

        strcpy(tempword, oneword);

        temp->word = tempword;

        printf("%s\n", temp->word);     //prints the value (just for debug)

        temp->next = head;            
        head = temp;             
    }

    node* temp = (node*)malloc(sizeof(node));
    temp = head;

    while(temp != NULL)    //loop to print the linked list
    {           
        printf("traverse %s\n", temp->word);    //prefix 'ing traverse to know its a linked list
        temp = temp->next;
    }

    free(head);
    free(temp);
    fclose(dict);

    printf("SUCCESS!!\n");      

}    

结果如下:

./tempeol
.............lots of words then the below
acceptor
acceptor's
tempeol: malloc.c:2372: sysmalloc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 *(sizeof(size_t))) - 1)) & ~((2 *(sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long) old_end & pagemask) == 0)' failed.
Aborted (core dumped)

Valgrind 在一些地方显示无效写入。

一个是 strcpy() 的位置。我必须考虑额外的空字符来解决这个问题,但我不知道如何解决。

    -----Valgrind Error-----
jharvard@appliance (~/Dropbox/pset5): valgrind ./tempeol
==4709== Memcheck, a memory error detector
==4709== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==4709== Using Valgrind-3.10.0.SVN and LibVEX; rerun with -h for copyright info
==4709== Command: ./tempeol
==4709== 
a
aaa
aaas
aachen
aalborg
==4709== Invalid write of size 1
==4709==    at 0x40DB401: _IO_vfscanf (vfscanf.c:1180)
==4709==    by 0x40E21F6: __isoc99_fscanf (isoc99_fscanf.c:34)
==4709==    by 0x8048681: main (tempeol.c:25)
==4709==  Address 0x423b1c0 is 0 bytes after a block of size 8 alloc'd
==4709==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4709==    by 0x8048662: main (tempeol.c:23)
==4709== 
==4709== Invalid read of size 1
==4709==    at 0x402D4F1: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4709==    by 0x80486D5: main (tempeol.c:31)
==4709==  Address 0x423b1c0 is 0 bytes after a block of size 8 alloc'd
==4709==    at 0x402A17C: malloc (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so)
==4709==    by 0x8048662: main (tempeol.c:23)
==4709== 
aalesund

需要帮助!!

还有一件有趣的事:如果我将 char* tempword = (char*)malloc(sizeof(node)); 更改为 char* tempword = (char*)malloc(sizeof(node)*512);,我最终会得到完整的链表,但最后会出现分段错误。

我觉得解决方案就在这行代码中。有什么想法吗??

=========================================== ==================

感谢@DrC 和@lurker,我让它工作了。 Valgrind 没有显示任何错误。没有分段错误。 :)

这是供任何需要它的人使用的最终工作代码:

================WORKING CODE:: SOLUTION============
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct node //struct for linked list
{
    char* word;
    struct node* next;
}
node;  

int main (void)
{        
    char* dictfile = "small";

    FILE* dict = fopen(dictfile, "r");

    if (dict == NULL)
        return 1;

    node* head = NULL;       

    char oneword[28];  //to store the word from fscanf()

    while ((fscanf (dict, "%s", oneword)) > 0)
    {                                        
        node* temp = (node*)malloc(sizeof(node));

        char* tempword = (char*)malloc(strlen(oneword)+1); //gives me a new pointer to store the string (as pointed out by Antione)

        strcpy(tempword, oneword);

        temp->word = tempword;

        //printf("%s\n", temp->word);     //prints the value (just for debug)

        temp->next = head;            
        head = temp;             
    }

    node* temp = head;

    while(temp != NULL)    //loop to print the linked list
    {           
        printf("%s\n", temp->word);    //prefix 'ing traverse to know its a linked list
        temp = temp->next;
    }

    printf("\n");

    free(head);
    //free(temp);   //no need for this (DrC)
    fclose(dict);

    printf("SUCCESS!!\n");      

}    

我可以睡觉了...

第一个问题的代码行是正确的。您根据 sizeof(node) malloc 内存来保存字符串。相反,它的长度应该是 strlen(oneword)+1。现在,任何长字都会超出缓冲区。

char* tempword = (char*)malloc(strlen(oneword)+1);

行中:

...}

node* temp = (node*)malloc(sizeof(node));
temp = head;

while(temp != NULL)  ...

您将 temp 分配给一些 malloc 存储,然后立即将 temp 设置为 head - 从而泄漏存储(轻微)。

非常小的项目 - 最后调用 free(temp) 是一种浪费,因为 temp 必然为空。