Кажется, я теряю ссылку на мои указатели здесь. Я не знаю почему, но я подозреваю, что это указатель, возвращаемый fgets, который все портит. Мне сказали, что хороший способ читать слова из файла - это получить строку, а затем разделить слова с помощью strok, но как я могу это сделать, если мои указатели внутри words[i] продолжают исчезать.
текст
Natural Reader is
john make tame
Результат я получаю.
array[0] = john
array[1] = e
array[2] =
array[3] = john
array[4] = make
array[5] = tame
int main(int argc, char *argv[]) {
FILE *file = fopen(argv[1], "r");
int ch;
int count = 0;
while ((ch = fgetc(file)) != EOF){
if (ch == '\n' || ch == ' ')
count++;
}
fseek(file, 0, SEEK_END);
size_t size = ftell(file);
fseek(file, 0, SEEK_SET);
char** words = calloc(count, size * sizeof(char*) +1 );
int i = 0;
int x = 0;
char ligne [250];
while (fgets(ligne, 80, file)) {
char* word;
word = strtok(ligne, " ,.-\n");
while (word != NULL) {
for (i = 0; i < 3; i++) {
words[x] = word;
word = strtok(NULL, " ,.-\n");
x++;
}
}
}
for (i = 0; i < count; ++i)
if (words[i] != 0){
printf("array[%d] = %s\n", i, words[i]);
}
free(words);
fclose(file);
return 0;
}
В любом случае ваши массивы выглядят поврежденными, потому что вы храните указатели токенов, возвращенные из strtok, но эти указатели являются указателями на ligne. Итак, первое слово &ligne[0]. Когда вы читаете вторую строку, эта строка перезаписывается "John ...". Если вам нужны постоянные строки, вы должны сделать копию. (Используйте strdup, который не является стандартным, но широко доступным.)
(Но поскольку вы не различаете символы новой строки и другие виды пробелов, вы можете просто прочитать весь файл как одну строку и разметить ее. Токены будут хороши, пока существует длинная строка.)



strtok не выделяет память, он возвращает указатель на строку с разделителями в буфере.
поэтому вам нужно выделить память для результата, если вы хотите сохранить слово между итерациями цикла
например
word = strdup(strtok(ligne, " ,.-\n"));
Вы также можете справиться с этим, используя уникальный ligne для каждой прочитанной строки, поэтому сделайте его массивом строк, например так:
char ligne[20][80]; // no need to make the string 250 since fgets limits it to 80
Затем ваш цикл while изменится на:
int lno = 0;
while (fgets(ligne[lno], 80, file)) {
char *word;
word = strtok(ligne[lno], " ,.-\n");
while (word != NULL) {
words[x++] = word;
word = strtok(NULL, " ,.-\n");
}
lno++;
}
При необходимости отрегулируйте первый индекс для максимального размера файла или динамически выделяйте буфер строки во время каждой итерации, если вам не нужен такой низкий предел. Вы также можете использовать getline вместо fgets, если ваша реализация поддерживает это; он может справиться с распределением, хотя затем вам нужно освободить блоки, когда вы закончите.
Если вы обрабатываете прозу из реального мира, вы можете включить в свой список другие разделители, такие как двоеточие, точка с запятой, восклицательный знак и вопросительный знак.
В вашем коде много несоответствий: например, сначала вы считаете только пробелы и символы новой строки, а затем размечаете пробелы, новые строки, запятые, точки и тире. Для чего нужна внутренняя
forпетля? Думаюwhile (word != NULL)должно хватить.