C, значения в массиве указателей исчезают (указатели)

Кажется, я теряю ссылку на мои указатели здесь. Я не знаю почему, но я подозреваю, что это указатель, возвращаемый 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;
}

В вашем коде много несоответствий: например, сначала вы считаете только пробелы и символы новой строки, а затем размечаете пробелы, новые строки, запятые, точки и тире. Для чего нужна внутренняя for петля? Думаю while (word != NULL) должно хватить.

M Oehm 17.03.2022 07:30

В любом случае ваши массивы выглядят поврежденными, потому что вы храните указатели токенов, возвращенные из strtok, но эти указатели являются указателями на ligne. Итак, первое слово &ligne[0]. Когда вы читаете вторую строку, эта строка перезаписывается "John ...". Если вам нужны постоянные строки, вы должны сделать копию. (Используйте strdup, который не является стандартным, но широко доступным.)

M Oehm 17.03.2022 07:34

(Но поскольку вы не различаете символы новой строки и другие виды пробелов, вы можете просто прочитать весь файл как одну строку и разметить ее. Токены будут хороши, пока существует длинная строка.)

M Oehm 17.03.2022 07:35
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
3
38
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

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, если ваша реализация поддерживает это; он может справиться с распределением, хотя затем вам нужно освободить блоки, когда вы закончите.

Если вы обрабатываете прозу из реального мира, вы можете включить в свой список другие разделители, такие как двоеточие, точка с запятой, восклицательный знак и вопросительный знак.

Другие вопросы по теме