Почему чтение происходит из файловой функции?

Попытка прочитать несколько строк из файла, чтобы сохранить их в структуре, состоящей из строковых элементов, однако, когда я запускаю программу, она просто сбой, и я не знаю, почему.

функция в вопросе:

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  #include  #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); } } 

Структура Hashtable:

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

У вас здесь немало проблем:

 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 строк. Я сделал это с последним, if . sizeof array / sizeof *array возвращает количество элементов, которые может содержать массив. Обратите внимание, что это работает только для массивов, а не для указателей, поскольку в целом sizeof array != sizeof pointer . Также не забывайте освобождать выделенную память впоследствии.

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

Являются ли параметры subscript и value здесь инициализированы каким-то образом? Проверьте свой init_hashtbl() .


РЕДАКТИРОВАТЬ

Теперь, когда вы разместили init_hashtbl :

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

Вы инициализируете subscript и value строковыми литералами, они указывают на постоянное расположение памяти, strcpy будет терпеть неудачу. Вы должны либо выделить память с помощью malloc либо изменить структуру с помощью массивов.

Опция 1

Сохраните структуру, измените init_hashtbl

 Hashtbl* init_hashtbl(){ Hashtbl* hashtbl; hashtbl = calloc(SIZE, sizeof(Hashtbl)); for(int i = 0; i 

Вы всегда должны проверять возвращаемое значение 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 

Затем в loadfromfile вам не нужно иметь дело с realloc как показано выше, вы можете сохранить свой код. Однако вам нужно проверить, что string[i] больше, чем SOME_MAXIMAL_LENGTH - 1 , иначе переполнение буфера.

Наконец, fgets читает целую строку, предполагая, что длина строки меньше, чем sizeof line , символ новой строки будет добавлен в строку. Скорее всего, вы этого не хотите. Один из способов избавиться от новой строки:

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