为什么从文件功能读取会崩溃? [英] Why is reading from file function crashing?

查看:107
本文介绍了为什么从文件功能读取会崩溃?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Trying to read multiple line from file to store them in a structure made up of the string elements, however when I run the program it simply crashes and I haven't the faintest idea why.

有问题的功能

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函数:

init_hasthable function:

   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;
   }

推荐答案

您在这里有很多问题:

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

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

If the file cannot be opened, then you cannot continue. Also the message might be printed way later, use printf("FILE NOT FOUND!\n"); instead.

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

string是未初始化指针的数组,您无法编写任何内容 那里.你应该做

string is an array of uninitialized pointers, you cannot write anything there. You should do

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多行.我做到了 最后一个if. sizeof array / sizeof *array返回 数组可以容纳的元素.请注意,这仅适用于数组,不适用于数组 指针,通常是sizeof array != sizeof pointer.也不要忘记 释放之后分配的内存.

Also you are not checking whether you read more than 40 lines. I did that with the the last if. sizeof array / sizeof *array returns the number of elements that an array can hold. Note that this only works for arrays, not pointers, since in general sizeof array != sizeof pointer. Also don't forget to free the allocated memory afterwards.

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

这里的subscriptvalue参数是否以某种方式初始化?查看 您的init_hashtbl().

Are the subscript and value parameters here initialized in some way? Check your init_hashtbl().

编辑

现在您发布了init_hashtbl:

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

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

You are initializing subscript and value with string literals, they are pointing to read-only memory location, strcpy is going to fail. You have to either allocate memory with malloc or change your structure with arrays.

选项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:

You should always check the return value of malloc/calloc. Also the problem here is that if you want to copy a string that is longer than SOME_MAXIMAL_LENGTH, you are going to have a buffer overflow. So you should use realloc in the reading routine:

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.

If you don't want to deal with realloc here, you have to make sure, that no string[i] is longer than SOME_MAXIMAL_LENGTH.

选项2

更改您的结构和初始化:

Change you structure and 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,否则缓冲区溢出.

Then in loadfromfile you don't have to deal with the realloc as shown above, you can keep your code. However, you have to check that no string[i] is longer than SOME_MAXIMAL_LENGTH - 1, otherwise buffer overflow.

最后一件事,fgets读取整行,假设 行小于sizeof line,则将换行符添加到 线.您很可能不想拥有它.摆脱的一种方法 换行符是:

One last thing, fgets reads a whole line, assuming that the length of the line is lesser than sizeof line, the newline character will be added to the line. You most likely don't want to have that. One way of getting rid of the newline is:

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

这篇关于为什么从文件功能读取会崩溃?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆