манипулировать словами файла с помощью массива, заполненного словами (извлекается из файла) - PullRequest
1 голос
/ 11 марта 2019

Я просмотрел файл с fgets.Я токенизирую предложение, возвращаемое fgets с помощью strtok, чтобы получить слова, которые я сохранил, слова в массиве char*

while (fgets(chaine, TAILLE_MAX, fichier) != NULL) {
    chainetoken = strtok(chaine, " ");
    while (chainetoken != NULL) {              
        tableau[i] = chainetoken;
        chainetoken = strtok (NULL, " ");
        i++;
    }// it works wel
}
printf("%d \n", i);

Теперь я хочу просмотреть массив char*(tableau[i]), который содержит слова файла для того, чтобы найти слово, введенное пользователем, и найти 2 предшествующих слова в файле

printf("words to find?\n");
scanf("%s", mot_recherche);

for (j = 0; j < i; j++) {
    printf ("tableau %d.mot %s \n", i, tableau[i]); //tableau[0]=last word of the file
    if (strcmp(mot_recherche, tableau[i]) == 0)
        printf("this word exist \n");
} //doesn't work,it save only the last word of the array(of the file)!!!!

1 Ответ

2 голосов
/ 11 марта 2019

У вас есть три ошибки

1) в

while (fgets(chaine, TAILLE_MAX, fichier) != NULL) 
{
   chainetoken=strtok(chaine," ");
   while (chainetoken != NULL)
   {              
      tableau[i]= chainetoken;
      chainetoken = strtok (NULL," ");
      i++;
    }// it works wel
}

вам нужно сохранить копию ( strdup ) результата strtok , в противном случае вы всегда сохраняете указатель, указывающий внутри chaine который изменяется каждым fgets

2) разделители для strtok должны быть "\ n", иначе '\ n' является частью результата, возвращаемого strtok

3) в

for (j=0; j<i; j++)
{
  printf ("tableau %d.mot %s \n",i,tableau[i]);//tableau[0]=last word of the file
  if (strcmp(mot_recherche,tableau[i])==0)
    printf("this word exist \n");
}//doesn't work,it save only the last word of the array(of the file)!!!!

вы смотрите на запись i вместо j из таблицы

Дополнительное замечание: в в то время как вам необходимо проверить, достигнет ли i количества записей в таблице , иначе вы рискуете выписать из него .


(изменить, чтобы объяснить, почему необходимо дублировать результат strtok)

Имея эту программу, используя strtok как вы (без дублирования):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  FILE * fichier = fopen("in", "r");

  if (fichier != NULL)
  {
#define TAILLE_MAX 32
    char chaine[TAILLE_MAX];
    char * chainetoken;
    char * tableau[16];
    int i = 0, j;

    while ((fgets(chaine, TAILLE_MAX, fichier) != NULL)  &&
           (i != sizeof(tableau)/sizeof(tableau[0])))
    {
      chainetoken=strtok(chaine," \n");
      while (chainetoken != NULL)
      {              
        tableau[i]= chainetoken;
        chainetoken = strtok (NULL," \n");
        i++;
      }
    }
    fclose(fichier);

    for (j = 0; j != i; ++j)
      printf("'%s'\n", tableau[j]);
  }

Компиляция и исполнение:

/tmp % gcc -pedantic -Wextra f.c
/tmp % cat in
1234 5678
1 23 45 678
/tmp % ./a.out
'1'
'45'
'1'
'23'
'45'
'678'

ожидаемый результат - 1234 5678 1 23 45 678, но это не тот случай, и только содержание второй строки in является правильным (потому что это последняя строка файла).

strtok возвращает подстроки цепочек , изменяя его так, чтобы он добавлял нулевой символ каждый раз, когда он возвращает ненулевой указатель, поэтому (я указываю под нулевым символом с помощью '@' )

  • fgets читает первую строку, chaine_ содержит "1234 5678 \ n @"
  • strtok заменяет пробел в "1234 5678 \ n @" нулевым символом и возвращает адрес chaine ("1234 @ 5678 \ n @"), который запоминается в tableau[0]
  • strtok заменяет '\ n' нулевым символом и возвращает цепочку + 5 ("5678 @"), запомненную в tableau[1]
  • следующий следующий вызов strtok возвращает нулевой указатель
  • fgets читает следующую строку и изменяет chaine на «1 23 45 678 \ n @»
  • strtok заменяет пробел после '1' нулевым символом и возвращает адрес chaine ("1 @ 23 045 678 \ n @"), запомненный в tableau[2]
  • strtok заменяет пробел после '3' нулевым символом и возвращает chaine + 2 ("23 @ 45 678 \ n @"), запомненные в tableau[3]
  • strtok заменяет пробел после '5' на нулевой символ и возвращает chaine + 5 ("45 @ 678 \ n @"), запоминаемый в tableau[4]
  • strtok заменяет '\ n' нулевым символом и возвращает chaine + 8 ("678 @"), запомненные в tableau[5]
  • strtok вернуть нулевой указатель

теперь chaine содержит "1 @ 23 @ 45 @ 678 @", а указатели в table * :

  • tableau [0] = chaine = "1 @ 23 @ 45 @ 678 @", printf выдает «1» вместо ожидаемого «1234»
  • tableau [1] = chaine + 5 : "45 @ 678 @", печать дает 45, а не 5678, ожидаемое
  • tableau [2] = chaine : «1 @ 23 @ 45 @ 678 @», printf выдает «1»
  • tableau [3] = chaine + 2 : «23 @ 45 @ 678 @», printf выдает «23»
  • tableau [4] = chaine + 5 : "45 @ 678 @", printf выдает 45
  • tableau [5] = chaine + 8 : «678 @», printf выдает «678»

именно поэтому необходимо дублировать результат strtok :

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
  FILE * fichier = fopen("in", "r");

  if (fichier != NULL)
  {
#define TAILLE_MAX 32
    char chaine[TAILLE_MAX];
    char * chainetoken;
    char * tableau[16];
    int i = 0, j;

    while ((fgets(chaine, TAILLE_MAX, fichier) != NULL)  &&
       (i != sizeof(tableau)/sizeof(tableau[0])))
    {
      chainetoken=strtok(chaine," \n");
      while (chainetoken != NULL)
      {              
        tableau[i]= strdup(chainetoken);
        chainetoken = strtok (NULL," \n");
        i++;
      }
    }
    fclose(fichier);

    for (j = 0; j != i; ++j) {
      printf("'%s'\n", tableau[j]);
      free(tableau[j]); /* to avoid memory leak */
    }
  }
}

Компиляция и исполнение:

/tmp % gcc -pedantic -Wextra f.c
/tmp % cat in
1234 5678
1 23 45 678
/tmp % ./a.out
'1234'
'5678'
'1'
'23'
'45'
'678'
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...