1

我正在将文件加载到内存中,并且使用以下语句执行此操作:

        if ((ch = fread(&temp[i],1,1,loadDict)) == EOF)
            break;

但我收到分段错误。使用 gdb 检查后,我确认故障发生在这一行(if 语句,在中断之前)。为什么它看不到它会出错(使用 EOF 的全部意义)?

我认为这可能是我在 if 语句中而不是在 while() 语句中使用 EOF。是否可以在 if 语句中使用 EOF?

更新:更多代码

bool load(const char* dictionary)
{
FILE* loadDict = fopen(dictionary, "r");

char* new = malloc(sizeof(char)); // for storing the "new-line" character
*new = 0x0A;

// defines a node, which containes one word and points to the next word
typedef struct node
{
char* word;
struct node* next;
}
node;


    node* head = malloc(sizeof(node));
    node* temp = malloc(sizeof(node));
    head->next=temp;

    // copies a word from the dictionary file into a node

    int* numStore = malloc(sizeof(int)); //count for number of words in dictionary
    int num = 0;
    int ch = 0; // to hold for EOF
    int flag = 0; // for breaking out of while loop
    while(true)
    {
    node* newNode = malloc(sizeof(node));
    temp->next=newNode;
    temp->word=malloc(46);

        int i = -1;

        do
        {
        i++;
        if (!feof(loadDict) || !ferror(loadDict))
        {
            flag = 1;
            break;
        }
        fread(&temp[i],1,1,loadDict);

        if  (memcmp (new, &temp[i], 1) == 0)
            num += 1;
        }
        while(memcmp (new, &temp[i], 1) != 0);

    temp=newNode;

    if (flag == 1)
        break;
    }

   numStore = #

return true;
}
4

3 回答 3

4
typedef struct node
{
char* word;
struct node* next;
}

您定义的结构可能会崩溃,至少我见过的实现会崩溃。节点内的 char* 没有固定值。所以当你这样做时:

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

malloc() 将分配 5 个字节的内存(char 指针占用 1 个字节,node 占用一个 int 大小指针,在 32 位机器上默认为 4 个字节)。当您读取超过 5 个字节时会发生什么?

此外,你不必要地使这个复杂化:

int* numStore = malloc(sizeof(int));

如果您想在字典中存储单词的数量,请立即使用int numstore,减少头痛:)

    while(true)
    {
        node* newNode = malloc(sizeof(node));
        temp->next=newNode;
        temp->word=malloc(46);
        ...
    }

现在,这是一个有趣的概念。如果你想读到文件末尾,你有两个选择:1)feof() 在循环结束时使用 2),试试这个:

   while(true)
   {
       ....
       if(fgetc(loadDict)==EOF) break; else fseek(loadDict,-1,SEEK_CUR);
   }

另外,这一行:temp->word=malloc(46); 你为什么要手动分配 46 个字节?

Armin 是正确的,&temp[i],虽然 i 确实被分配到 0,但 do{...}while(); 完全没有必要。

同样来自 man fread : http: //www.manpagez.com/man/3/fread/ 您正在阅读对我来说看起来像 1 个字符的内容。

在我看来,尝试这样的事情:

设置一个字长的最大值(如 50,实际用途更多) 用 fscanf 读入它 用 fscanf 获取它的长度 分配内存

此外,您不需要为 *head 分配内存;它可以保留为我几乎忘记的迭代器符号,如果您返回 bool,您将如何使用返回的列表,并且 *head 丢失了,从而造成内存泄漏,因为您无法释放其余部分?除非你使用 c99,否则 c 不支持 bool

/*Global declaration*/

typedef struct node
{
    char* word;
    struct node* next;
}node;

node *head, *tmp;
/* for the bool if you really want it*/
typedef enum { false, true } bool;

node* load(const char* dictionary)
{
    FILE* loadDict = fopen(dictionary, "r");
    char word[50];
    int num = 0;       
    int len;
    node *old;  
    while(true)
    {
    /*node* newNode = malloc(sizeof(node));
    temp->next=newNode;
    temp->word=malloc(46);*/
        fscanf(loadDict,"%s ",word);
        len = strlen(word);
        tmp = malloc(len + sizeof(node));
        strcpy(tmp->word,word);
        tmp->next = NULL;
        if(head==NULL)
        {
            head = tmp;
            old = head;
        }
        else
            old->next = tmp;
        old = tmp; 
        num++;
        if(fgetc(loadDict)==EOF) break; else fseek(loadDict,-1,SEEK_CUR);    
    }
    printf("number of counted words::\t%d\n",num);
    fclose(loadDict);
    return head;
}

另外,请记住,我只考虑了每个单词之间用一个空格分隔的行为,所以请像那样加载文件 t=,或更改算法 :) 另外,请务必在使用程序后释放内存!

void freeDict()
{
    node *i;
    while(head!=NULL)
    {
        i = head;
        head = head->next;
        free(i);
    }
}

希望这可以帮助 :)

于 2013-04-12T04:49:50.613 回答
2

这编译...我现在也运行它了。分配失败的错误处理是应受谴责的;它至少应该给出一条错误消息,并且可能应该释放所有分配的节点并从函数中返回 0(NULL)(并关闭文件)。

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

typedef struct Node
{
    char        *word;
    struct Node *next;
} Node;

Node *dict_load(const char *dictionary)
{
    FILE *loadDict = fopen(dictionary, "r");

    if (loadDict == 0)
        return 0;

    Node *head = 0;
    char line[4096];
    while (fgets(line, sizeof(line), loadDict) != 0)
    {
        size_t len = strlen(line);           // Includes the newline
        Node *node = malloc(sizeof(*node));
        if (node == 0)
            exit(1);    // Reprehensible
        node->word = malloc(len);
        if (node->word == 0)
            exit(1);    // Reprehensible
        memmove(node->word, line, len - 1);  // Don't copy the newline
        node->word[len-1] = '\0';            // Null terminate the string - tweaked!
        node->next = head;
        head = node;
    }

    fclose(loadDict);
    return head;
}

如果您必须bool从函数返回 a ,那么您可能需要:

static bool dict_load(const char *dictionary, Node **head)

如果参数列表仅固定在文件名上,那么您将被迫使用全局变量,这对设置练习的人来说是令人讨厌的。这是“可行的”,但“丑陋如罪”。

上面的代码确实有效(注意调整后的行);添加函数dict_free()dict_print()发布字典并打印字典以及适当的错误处理,dict_load()并且一个简单的main()允许我在自己的源代码上对其进行测试,并且它可以工作(向后打印源代码)。它也从中获得了一份干净的健康valgrind证明。

于 2013-04-12T04:23:54.287 回答
0

您使用 temp[i] 会引起怀疑,您可能正在访问外部内存。
引用 K&R 的话:

If pa points to a particular element of an array, then by definition pa+1 points 
to the next element, pa+i points i elements after pa, and pa-i points i elements
before. 


These remarks are true regardless of the type or size of the variables in
the array a. The meaning of ``adding 1 to a pointer,'' and by extension,
all pointer arithmetic, is that pa+1 points to the next object, and pa+i
points to the i-th object beyond pa.     
于 2013-04-12T04:25:08.117 回答