IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

fonction lit fichier et retourne string


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut fonction lit fichier et retourne string
    Bonjour,

    J'apprends le C par moi-même et je me demande s'il est possible (c'est sûrement possible mais je n'arrive pas m'imaginer comment) de créer une fonction qui va lire dans un fichier (soit en argument soit ouvert dans le corps de la fonction), qui mets les mots du fichier dans une chaîne ou un vecteur et le retourne.

    En fait je fais un petit programme qui va chercher des mots dans un texte. Pour l'instant je lui passe le ou les mots à rechercher sur la ligne de commande mais j'aimerais pouvoir les stocker dans un fichier et lire le fichier à l'intérieur du programme pour en extraire les mots.

    Pour l'instant je suis parvenu à ça mais cette fonction se contente d'imprimer les mots lus à l'écran, hors j'aimerais qu'elle puisse les retourner.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int readstr(void)
    {	FILE * flux = fopen("mots_à_chercher", "r") ;
    	if (!flux) return 1 ;
    	int lu, max, x ;
    	char *mots[100] ;
    	for (max = 0 ; lu != EOF ; max++)
    	{	char sas[32] ;
    		lu = fscanf(flux, "%s", sas) ;
    		mots[max] = strdup(sas) ; }
    	for (x = 0 ; x < max -1; x++)
    		printf("%s ", mots[x]) ; 
    	printf("\nnombres de mots à chercher : %d\n", x) ;
    	fclose(flux) ; 
    	return 0 ; }
    Je sais bien que cette fonction n'est sûrement pas optimale mais pour l'instant je fais avec ce que je connais, je vais de tuto en tuto et je cherche de l'aide sur les forums mais là je bloque.

    Est-ce possible de créer un vecteur de caractères, de le passer en argument à la fonction, de le modifier dans la fonction et de le retourner ?

    Merci d'avance.

  2. #2
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    Si tu souhaites lire des mots espacés... je te conseille fgetln et autres getline.
    Avec eux, tu vas extraire 1 ligne à la fois, et pouvoir la traiter.

    Pour extraire les "mots" séparés par des espaces : strtok ou strtok_r !

    Pour passer en paramètre une chaîne de caractères/vecteur de caractères :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    char *str;
     
    str = malloc((TAILLE_STR + 1) * sizeof (char));
    fonction(str);
    free(str);
    "fonction" prenant un char* en paramètre évidemment.
    Dans ce cas, tu vas surtout faire une procédure : tu vas modifier le contenu du tableau, et non pas renvoyer un tableau (c'est beaucoup plus "conseillé" pour éviter de faire passer les tableaux entiers par la "pile" d'exécution).

    N'oublies pas de terminer ta chaîne par un '\0' s'il n'y est pas ! (c'est la raison du "+ 1" dans mon malloc ! )
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Merci beaucoup pour ta réponse, rapide qui plus est.

    Je connais getline et strtok en revanche je n'ai jamais utilisé malloc. Je sais un peu près à quoi sert cette fonction mais je n'ai encore jamais testé, pour l'instant je créer des vecteurs avec des tailles prédéfinies...

    En effet c'était ma seconde idée, modifier le tableau à l'intérieur de la fonction, sans le retourner. Je pensais le créer avant de le passer en argument à la fonction qui le modifiera.

    Je essayé de faire cette fonction qui ne retourne rien mais je pense qu'il y a un problème quelque part car j'obtiens un "assignment makes integer from pointer without a cast".

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    void put_wordslist(str liste)
    {	FILE * wordslist = fopen("mots_à_rechercher", "r") ;
    	if (!wordslist) usage("fichier mots introuvable !") ;
     
    	int lu, max ;
    	for (max=0 ; lu != EOF ; max++)
    	{	char sas[32] ;
    		lu = fscanf(stoplist, "%s", sas) ;
    		liste[max] = strdup(sas) ; }
     
    	fclose(stoplist) ; }
    Je ne comprend pas pourquoi liste semble être considéré comme un int.

  4. #4
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    malloc sert à avoir des tailles dynamiques.
    Mais pour un début, tu peux te contenter de vérifier ton algo avec de la taille statique !

    On va commencer par réorganiser un peu ton code : une meilleure indentation... et mon habitude (bonne ou mauvaise du C89) de mettre les variables en début de déclaration de fonction.
    Je suppose que str est un char*...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    void put_wordslist(str liste)
    {
      FILE *wordslist; 
      int lu, max ;
      char sas[32] ;
     
      wordslist = fopen("fichier.txt", "r") ;
      if (!wordslist)
        usage("fichier mots introuvable !") ;
      for (max = 0; lu != EOF; max++)
      {
        lu = fscanf(stoplist, "%s", sas) ;
        liste[max] = strdup(sas) ;
      }
      fclose(stoplist);
    }
    Le problème vient probablement du "str" ! Pas de *, donc le compilateur panique quand tu lui demandes de déréférencer avec les crochets.
    Peux-tu me montrer le typedef qui va avec ?
    Et stoplist, peux-tu me montrer sa déclaration et son affectation ?
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Oullaa autant pour moi, stoplist n'a rien à faire là, en fait j'avais prévu de faire une fonction similaire avec des mots non pas à rechercher mais à éviter, les fonctions sont identiques au noms de fichier près... Si j'arrive à faire tourner la première correctement ce ne devrait pas être compliqué de faire de même avec l'autre.

    donc voilà ce que j'ai avec le typedef de str :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    typedef char * str ;
     
    void put_wordslist(str liste)
    {
      FILE *wordslist; 
      int lu, max ;
      char sas[32] ;
     
      wordslist = fopen("fichier.txt", "r") ;
      if (!wordslist)
        usage("fichier mots introuvable !") ;
      for (max = 0; lu != EOF; max++)
      {
        lu = fscanf(wordslist, "%s", sas) ;
        liste[max] = strdup(sas) ;
      }
      fclose(wordslist);
    }
     
    void usage(str message) { fprintf(stderr, "%s\n", message) ; exit(1) ; }

  6. #6
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    Bon, déjà, les grosses incohérences sont retirées

    Le problème est clair maintenant :
    D'après le man de strdup, on voit que...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    char *strdup(const char *str);
    strdup renvoit un char* et non un char !
    Là, il faudrait que tu t'intéresses au malloc/free et aux pointeurs absolument !

    Pour ce que tu souhaites faire, en évitant les mallocs, tu dois utiliser strcpy qui va copier les caractères d'une chaîne vers une autre déjà allouée/tableau statique !

    Donc tu devrais lire le man de strcpy et strncpy !
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    strcpy et strncpy retournent aussi un char *, tout comme strcat.

    Ce que je ne comprend pas c'est pourquoi si je définie un variable de type char * à l'intérieur de la fonction cela fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    typedef char * str ;
     
    void put_wordslist(str liste)
    {
      FILE *wordslist; 
      int lu, max ;
      char sas[32], mots[64] ;
     
      wordslist = fopen("fichier.txt", "r") ;
      if (!wordslist)
        usage("fichier mots introuvable !") ;
      for (max = 0; lu != EOF; max++)
      {
        lu = fscanf(wordslist, "%s", sas) ;
        mots[max] = strdup(sas) ;
      }
      for (x = 0 ; x < max -1; x++)
      {
        printf("%s ", mots[x]) ;
      }
      fclose(wordslist);
    }
     
    void usage(str message) { fprintf(stderr, "%s\n", message) ; exit(1) ; }
    et apparemment mots à la bonne valeur :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    spectre quasar infrarouge
    Mon fichier "mots_à_chercher" contient la même chose, j'en déduit que ça fonctionne.
    Alors qu'avec liste qui est du même type que mots cela ne marche pas.

    p.s. : j'ai tenté d'autres solutions avec strcpy, strncpy et strcat mais pour l'instant rien de glorieux...

  8. #8
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    strdup va allouer avec malloc de l'espace, et mettre dans le char* (un pointeur) l'adresse de l'espace alloué.

    strcpy, il faut lui donner le tableau ou l'adresse de l'espace alloué pour qu'il recopie dedans, le retour de fonction n'est pas "important" pour strcpy et strncpy (contrairement à strdup).

    liste[1], c'est un char
    liste c'est un char[] (mais est aussi considéré comme un char* du coup).

    Essaye cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    strncpy(liste, sas, 32);
    Au lieu de ton strdup.

    EDIT : et précisément strncpy(liste, sas, 32); ! Rien de plus, rien de moins sur la ligne ! Pas de liste = strcpy(liste,sas,32); !
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    C'est en effet ce que j'ai essayé tout à l'heure après avoir suivi ton conseil et jeté un œil au man de strcpy et strncpy.

    J'ai testé avec strncpy(liste, sas, 32) et strncpy(liste, sas, sizeof(liste)) et strcpy(liste, sas) mais j'obtiens toujours "core dumped".

  10. #10
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Citation Envoyé par Self-Mao Voir le message
    [...]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    int readstr(void)
    {	FILE * flux = fopen("mots_à_chercher", "r") ;
    	if (!flux) return 1 ;
    	int lu, max, x ;
    	char *mots[100] ;
    	for (max = 0 ; lu != EOF ; max++)
    	{	char sas[32] ;
    		lu = fscanf(flux, "%s", sas) ;
    		mots[max] = strdup(sas) ; }
    	for (x = 0 ; x < max -1; x++)
    		printf("%s ", mots[x]) ; 
    	printf("\nnombres de mots à chercher : %d\n", x) ;
    	fclose(flux) ; 
    	return 0 ; }
    Je sais bien que cette fonction n'est sûrement pas optimale mais pour l'instant je fais avec ce que je connais, je vais de tuto en tuto et je cherche de l'aide sur les forums mais là je bloque.
    ...
    Bonsoir,
    ce n'est pas que ta fonction n'est pas optimale, elle contient des erreurs.
    Tu cherches de l'aide sur les forums, mais tu ne tiens apparemment pas compte des remarques qui te sont faites.

    Citation Envoyé par kwariz Voir le message
    Citation Envoyé par Self-Mao Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    FILE * fich = fopen(file, "r") ;
    if (!fich) return 1 ;
    int max, lu, nombres[11] ;
    for (max = 0 ; max < 11 && lu != EOF ; max++)
    	lu = fscanf(fich, "%d", & nombres[max]) ;

    Bonsoir,
    déjà tu accèdes à lu sans l'avoir initialisé au premier tour de boucle (ça marche = coup de bol).
    ensuite fscanf ne renvoie pas EOF mais le nombre de conversions réussies. Dans ton cas c'est soit 1 (on a réussi à lire un entier), soit 0 (on a pas réussi).
    Donc au risque de me répéter :
    • Au premier tour de boucle, lu n'est pas initialisé il contient n'importe quoi : c'est un coup de bol que ça fonctionne
    • fscanf ne renvoie pas EOF mais le nombre de conversions réussies : pas de bol, ça ne m'étonne pas que ça ne fonctionne pas trop bien ...

  11. #11
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Merci pour ta réponse kwartz.

    Bah le problème c'est que selon les personnes à qui je demande de l'aide et les forums, on me répond rarement la même chose.

    En effet d'après le man de scanf je voie bien que la fonction retourne un entier mais apparemment ça marche tout de même.
    Il y aurait une alternative à ce test en comparant max aux nombres de mots du fichier mais cela nécessite de connaitre ou de calculer le nombres de mots avant ça.

    Pour le teste j'ai essayé en mettant le nombre de mots du fichier "mots_à_chercher" manuellement mais cela ne suffit apparemment pas à résoudre l'erreur.

  12. #12
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    Haha, c'est vrai que j'ai supposé trop de choses dans son code (dont le "lu" peut être initialisé hors de la fonction.... genre en global => et en plus il ne l'était pas dans le code... je suis resté sur son strdup/strcpy)

    Merci de remonter les autres erreurs !
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  13. #13
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Si l'erreur vient bel et bien de là alors je sèche, j'ai initialisé lu avant la boucle mais cela ne corrige pas l'erreur, au final j'ai toujours ce "core dumpbed".

  14. #14
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Citation Envoyé par Self-Mao Voir le message
    Si l'erreur vient bel et bien de là alors je sèche, j'ai initialisé lu avant la boucle mais cela ne corrige pas l'erreur, au final j'ai toujours ce "core dumpbed".
    Tu dois complètement réécrire ta boucle de lecture. On peut respirer un grand coup et voir les principaux blocs dont tu vas avoir besoin.

    • ouverture du fichier
      là pas de problèmes, tu as bien défini une variable de type FILE* et vérifié le retour de fopen.
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      FILE* flux=fopen(...);
      if (!flux) /* équivalent à (flux==NULL) */
        on quitte l'appli
      ...
      fclose(flux);
    • lecture d'un mot
      Là ça se complique, surtout si on veut couvrir un maximum de cas de figure. La lecture préalable de l'article que Bktero t'a conseillé est indispensable.
      Nous allons donc faire une boucle. La première chose à faire est d'essayer de lire un mot.
      Tu as choisi d'utiliser comme buffer une variable locale de 32 octets nommée sas. Rappel : elle ne pourra donc contenir qu'un mot d'au maximum 31 octets. Je dis bien octets et pas caractères, car suivant l'encodage utilisé un caractère peut faire plus de 1 octet. Par exemple dans ma configuration, "théâtralisé" est un mot de 11 lettres, mais la chaîne a une longueur de 15 octets, car les lettres accentuées utilisent 2 octets et il ne faut pas oublier de comptabiliser le 0 terminal.
      Si tu utilises %s pour décoder une chaine, scanf va lire un maximum de caractères et les mettre dans ton buffer puis rajouter un 0 terminal, tout ça même si ton buffer est trop petit ! Pour sécuriser ça on passe une taille maximum au %s -> il faudra le faire comme indiqué dans l'article. Je me contenterai de placer un commentaire pour le rappeler.
      Ensuite il faut vérifier le code de retour de fscanf. S'il vaut 1 c'est que tout c'est bien passé, car tu n'as demandé qu'une conversion -> uniquement dans ce cas là tu utilises ton buffer pour rajouter le mot que tu viens de lire !
      Dans les autres cas (il renvoie 0 ou EOF) c'est qu'il y a eu un problème ou que la fin de fichier a été rencontrée. Tu ne peux pas le savoir sans utiliser les fonction feof() et ferror().
      Ça donne un code du genre :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      int ok; // un booléen qui indique que l'on peut continuer la lecture
      int erreur; //un booléen pour indiquer une erreur lors de la lecture
      int res; // pour stocker le retour de fscanf
      char buffer[32]; // le buffer de lecture
      do {
        res=fscanf(flux,"%31s", buffer);
        if (res==1) {
          // ici tu fais comme indiqué dans l'article pour vérifier
          // que tu as lu un mot entier et pas que tu as tronqué
          // un mot auquel cas tu peux indiquer à l'utilisateur qu'une
          // entrée a été tronquée
       
          // ici buffer contient un mot tu fais ce que tu veux de lui
          ok=1; // on peut continuer
          erreur=0; // pas d'erreur à signaler
        } else if (res==0) {
          // ici la conversion a échoué, on arrête tout en erreur
          ok=0;
          erreur=1;
        } else {
          // fin de fichier ou erreur lors de l'accès au fichier
          if feof(flux) {
            // ouf ce n'est que la fin du fichier !
            ok=0; // on arrête la lecture
            erreur=0; // mais ce n'est pas une erreur
          } else if (ferror(flux)) {
            // zut ! une erreur d'accès
           ok=0;
           erreur=1;
          } else {
            // là c'est étrange ...
            ok=0;
            erreur=1;
          } /* fin de cas scanf qui renvoie EOF */
        } /* fin du test de retour de scanf */
      } while (ok);
       
      if (erreur) {
        ...
      } else {
        ...
      }


    Le code complet peut paraître lourd et compliqué, c'est vrai. Mais normalement il faudrait toujours tout vérifier, bien qu'en général on ne le fait pas forcément.
    Souvent on se contente de prendre un buffer suffisamment grand en utilisant un %s pour se mettre plus ou moins à l'abri d'un débordement (char buffer[1024]) : c'est mal, mais qui ne l'a jamais fait ? Ça marche dans la majorité des cas et si ce n'est que pour un test ou un exemple ... mais ça reste mal
    En revanche le test de retour de (f)scanf() est indispensable, nécessaire. On ne doit utiliser les buffer lus que si la lecture c'est bien passée !!!
    Il faut aussi se souvenir qu'en général une fonction de la libc qui renvoie EOF ne dit pas qu'une fin de fichier a été atteinte mais qu'il est impossible de lire plus loin. Il est impératif de vérifier avec feof() et ferror() ce qu'il en est et réagir en conséquence.
    Et puis oui, dès qu'on lit un flux c'est 90% de tests pour 10% d'action ... surtout si on veut bien le faire.

    Il va falloir aussi se mettre aux mallocs De toute façon comme strdup en fait pour toi, il faudra que tu libères chaque chaine avec un free tôt ou tard ...

    Si tu veux vraiment savoir pourquoi ton code plante en core dumped (tu dois aussi avoir un message signalant un SIGSEV ou quelque chose dans le genre ...) envoie le en entier pour avoir des explications.

    N'oublie pas non plus de compiler test sources avec les options -Wall -Wextra pour avoir plein d'indications du compilateur. N'oublie pas non plus -g et commence à essayer d'utiliser le débugger (gdb) : c'est hyper pratique quand tu développes (et ce quels que soient le langage, la plateforme, l'environnement, l'âge du capitaine, ...).

  15. #15
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Je te remercie infiniment pour ton ide. Je n'ai pas lu tout ton post car honnêtement le café ne parvient plus à garder mes yeux ouvert. Je me suis documenté sur les fonctions de lecture / écriture, lu quelques tutos sur les pointeurs, je regarde ça demain avec le cerveau rechargé. Et je vous tiens au courant.

    Merci encore à vous pour votre aide !!

  16. #16
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Merci beaucoup pour ce code kwartz, c'est vrai qu'on se sent plus serein quand on sait que toutes les erreurs sont gérer.

    Par contre j'ai bute encore en essayant d'ajouter les mots scannés à ma variable liste, en utilisant un vecteur mots définie à l'intérieur de la fonction ça fonctionne pourtant !!

    Voici mon code basé sur le tien :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    int ok, erreur, res;
    int compteur=0;
    char buffer[32];
    char *mots[128];
     
    do {
      res=fscanf(flux,"%31s", buffer);
      if (res==1) {
        printf("%s ", buffer) ;
    	mots[compteur] = strdup(buffer) ;
    	compteur++ ;
        ok=1;
        erreur=0;
      } else if (res==0) {
        ok=0;
        erreur=1;
      } else {
        if feof(flux) {
          ok=0;
          erreur=0;
        } else if (ferror(flux)) {
         ok=0;
         erreur=1;
        } else {
          ok=0;
          erreur=1;
        }
      }
    } while (ok);
     
    if (erreur) {
      usage("problème de lecteur !");
    } else {
      printf("ok!\n");
    }
     
    fclose(flux");
    le compteur permet de se déplacer dans le vecteur mots.
    Le printf("%s ", buffer) fonctionne correctement car cela affiche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    spectre quasar infrarouge
    (les mots du fichiers "mots_à_rechercher").

    Le mots[compteur] = strdup(buffer) marche aussi, si je demande à afficher chaque élément du vecteur ça affiche la même liste de mots qu'au dessus.

    Par contre si je mets liste à la place de mots, "Erreur de segmentation (core dumped)" !!!!

    Voici comment je déclare le vecteur de caractères que je passe à ma fonction :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #define maximum 128
     
    int main(int argc, const str argv[])
    {
        ...
        str sl[maximum];
        readstr(*sl);
        ...
    }
    Je m'y prend mal, c'est certain, mais où ? Est-ce lorsque je passe la liste à la fonction readstr() ? Ou bien à l'intérieur de cette fonction ?

    Ne serait-il pas plus simple de passer une variable de type char plutôt que char * à readstr() ? La fonction n'aurait-plus qu'à augmenter la variable avec chaque mot lus. Ensuite je pourrais toujours utiliser strtok pour splitter la variable...

    Voilà ce que j'ai fait :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    #define maximum 128
    
    int main(int argc, const str argv[])
    {
        ...
        char sl[maximum];
        readstr(sl);
        ...
    }
    
    str readstr(str liste)
    {
        int ok, erreur, res;
        int compteur=0;
        char buffer[32];
        char *mots[128];
    
    	do {
    	  res=fscanf(flux,"%31s", buffer);
    	  if (res==1) {
    		printf("%s ", buffer) ;
    		strcat(liste, strdup(sas)) ;
    		strcat(liste, " ") ; // pour l'espace entre les mots...
    		compteur++ ;
    		ok=1;
    		erreur=0;
    	  } else if (res==0) {
    		ok=0;
    		erreur=1;
    	  } else {
    		if feof(flux) {
    		  ok=0;
    		  erreur=0;
    		} else if (ferror(flux)) {
    		 ok=0;
    		 erreur=1;
    		} else {
    		  ok=0;
    		  erreur=1;
    		}
    	  }
    	} while (ok);
    	 
    	if (erreur) {
    	  usage("problème de lecteur !");
    	} else {
    	  printf("ok!\n");
    	}
    
    	printf("%s \n", liste);
    
    	fclose(flux");
    }

    et ça me retourne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    spectre quasar infrarouge // résultat de printf sas dans la boucle
    ok!
    spectre quasar infrarouge     // résultats de printf liste
    Est-ce que c'est mieux, pas conseillé ou autre ? Car en passant une variable de type char * je n'y arrive pas du tout, pas moyen que ça marche correctement.

  17. #17
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    Attention !

    liste est de type str, donc char*.
    mots est de type char[xx]*, donc un char** !

    Dire à liste[x] de recevoir strdup, c'est dire à strdup d'écrire dans un char !
    Dire à mots[x] de recevoir strdup, c'est dire à strdup d'écrire dans un char*, donc ça passe...
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

  18. #18
    Membre averti
    Profil pro
    Inscrit en
    Avril 2013
    Messages
    21
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2013
    Messages : 21
    Par défaut
    Donc ça passe ?

    Excuse-moi metalman, je n'ai pas trop compris le sens de ton message par rapport à ma fonction ?

    Est-ce préférable de déclarer sl de type char ou char* ? Et pour liste ?

  19. #19
    Membre Expert
    Avatar de kwariz
    Homme Profil pro
    Chef de projet en SSII
    Inscrit en
    Octobre 2011
    Messages
    898
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Chef de projet en SSII
    Secteur : Conseil

    Informations forums :
    Inscription : Octobre 2011
    Messages : 898
    Par défaut
    Il faudrait voir ou revoir quelques tuto ou exemples sur différents points.
    • les mécanismes des passages de paramètres
    • les différences entre pointeurs, tableaux, ce qui est pointé, ... comment choisir la structure de données appropriée
    • important : l'allocation dynamique de la mémoire (il ne faut surtout pas en avoir peur)

      Par exemple dans le morceau de code que tu donnes (j'oublie ton typedef) :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      #define maximum 128
       
      int main(int argc, const str argv[])
      {
          ...
          char sl[maximum];
          readstr(*sl);
          ...
      }
      Une allocation dynamique pourrait être :
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      #define maximum 128
       
      int main(int argc, const char* argv[])
      {
          ...
          char **sl
          sl = malloc( maximum * sizeof(*sl) );
       
          readstr(*sl);
          ...
          free(sl);
      }
      L'avantage de l'allocation dynamique est ... d'être dynamique La taille allouée n'a plus besoin d'être connue lors de la compilation mais peut être non seulement déterminée à l'exécution mais également modifiée (on peut «rajouter» ou «enlever» de la place).
      De plus ta mémoire est divisée en deux grandes zones (pour rester simple) : la pile et le tas. La pile est une ressource très limitée (par exemple pas plus de 8Mo de disponible pour toute l'exécution du programme) alors que le tas est là où tu as le plus de place (suivant ta RAM, ton swap, par ces temps-ci ça se compte en Go).
      L'allocation dynamique s'effectue sur le tas, l'allocation de toute tes variables locales sur la pile -> avantage allocation dynamique pour les grosses structures.
      Le «désavantage» : c'est toi qui gère la mémoire et pour éviter les fuites il faut penser à libérer la mémoire allouée ...

  20. #20
    Membre Expert
    Avatar de Metalman
    Homme Profil pro
    Enseignant-Chercheur
    Inscrit en
    Juin 2005
    Messages
    1 049
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 36
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Enseignant-Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 049
    Par défaut
    Kwariz a parfaitement tout résumé !
    Suis ses conseils, et tout devrait te paraitre évident après cela !
    --
    Metalman !

    Attendez 5 mins après mes posts... les EDIT vont vite avec moi...
    Les flags de la vie : gcc -W -Wall -Werror -ansi -pedantic mes_sources.c
    gcc -Wall -Wextra -Werror -std=c99 -pedantic mes_sources.c
    (ANSI retire quelques fonctions comme strdup...)
    L'outil de la vie : valgrind --show-reachable=yes --leak-check=full ./mon_programme
    Et s'assurer que la logique est bonne "aussi" !

    Ma page Developpez.net

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 22/05/2006, 11h27
  2. Réponses: 15
    Dernier message: 15/12/2005, 14h36
  3. Réponses: 2
    Dernier message: 06/12/2005, 12h01
  4. besoin d'aide fonction avec fichier (debutant)
    Par boby61 dans le forum Débuter
    Réponses: 9
    Dernier message: 14/03/2005, 11h22
  5. appeler une fonction connaissant son nom (en string)
    Par Guigui_ dans le forum Général Python
    Réponses: 1
    Dernier message: 20/07/2004, 00h46

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo