为什么从文件函数读取崩溃?

时间:2018-01-14 02:14:14

标签: c file fgets strcpy

尝试从文件中读取多行以将它们存储在由字符串元素组成的结构中,但是当我运行该程序时,它只是崩溃而且我不知道为什么会这样做。

有问题的功能:

Hashtbl* loadfromfile(Hashtbl* hashtbl, char *path){
    int i = 0;
    char line[100];
    char* string[40];

    FILE *f = fopen(path, "r");

    if(f == NULL){
        printf("FILE NO FOUND!");
    }else{
        while(fgets(line, sizeof(line), f)!=NULL){
           strcpy(string[i],line);
           i++;
       }
       fclose(f);
       for(i = 0; i<(SIZE*2); i++){
            strcpy(hashtbl[i].subscript, string[i]);
            i++;
       }

       for(i = 1; i<(SIZE*2); i++){
           strcpy(hashtbl[i].value, string[i]);
           i++;
       }

       return hashtbl;
       }
}

main.c中:

#include <stdio.h>
#include <stdlib.h>
#include "hashtable.h"

int main() {

    Hashtbl* numbers;
    numbers = init_hashtbl(); //init_hashtable initialises numbers
    loadfromfile(numbers, "test.txt");
    for(int i = 0; i<SIZE; i++) {
        printf("%s1", numbers[i].subscript);
        printf("%s2\n", numbers[i].value);
    }
}

哈希表结构:

typedef struct Hashtbls{
    char *subscript;
    char *value;
} Hashtbl;

init_hasthable函数:

   Hashtbl* init_hashtbl(){
       Hashtbl* hashtbl;
       hashtbl = calloc(SIZE, sizeof(Hashtbl));
       for(int i = 0; i<SIZE; i++){
           hashtbl[i].subscript = "ZERO";
           hashtbl[i].value = "ZERO";
       }
       return hashtbl;
   }

1 个答案:

答案 0 :(得分:2)

这里有很多问题:

if(f == NULL){
    printf("FILE NO FOUND!");
}

如果无法打开文件,则无法继续。消息也可能 稍后打印,请改用printf("FILE NOT FOUND!\n");

char* string[40];
...
while(fgets(line, sizeof(line), f)!=NULL){
    strcpy(string[i],line);
    i++;
}

string是一个未初始化的指针数组,你不能写任何东西 那里。你应该做

while(fgets(line, sizeof line, f))
{
    string[i] = malloc(strlen(line) + 1);
    if(string[i] == NULL)
    {
        // error handling is needed
    }
    strcpy(string[i], line);
    i++;
    if(i == sizeof string / sizeof *string)
        break;
}

// or if your system has strdup

while(fgets(line, sizeof line, f))
{
    string[i] = strdup(line);
    if(string[i] == NULL)
    {
        // error handling is needed
    }
    i++;
    if(i == sizeof string / sizeof *string)
        break;
}

此外,您不会检查是否阅读超过40行。我这样做了 最后ifsizeof array / sizeof *array返回的数字 数组可以容纳的元素。请注意,这仅适用于数组,而不适用于数组 指针,因为一般sizeof array != sizeof pointer。也别忘了 之后释放分配的内存。

strcpy(hashtbl[i].subscript, string[i]);
...
strcpy(hashtbl[i].value, string[i]);

这里的subscriptvalue参数是否以某种方式初始化?校验 你的init_hashtbl()

修改

现在您发布了init_hashtbl

for(i = 0; i<(SIZE*2); i++){
    strcpy(hashtbl[i].subscript, string[i]);
    i++;
}

您正在使用字符串文字初始化subscriptvalue 指向只读内存位置,strcpy将失败。你有 使用malloc分配内存或使用数组更改结构。

选项1

保留结构,更改init_hashtbl

Hashtbl* init_hashtbl(){
   Hashtbl* hashtbl;
   hashtbl = calloc(SIZE, sizeof(Hashtbl));
   for(int i = 0; i<SIZE; i++){
       hashtbl[i].subscript = malloc(SOME_MAXIMAL_LENGTH + 1);
       strcpy(hashtbl[i].subscript, "ZERO");

       hashtbl[i].value = malloc(SOME_MAXIMAL_LENGTH + 1);
       strcpy(hashtbl[i].value, "ZERO");
   }
   return hashtbl;
}

您应该始终检查malloc / calloc的返回值。还有 问题在于,如果要复制长度大于的字符串 SOME_MAXIMAL_LENGTH,你将有一个缓冲区溢出。所以你应该 在阅读程序中使用realloc:

for(i = 0; i<(SIZE*2); i++){
    char *tmp = realloc(hashtbl[i].subscript, strlen(string[i]) + 1);
    if(tmp == NULL)
    {
        // error handling
    }

    hashtbl[i].subscript = tmp;
    strcpy(hashtbl[i].subscript, string[i]);
    i++;
}

如果你不想在这里处理realloc,你必须确保,不 string[i]超过SOME_MAXIMAL_LENGTH

选项2

更改结构和init:

typedef struct Hashtbls{
    char subscript[SOME_MAXIMAL_LENGTH];
    char value[SOME_MAXIMAL_LENGTH];
} Hashtbl;


Hashtbl* init_hashtbl(){
   Hashtbl* hashtbl;
   hashtbl = calloc(SIZE, sizeof(Hashtbl));
   for(int i = 0; i<SIZE; i++){
       strcpy(hashtbl[i].subscript, "ZERO");
       strcpy(hashtbl[i].value, "ZERO");
   }
   return hashtbl;
}

然后在loadfromfile中,您无需处理realloc,如图所示 上面,你可以保留你的代码。但是,你必须检查没有string[i]SOME_MAXIMAL_LENGTH - 1长,否则缓冲区溢出。

最后一件事,fgets读取整行,假设长度为 line小于sizeof line,换行符将添加到。{ 线。你很可能不想拥有它。摆脱困境的一种方法 换行是:

fgets(line, sizeof line, f);
int len = strlen(line);
if(line[len - 1] == '\n')
    line[len - 1] = 0;