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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  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 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 ...

  8. #8
    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.

  9. #9
    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

  10. #10
    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".

  11. #11
    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, ...).

+ 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