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 :

Lire une cha�ne de caract�res de taille variable sur stdin


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    23
    D�tails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 23
    Par d�faut Lire une cha�ne de caract�res de taille variable sur stdin
    Bonjour tout le monde,

    Tout � coup j'ai eu une subite envie de faire une petite fonction permettant de lire une cha�nes de caract�res de taille variable sur stdin (et plus g�n�ralement, sur un FILE *).
    Le comportement de la fonction est le suivant :
    - La fonction prend un param�tre, le flux (FILE *) sur lequel la cha�ne de caract�res sera lue
    - La fonction retournera un char *, l'adresse du premier caract�re lu ou NULL si une erreur survient
    - Si une erreur survient, le flux sera consomm� (= lecture des caract�res juqu'� ce qu'on tombe sur \n ou EOF)
    La signature de la fonction sera donc la suivante : char * get_line(FILE *);

    N'ayant pas trouv� grand chose sur la lecture de cha�nes de caract�res de taille variable, j'ai du faire chauffer mes m�ninges et trouver un algorithme, esp�rons qu'il soit potable.
    Ne sachant pas trop comment �crire cela en pseudo-code, je vais le faire avec de bonnes vieilles phrases.
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*
    D'abord on va allouer un espace mémoire de taille arbitraire (32 octets) pouvant stocker des char.
    Si l'allocation a réussie, on va pouvoir lire le flux caractère par caractère.
        Tant qu'on ne rencontre pas \n ou EOF :
             Si l'espace alloué n'est pas suffisant, on va augmenter la taille de l'espace précédemment alloué (+ 32 octets).
             Si l'allocation a échouée, on va libérer l'espace précédemment alloué, consommer le flux et sortir de la boucle.
    S'il n'y a pas eu d'erreur d'allocation, on rajoute le \0 à la chaîne de caractères.
    On retourne un pointeur sur le premier élément de l'espace alloué ou NULL s'il y a eu une erreur d'allocation.
    */
    Premi�re question, est-ce que cet algorithme semble correct, potable ?
    Pour la r�allocation, j'ai vu certains codes qui doublaient la taille de l'espace allou� au lieu de l'agrandir d'un nombre fixe d'octets. Y a-t-il une m�thode pr�f�rable � l'autre, ou est-ce d�pendant de la situation ? Et si c'est d�pendant de la situation, quelle m�thode r�pondrait le mieux � la probl�matique actuelle ?

    Passons maintenant � l'impl�mentation en C :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /* /Document/C/str/mstr.h */
    #ifndef MSTR_H_INCLUDED
    #define MSTR_H_INCLUDED
     
    #include <stdlib.h>
    #include <stdio.h>
     
    #define MSTR_ALLOC_BLOCK_SIZE 32
     
    char * get_line(FILE *);
     
    #endif /* MSTR_H_INCLUDED */
    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
    /* /Document/C/str/mstr.c */
    #include "mstr.h"
     
    char * get_line(FILE * stream) {
        /* Allocation du bloc de depart */
        size_t size = MSTR_ALLOC_BLOCK_SIZE;
        char * s = malloc(size);
     
        /* Si l'allocation a reussie */
        if(s != NULL) {
            size_t i;
            int c;
     
            /* On lit tous les caractères jusqu'a \n ou EOF */
            for(i = 0; (c = fgetc(stream)) != '\n' && c != EOF; i++) {
                /* Si l'espace alloue n'est plus suffisant
                   on essaie de l'agrandir */
                if(i >= size) {
                    char * tmp = realloc(s, size += MSTR_ALLOC_BLOCK_SIZE);
     
                    /* Si l'allocation a reussie, on recupere le pointeur
                       Sinon on libere l'espace precedemment alloue,
                       on vide le buffer du flux et on sort du while */
                    if(tmp != NULL) {
                        s = tmp;
                    }
                    else {
                        free(s);
                        s = NULL;
                        while((c = fgetc(stream)) != '\n' && c != EOF) {
                        }
                        break;
                    }
                }
                s[i] = (char)c;
            }
            /* On ajoute le \0 terminal a la chaine recuperee */
            if(s != NULL) {
                s[i] = '\0';
            }
        }
     
        return s;
    }
    Qu'en pensez-vous ?
    Le code semble fonctionner. Semble car j'avoue avoir un peu de mal pour les tests unitaires.. Est-il possible de faire �chouer volontairement un malloc/realloc ?

    Derni�re petite chose, j'ai eu beau lutter, un warning persiste � la compilation.. J'utilise code::block avec les options de compilations suivantes (GNU/CSS compiler) : -Wall -Wextra -ansi -O -Wwrite-strings -Wstrict-prototypes -Wuninitialized -Wunreachable-code


    Et voici le warning en question :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    /*
    \Documents\C\str\mstr.c||In function `get_line':|
    \Documents\C\str\mstr.c|10|warning: will never be executed|
    ||=== Build finished: 0 errors, 1 warnings ===|
    */
    J'ai demand� � une connaissance de compiler, il a utilis� le m�me compilateur (mais je ne sais pas si c'est la m�me version par contre) avec les m�mes options, et point de warning chez lui.

    Merci d'avoir pris le temps de me lire et merci d'avance pour vos futures r�ponses. =)

    Cordialement, Krystal_.

  2. #2
    R�dacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par d�faut
    Citation Envoy� par Krystal_ Voir le message
    Premi�re question, est-ce que cet algorithme semble correct, potable ?
    Peut �tre perfectible, mais �a semble r�pondre � ton probl�me.
    Citation Envoy� par Krystal_ Voir le message
    Pour la r�allocation, j'ai vu certains codes qui doublaient la taille de l'espace allou� au lieu de l'agrandir d'un nombre fixe d'octets. Y a-t-il une m�thode pr�f�rable � l'autre, ou est-ce d�pendant de la situation ?
    C'est d�pendant de la situation. D'autres m�thodes diminuent l'espace suppl�mentaire allou� en se basant sur l'heuristique que plus on avance, plus on est pr�t d'arriver.
    Citation Envoy� par Krystal_ Voir le message
    Et si c'est d�pendant de la situation, quelle m�thode r�pondrait le mieux � la probl�matique actuelle ?
    Ta solution, car dans le pire des cas tu risque de doubler la taille de ton buffer pour 1 octet (et d'avoir le risque d'un �chec de r�allocation).

    Citation Envoy� par Krystal_ Voir le message
    Passons maintenant � l'impl�mentation en C :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    /* /Document/C/str/mstr.h */
    #ifndef MSTR_H_INCLUDED
    #define MSTR_H_INCLUDED
     
    #include <stdlib.h>
    #include <stdio.h>
    En g�n�ral, on �vite les includes dans les .h.

    Citation Envoy� par Krystal_ Voir le message
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    /* /Document/C/str/mstr.c */
           for(i = 0; (c = fgetc(stream)) != '\n' && c != EOF; i++) {
    Attention EOF peut aussi signifier une erreur de lecture (http://www.cplusplus.com/reference/c...dio/fgetc.html).
    Citation Envoy� par Krystal_ Voir le message
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
                       /*Sinon on libere l'espace precedemment alloue,
                       on vide le buffer du flux et on sort du while */
                    else {
                        free(s);
                        s = NULL;
                        while((c = fgetc(stream)) != '\n' && c != EOF) {
                        }
                        break;
                    }
    Pourquoi?
    Citation Envoy� par Krystal_ Voir le message
    Le code semble fonctionner. Semble car j'avoue avoir un peu de mal pour les tests unitaires.. Est-il possible de faire �chouer volontairement un malloc/realloc ?
    Pour les testsU tu dois r��crire les fonctions que tu appelle pour justement pouvoir en contr�ler le r�sultat.
    Le moteur de testU est ind�pendant de ton appli et se content d'appeler ta fonction.

    Citation Envoy� par Krystal_ Voir le message
    Derni�re petite chose, j'ai eu beau lutter, un warning persiste � la compilation.. J'utilise code::block avec les options de compilations suivantes (GNU/CSS compiler) : -Wall -Wextra -ansi -O -Wwrite-strings -Wstrict-prototypes -Wuninitialized -Wunreachable-code


    Et voici le warning en question :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    /*
    \Documents\C\str\mstr.c||In function `get_line':|
    \Documents\C\str\mstr.c|10|warning: will never be executed|
    ||=== Build finished: 0 errors, 1 warnings ===|
    */
    J'ai pas de r�ponse assur�e. La seule certitude c'est que c'est li� � -Wunreachable-code. Mais, �a n'explique pas tout. Je dirais qu'il consid�re size_t i; comme une instruction alors que �a n'est qu'une d�claration de variable. D'ailleurs, si tu mets size_t i = 0; ton warning disparait.

  3. #3
    Expert �minent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retrait�
    Inscrit en
    D�cembre 2003
    Messages
    14 512
    D�tails du profil
    Informations personnelles :
    �ge : 68
    Localisation : France, Paris (�le de France)

    Informations professionnelles :
    Activit� : Retrait�

    Informations forums :
    Inscription : D�cembre 2003
    Messages : 14 512
    Par d�faut
    Citation Envoy� par Krystal_ Voir le message
    Et voici le warning en question :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    /*
    \Documents\C\str\mstr.c||In function `get_line':|
    \Documents\C\str\mstr.c|10|warning: will never be executed|
    ||=== Build finished: 0 errors, 1 warnings ===|
    */
    J'ai demand� � une connaissance de compiler, il a utilis� le m�me compilateur (mais je ne sais pas si c'est la m�me version par contre) avec les m�mes options, et point de warning chez lui.

    Merci d'avoir pris le temps de me lire et merci d'avance pour vos futures r�ponses. =)

    Cordialement, Krystal_.
    Ce warning est probablement du � l'optimiseur. Pas grave.

    Par contre :

    - Le nom de la fonction devrait �tre fget_line() pour �tre coh�rent :
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
     
    void *fget_line(FILE *fp);
     
    #define get_line() fget_line (stdin)
    - <stdlib.h> n'a rien � faire dans "mstr.h"

    - la d�finition de MSTR_ALLOC_BLOCK_SIZE n'a rien � faire dans "mstr.h"

    -Boucle infinie lors d'un test basique :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #include "mstr.h"
     
    int main (void)
    {
       FILE *fp = fopen ("in.txt", "r");
     
       if (fp != NULL)
       {
          char *line;
          while ((line = fget_line (fp)) != NULL)
          {
             printf ("'%s'\n", line);
             free (line);
          }
          fclose (fp);
       }
       return 0;
    }
    avec
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
     
     
    a
    ab
    a b
    abcdefghijklmnopqrstuvwxyz
    cast inutile.

    J'ai int�gr� tes derni�res modifs. Ceci fonctionne :

    http://delahaye.emmanuel.free.fr/forums/Krystal_

  4. #4
    Expert �minent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retrait�
    Inscrit en
    D�cembre 2003
    Messages
    14 512
    D�tails du profil
    Informations personnelles :
    �ge : 68
    Localisation : France, Paris (�le de France)

    Informations professionnelles :
    Activit� : Retrait�

    Informations forums :
    Inscription : D�cembre 2003
    Messages : 14 512
    Par d�faut
    Citation Envoy� par 3DArchi Voir le message
    En g�n�ral, on �vite les includes dans les .h.
    Absurde. La vraie r�gle de bon sens est "on met ce qui est n�cessaire et suffisant". Ici,
    • <stdio.h> est n�cessaire pour FILE
    • <stdlib.h> est inutile
    • la macro est inutile

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    23
    D�tails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 23
    Par d�faut
    Citation Envoy� par 3DArchi Voir le message
    Peut �tre perfectible, mais �a semble r�pondre � ton probl�me.
    Aurais-tu des pistes/id�es pour l'am�liorer ?

    Citation Envoy� par 3DArchi Voir le message
    En effet, oubli de ma part.

    Citation Envoy� par 3DArchi Voir le message
    Pourquoi?
    C'est le comportement souhait�.
    Soit tout se passe bien et on retourne la cha�ne, soit quelque chose se passe mal (allocation, erreur de lecture) et on consomme le flux, on lib�re l'espace alou� et on retourne NULL.

    Citation Envoy� par Emmanuel Delahaye Voir le message
    -Boucle infinie lors d'un test basique :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    #include "mstr.h"
     
    int main (void)
    {
       FILE *fp = fopen ("in.txt", "r");
     
       if (fp != NULL)
       {
          char *line;
          while ((line = fget_line (fp)) != NULL)
          {
             printf ("'%s'\n", line);
             free (line);
          }
          fclose (fp);
       }
       return 0;
    }
    avec
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
     
     
    a
    ab
    a b
    abcdefghijklmnopqrstuvwxyz
    En effet, je n'avais pas pr�vu le cas ou fgetc() retournerait EOF d�s son premier appel.

    Citation Envoy� par Emmanuel Delahaye Voir le message
    J'ai int�gr� tes derni�res modifs. Ceci fonctionne :

    http://delahaye.emmanuel.free.fr/forums/Krystal_
    Merci bien. Mais si la ligne qu'on est en train de lire ne se termine pas par \n, elle est zapp�e. Ce choix n'est-il pas un peu dangereux si on lit des fichiers �dit� avec des logiciels comme le bloc note de Windows ?
    Aussi, par rapport � la r�allocation, pourquoi privil�gier une multiplication par deux de l'espace allou� ?

  6. #6
    R�dacteur
    Avatar de Franck.H
    Homme Profil pro
    D�veloppeur .NET
    Inscrit en
    Janvier 2004
    Messages
    6 951
    D�tails du profil
    Informations personnelles :
    Sexe : Homme
    �ge : 48
    Localisation : France, Haut Rhin (Alsace)

    Informations professionnelles :
    Activit� : D�veloppeur .NET
    Secteur : Service public

    Informations forums :
    Inscription : Janvier 2004
    Messages : 6 951
    Par d�faut
    Citation Envoy� par Krystal_ Voir le message
    N'ayant pas trouv� grand chose sur la lecture de cha�nes de caract�res de taille variable, j'ai du faire chauffer mes m�ninges et trouver un algorithme, esp�rons qu'il soit potable.
    Ne sachant pas trop comment �crire cela en pseudo-code, je vais le faire avec de bonnes vieilles phrases.
    Code : S�lectionner tout - Visualiser dans une fen�tre � part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    /*
    D'abord on va allouer un espace mémoire de taille arbitraire (32 octets) pouvant stocker des char.
    Si l'allocation a réussie, on va pouvoir lire le flux caractère par caractère.
        Tant qu'on ne rencontre pas \n ou EOF :
             Si l'espace alloué n'est pas suffisant, on va augmenter la taille de l'espace précédemment alloué (+ 32 octets).
             Si l'allocation a échouée, on va libérer l'espace précédemment alloué, consommer le flux et sortir de la boucle.
    S'il n'y a pas eu d'erreur d'allocation, on rajoute le \0 à la chaîne de caractères.
    On retourne un pointeur sur le premier élément de l'espace alloué ou NULL s'il y a eu une erreur d'allocation.
    */
    Tu peux �ventuellement utiliser l'allocation par Progression g�om�trique cependant, avec cette m�thode tu risque d'avoir un peu plus d'allocation, la r�gle simplifi�e de cette m�thode:
    new_size = old_size + old_size / 2
    Le lien vers le document PDF de Jean-Marc.Bourguet sur la formule compl�te et d�taill�e (si t'es tr�s bon en maths ): http://www.bourguet.org/realloc.pdf

    Je l'ai d�j� utilis�e et je peut dire que c'est tr�s pratique mais tu auras surement plus de demandes d'allocation que d'allouer en taille fixe !
    Mon Site
    Ma biblioth�que de gestion des cha�nes de caract�res en C

    L'imagination est plus importante que le savoir. A. Einstein

    Je ne r�pond � aucune question technique par MP, merci d'avance !

  7. #7
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    23
    D�tails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 23
    Par d�faut
    J'ai donc le choix entre :
    - Beaucoup d'allocation mais peu d'espace perdu (taille += taille / 2)
    - Peu d'allocation mais beaucoup d'espace perdu (taille *= 2)
    - Nombre moyen d'allocation et quantit� moyenne d'espace perdu (taille += BLOC_SIZE)

    La possibilit� de choisir est une vraie torture quand on n'a pas les informations requises pour faire ce choix. J'aurais tendance � choisir la troisi�me m�thode, puisque, de mon point de vue, elle n'est jamais la plus mauvaise. Mais elle n'est jamais la meilleure non plus..

    �videmment, il y a peut-�tre des subtilit�s sur l'allocation dont je n'ai pas connaissance.

    Merci pour le pdf, mais je ne vois pas comment il passe de la premi�re ligne de son in�quation � la seconde. La suite �a va par contre.

    Edit : pour le fun, et parce que �a permet de v�rifier qu'on a bien compris/retenu les choses, j'ai refait le code de mstr.c.
    J'en ai profit� pour permettre de ne pas devoir terminer la derni�re ligne par \n.
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    #include <stdlib.h>
     
    #include "mstr.h"
     
    #define ALLOC_BLOCK_SIZE 32
     
    static void fclean(FILE * stream) {
        int c;
     
        while((c = fgetc(stream)) != '\n' && c != EOF) {
        }
    }
     
    char * fget_line(FILE * stream) {
        size_t size = ALLOC_BLOCK_SIZE;
        char * s = malloc(size);
     
        /* si l'allocation s'est bien passee */
        if(s != NULL) {
            int c;
            size_t i = 0;
     
            /* s'il n'y a pas de caracteres dans le flux, on termine tout */
            if((c = fgetc(stream)) == EOF) {
                free(s), s = NULL;
                fclean(stream);
            }
            /* s'il y a des caracteres dans le flux on le lit */
            else {
                do {
                    /* si l'espace alloue n'est plus suffiant, on realloue */
                    if(i == size - 1) {
                        char * tmp = realloc(s, size + ALLOC_BLOCK_SIZE);
     
                        /* s'il y a eu erreur d'allocation,
                           on libere l'espace precedemment alloue,
                           on vide le flux et on retourne NULL */
                        if(tmp != NULL) {
                            s = tmp;
                            size += ALLOC_BLOCK_SIZE;
                        }
                        else {
                            free(s), s = NULL;
                            fclean(stream);
                        }
                    }
     
                    s[i] = c;
                    i++;
                } while((c = fgetc(stream)) != '\n' && c != EOF);
            }
            /* s'il y a eu une erreur de lecture,
               on libere l'espace precedemment alloue,
               on vide le buffer et on retourne NULL */
            if(ferror(stream) != 0) {
                free(s), s = NULL;
                fclean(stream);
            }
            /* s'il n'y a pas eu d'erreur de lecture/allocation,
               on rajoute le \0 terminal */
            if(s != NULL) {
                s[i] = '\0';
            }
        }
     
        return s;
    }

  8. #8
    Inactif  

    Profil pro
    Inscrit en
    D�cembre 2002
    Messages
    534
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : D�cembre 2002
    Messages : 534
    Par d�faut
    Salut,

    Mais cette fameuse construction rend tout aussi bien de la saisie au clavier comme de la lecture des fichiers ?

  9. #9
    Expert �minent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retrait�
    Inscrit en
    D�cembre 2003
    Messages
    14 512
    D�tails du profil
    Informations personnelles :
    �ge : 68
    Localisation : France, Paris (�le de France)

    Informations professionnelles :
    Activit� : Retrait�

    Informations forums :
    Inscription : D�cembre 2003
    Messages : 14 512
    Par d�faut
    Citation Envoy� par dj.motte Voir le message
    Salut,

    Mais cette fameuse construction rend tout aussi bien de la saisie au clavier comme de la lecture des fichiers ?
    Oui. Il suffit de passer stdin en param�tre. C'est un scoop ?

  10. #10
    R�dacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par d�faut
    Citation Envoy� par Krystal_ Voir le message
    J'ai donc le choix entre :
    - Beaucoup d'allocation mais peu d'espace perdu (taille += taille / 2)
    - Peu d'allocation mais beaucoup d'espace perdu (taille *= 2)
    - Nombre moyen d'allocation et quantit� moyenne d'espace perdu (taille += BLOC_SIZE)

    La possibilit� de choisir est une vraie torture quand on n'a pas les informations requises pour faire ce choix. J'aurais tendance � choisir la troisi�me m�thode, puisque, de mon point de vue, elle n'est jamais la plus mauvaise. Mais elle n'est jamais la meilleure non plus..
    L� il faut sortir du C pour regarder l'utilisation de ta fonction. Dans 80% des cas tu auras:
    1/ des donn�es de BLOC_SIZE +-20% -> taille += taille / 2
    2/ des donn�es < BLOC_SIZE -> taille += taille / 2
    3/ des donn�es < BLOC_SIZE mais quand c'est plus grand c'est vraiment plus grand: taille *= 2 ou taille += BLOC_SIZE
    ...
    En fait, il faut utiliser l'environnement m�tier pour d�terminer quel choix est le plus pertinent dans ton cas r�el d'utilisation.

    Le choix des noms de tes fonctions: fget_line, fclean. Ca ressemble � des fonctions standards. Ca peut �tre perturbant. Moi, je pr�f�re MSTR_fget_line et MSTR_fclean, par exemple. On voit tout de suite qu'il s'agit d'une fonction de ton module.

    Tu fais, en gros, if(fin ou erreur) alors ... else do ... while(!fin et !erreur). Normalement tu peux reformuler en while(!fin et !erreur)... Ca devrait suffire.

    Qqs commentaires mineurs dans le code:
    Citation Envoy� par Krystal_ 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
    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
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    #include <stdlib.h>
    
    #include "mstr.h"
    
    #define ALLOC_BLOCK_SIZE 32
    
    static void fclean(FILE * stream) {
        int c;
    
        while((c = fgetc(stream)) != '\n' && c != EOF) {
        }
    }
    
    char * fget_line(FILE * stream) {
        size_t size = ALLOC_BLOCK_SIZE;
        char * s = malloc(size);
    
        /* si l'allocation s'est bien passee */
        if(s != NULL) {
            int c;
            size_t i = 0;
    
            /* s'il n'y a pas de caracteres dans le flux, on termine tout */
            if((c = fgetc(stream)) == EOF) {
                free(s), s = NULL;
                fclean(stream);
            }
            /* s'il y a des caracteres dans le flux on le lit */
            else {
                do {
                    /* si l'espace alloue n'est plus suffiant, on realloue */
                    if(i == size - 1) {
    /* Moi, je pr�f�re souvent des i >= size - 1, mais c'est un choix perso (>= sera plus souvent v�rifi� que ==) */
                        char * tmp = realloc(s, size + ALLOC_BLOCK_SIZE);
    
                        /* s'il y a eu erreur d'allocation,
                           on libere l'espace precedemment alloue,
                           on vide le flux et on retourne NULL */
                        if(tmp != NULL) {
                            s = tmp;
                            size += ALLOC_BLOCK_SIZE;
                        }
                        else {
                            free(s), s = NULL;
    /*Le ',' est une faute de frappe? Pr�f�re le ';': free(s); s = NULL;*/
                            fclean(stream);
                        }
                    }
    
                    s[i] = c;
                    i++;
                } while((c = fgetc(stream)) != '\n' && c != EOF);
            }
            /* s'il y a eu une erreur de lecture,
               on libere l'espace precedemment alloue,
               on vide le buffer et on retourne NULL */
            if(ferror(stream) != 0) {
                free(s), s = NULL;
                fclean(stream);
            }
            /* s'il n'y a pas eu d'erreur de lecture/allocation,
               on rajoute le \0 terminal */
            if(s != NULL) {
                s[i] = '\0';
            }
        }
    
        return s;
    }
    PS/HS:
    Citation Envoy� par Emmanuel Delahaye
    Absurde.
    C'est vrai, �a fait de beaux graphes d'inclusion.

  11. #11
    Expert �minent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retrait�
    Inscrit en
    D�cembre 2003
    Messages
    14 512
    D�tails du profil
    Informations personnelles :
    �ge : 68
    Localisation : France, Paris (�le de France)

    Informations professionnelles :
    Activit� : Retrait�

    Informations forums :
    Inscription : D�cembre 2003
    Messages : 14 512
    Par d�faut
    Citation Envoy� par 3DArchi Voir le message
    Le choix des noms de tes fonctions: fget_line, fclean. Ca ressemble � des fonctions standards. Ca peut �tre perturbant. Moi, je pr�f�re MSTR_fget_line et MSTR_fclean, par exemple. On voit tout de suite qu'il s'agit d'une fonction de ton module.
    +1

  12. #12
    Inactif  

    Profil pro
    Inscrit en
    D�cembre 2002
    Messages
    534
    D�tails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : D�cembre 2002
    Messages : 534
    Par d�faut
    Salut,

    Personnellement je ne me servirais jamais d'une telle fonction pour lire un fichier. Pour stdin � la rigueur, sans plus.

    C'est le truc ressass� depuis l'antiquit�, mais la subtilit� r�side dans le nom de la fonction. Faut-il dire fget_line ou my_get_fline, ou encore get_the_fline ? Personne n'aurait la subtilit� de l'appeler alonso_la_linea...

    Enfin cette fonction ne permet pas de quantifier ce que l'on lit dans le flux. Pour un fichier on peut ne souhaiter lire que les 150 premiers octets par exemple

  13. #13
    Expert �minent
    Avatar de Emmanuel Delahaye
    Profil pro
    Retrait�
    Inscrit en
    D�cembre 2003
    Messages
    14 512
    D�tails du profil
    Informations personnelles :
    �ge : 68
    Localisation : France, Paris (�le de France)

    Informations professionnelles :
    Activit� : Retrait�

    Informations forums :
    Inscription : D�cembre 2003
    Messages : 14 512
    Par d�faut
    Citation Envoy� par dj.motte Voir le message
    Personnellement je ne me servirais jamais d'une telle fonction pour lire un fichier. Pour stdin � la rigueur, sans plus.
    Bah, je fais �a tous les jours, je ne vois pas le probl�me. C'est tr�s pratique... de plus, ce n'est qu'une version de plus du tr�s GNU getline()...
    Enfin cette fonction ne permet pas de quantifier ce que l'on lit dans le flux. Pour un fichier on peut ne souhaiter lire que les 150 premiers octets par exemple
    Pour �a, on a d�j� fread(), voire fgets(), tout d�pend du besoin r�el...

    L'int�r�t de fget_line() ou MSTR_fget_line() est de lire une ligne quelque soit sa taille. Point. Rien de compliqu� ou de magique. En tout cas, il n'y a pas lieu de pol�miquer...

  14. #14
    Membre averti
    Profil pro
    Inscrit en
    Septembre 2008
    Messages
    23
    D�tails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2008
    Messages : 23
    Par d�faut
    Citation Envoy� par 3DArchi Voir le message
    L� il faut sortir du C pour regarder l'utilisation de ta fonction. Dans 80% des cas tu auras:
    1/ des donn�es de BLOC_SIZE +-20% -> taille += taille / 2
    2/ des donn�es < BLOC_SIZE -> taille += taille / 2
    3/ des donn�es < BLOC_SIZE mais quand c'est plus grand c'est vraiment plus grand: taille *= 2 ou taille += BLOC_SIZE
    ...
    En fait, il faut utiliser l'environnement m�tier pour d�terminer quel choix est le plus pertinent dans ton cas r�el d'utilisation.
    C'est bien ce que je pensais, je verrai donc cela.

    Citation Envoy� par 3DArchi Voir le message
    Le choix des noms de tes fonctions: fget_line, fclean. Ca ressemble � des fonctions standards. Ca peut �tre perturbant. Moi, je pr�f�re MSTR_fget_line et MSTR_fclean, par exemple. On voit tout de suite qu'il s'agit d'une fonction de ton module.
    C'est une id�e, je vote pour !

    Citation Envoy� par 3DArchi Voir le message
    Tu fais, en gros, if(fin ou erreur) alors ... else do ... while(!fin et !erreur). Normalement tu peux reformuler en while(!fin et !erreur)... Ca devrait suffire.
    Je pr�f�re if() + do while() � while() dans ce cas-ci, le code me semble bien plus intuitif et facile � lire.
    Et aussi, �a �vite de devoir �valuer plusieurs fois ce qui n'a besoin que d'�tre �valu� qu'une seule fois, m�me si je doute que �a change vraiment quelque chose au niveau du temps d'ex�cution.

    Citation Envoy� par 3DArchi Voir le message
    /*Le ',' est une faute de frappe? Pr�f�re le ';': free(s); s = NULL;*/
    Hm non, ce n'est pas une faute de frappe. J'avais vu cela dans le code d'Emmanuel, et je trouvais cette �criture assez s�duisante.

Discussions similaires

  1. R�ponses: 3
    Dernier message: 09/02/2009, 17h46
  2. Lire une cha�ne de caract�res dans le corps de page
    Par bronon dans le forum G�n�ral JavaScript
    R�ponses: 4
    Dernier message: 19/11/2007, 10h11
  3. R�ponses: 1
    Dernier message: 30/04/2007, 15h33
  4. Taille d'affichage r�el d'une cha�ne de caract�res
    Par SheikYerbouti dans le forum AWT/Swing
    R�ponses: 5
    Dernier message: 21/02/2007, 17h46
  5. [SAX] Lire une cha�ne de caract�res comme un XML
    Par Le Furet dans le forum Format d'�change (XML, JSON...)
    R�ponses: 2
    Dernier message: 23/01/2006, 08h57

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