即使使用EOF,C分段也会出现故障

时间:2013-04-12 03:14:15

标签: c segmentation-fault eof

我正在将文件加载到内存中,我正在使用以下语句:

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

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

我认为可能是我在if语句中使用EOF而不是在while()语句中。是否可以在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;
}

3 个答案:

答案 0 :(得分:4)

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

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

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

malloc()将分配一个内存(对于char指针使用1个字节,对于节点使用int size指针,在32位计算机上默认为4个字节)5个字节。当你读取超过5个字节时会发生什么?

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

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

如果你想在dictonary中存储单词的数量,请立即使用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],而我确实被分配到0,do {...} while();完全没必要。

同样来自男人的恐惧: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);
    }
}

希望这会有所帮助:)

答案 1 :(得分: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,那么您可能需要:

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

如果参数列表只是固定在文件名中,那么你就不得不使用一个全局变量,这对于设置练习的人来说是很讨厌的。它是“可行的”,但“像罪一样丑陋”。

上面的代码确实有用(注意调整后的行);添加函数dict_free()dict_print()以释放字典并打印字典以及dict_load()中的正确错误处理,并且简单main()允许我在其自己的源代码上测试它,它的工作原理(向后打印源)。它也从valgrind获得了健康的健康状况。

答案 2 :(得分:0)

你使用temp [i]引起怀疑,你可能正在访问外部记忆 引用K&amp; 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.