В вашей программе есть некоторые проблемы, которые могут вызвать неопределенное поведение, которое вы наблюдаете:
- Вы не проверяете, был ли файл открыт успешно, вызывая неопределенное поведение, если файл находится не там, где вы ожидаете, или имеет другое имя.
- Вы не ограничиваете количество строк, считываемых в массив, вызывая неопределенное поведение, если файл содержит более 99998 строк, что может быть в случае с linux, например, если
/usr/share/dict/words
имеет 139716 строк в моей системе.
Ваша схема выделения памяти неоптимальная, но правильная: вам нужно вычислить длину слова и убрать новую строку до выделения копии. Как закодировано, вы выделяете слишком много памяти. Тем не менее, вы должны освободить line
перед возвратом из read_to_array
, и вам следует избегать использования глобальных переменных.
Вот модифицированная версия:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **read_to_array(const char *filename, int *countp) {
FILE *words_file;
char *line = NULL;
size_t line_size = 0;
char **dic = NULL;
int dic_size = 0;
int i = 0;
words_file = fopen(filename, "r");
if (words_file == NULL) {
fprintf(stderr, "cannot open dictionary file %s\n", filename);
return NULL;
}
dic_size = 99999;
dic = malloc(dic_size * sizeof(char *));
if (dic == NULL) {
fprintf(stderr, "cannot allocate dictionary array\n");
fclose(words_file);
return NULL;
}
// read dic to array
while (getline(&line, &line_size, words_file) != -1) {
size_t len = strlen(line);
/* strip the newline if any */
if (len > 0 && line[len - 1] == '\n') {
line[--len] = '\0';
}
if (i >= dic_size - 1) {
/* too many lines: should reallocate the dictionary */
fprintf(stderr, "too many lines\n");
break;
}
dic[i] = malloc(len + 1);
if (dic[i] == NULL) {
/* out of memory: report the error */
fprintf(stderr, "cannot allocate memory for line %d\n", i);
break;
}
strcpy(dic[i], line);
i++;
}
dic[i] = NULL;
*countp = i;
fclose(words_file);
free(line);
return dic;
}
int main(int argc, char **argv) {
const char *filename = (argc > 1) ? argv[1] : "words.txt";
int num_words;
char **dic = read_to_array(filename, &num_words);
if (dic != NULL) {
printf("dictionary loaded: %d lines\n", num_words);
while (num_words > 0)
free(dic[--num_words]);
free(dic);
}
return 0;
}
Выход:
chqrlie> readdic /usr/share/dict/words
too many lines
dictionary loaded: 99998 lines