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 :

Saisie de caractères "illimitée"


Sujet :

C

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éclairé
    Avatar de odsen.s
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2006
    Messages
    269
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2006
    Messages : 269
    Par défaut Saisie de caractères "illimitée"
    Bonjour à tous,

    J'ai essayé de faire un programme permettant une saisie de caractère "illimitée" sur l'entrée standard.
    Le comportement me paraît bon, mais je tenais quand même à vous montrer le code pour voir si je n'avais pas commis une bourde (je n'ai pas l'habitude d'utiliser realloc()).

    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
    #include <stdio.h>
    #include <stdlib.h>
     
    int main(void)
    {
       size_t size = 2;
       char *s = malloc (size);
     
       if(s != NULL)
       {
          int c;
          int fin = 0;
          size_t i = 0;
          while((c = getchar()) != '\n' && c != EOF && !fin)
          {
             if(i >= size-1)
             {
                size *= 1.5;
                char *p_tmp = realloc(s, size);
     
                if(p_tmp != NULL)
                {
                   s = p_tmp;
                   s[i++] = c;
                }
                else
                {
                   fin = 1;
                }
             }
             else
             {
                s[i++] = c;
             }
          }
     
          s[i] = '\0';
          printf("saisie : %s\n", s);
       }
       else
       {
          printf("erreur d'allocation memoire\n");
       }
     
       return 0;
    }
    Voyez-vous des corrections à effectuer ?
    Par avance, merci.

  2. #2
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Je remarque que la taille du buffer croit de manière exponentielle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     size *= 1.5;
                char *p_tmp = realloc(s, size);
    Ne vaudrait-il pas mieux quelque chose de plus progressif (par exemple une croissance arithmétique) ?
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  3. #3
    Membre éclairé
    Avatar de odsen.s
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2006
    Messages
    269
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2006
    Messages : 269
    Par défaut
    Citation Envoyé par Zavonen
    Je remarque que la taille du buffer croit de manière exponentielle:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     size *= 1.5;
                char *p_tmp = realloc(s, size);
    Ne vaudrait-il pas mieux quelque chose de plus progressif (par exemple une croissance arithmétique) ?
    D'après ce que j'ai lu ici et là, il vaut mieux multiplier par un nombre inférieur au nombre d'or. On peut donc utiliser 1.5 comme facteur de multiplication. Je ne me rappelle plus bien la raison, mais c'est préférable à ajouter de l'espace pour chaque caractère.

  4. #4
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Vous commencez à deux et vous multipliez par 1.5 à chaque fois.
    Voici donc les tailles successives allouées ou réallouées:
    2 3 4 6 9 13 19 28 32 48 64
    96 128 192 288 bon...
    Si vous avez besoin de 300 caractères vous en mobiliserez 432 soit 132 de trop, et le pourcentage ne fera que croitre avec la longueur de la chaine.
    En fait il faudrait connaitre a priori:
    la longueur moyenne des chaines que vous entrez
    la taille minimale
    la taille maximale
    pour décider de la bonne stratégie.
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  5. #5
    Membre éclairé
    Avatar de odsen.s
    Profil pro
    Étudiant
    Inscrit en
    Octobre 2006
    Messages
    269
    Détails du profil
    Informations personnelles :
    Âge : 35
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Octobre 2006
    Messages : 269
    Par défaut
    En fait il faudrait connaitre a priori:
    la longueur moyenne des chaines que vous entrez
    la taille minimale
    la taille maximale
    pour décider de la bonne stratégie.
    Justement, le but du programme est de pouvoir saisir entièrement une chaîne de longueur inconnue, donc pas de taille minimale ou maximale.
    Après, s'il y a des moyens de réallouer de l'espace mémoire avec moins de "pertes", et en limitant le nombre de réallocations comme ici, je suis preneur.

  6. #6
    Rédacteur
    Avatar de Zavonen
    Profil pro
    Inscrit en
    Novembre 2006
    Messages
    1 772
    Détails du profil
    Informations personnelles :
    Âge : 77
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 1 772
    Par défaut
    Je me suis peut être mal fait comprendre:
    Dans tous les cas on proposera un système qui ne se bloque pas, mais la discussion porte sur mode de croissance du buffer.
    Moi je proposerais une croissance arithmétique du genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    size += 50;
                char *p_tmp = realloc(s, size);
    qui assurerait que l'espace maximal perdu reste inférieur à 50 octets.
    NB: realloc est très rapide, imperceptible pendant une opération de saisie
    Ce qu'on trouve est plus important que ce qu'on cherche.
    Maths de base pour les nuls (et les autres...)

  7. #7
    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 odsen.s
    J'ai essayé de faire un programme permettant une saisie de caractère "illimitée" sur l'entrée standard.
    <...>
    Voyez-vous des corrections à effectuer ?
    Par avance, merci.
    Première chose à faire : une fonction :
    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
     
    #include <stdio.h>
    #include <stdlib.h>
     
    char *get_line (void)
    {
       size_t size = 2;
       char *s = malloc (size);
     
       if (s != NULL)
       {
          int c;
          int fin = 0;
          size_t i = 0;
          while ((c = getchar ()) != '\n' && c != EOF && !fin)
          {
             if (i >= size - 1)
             {
                size *= 1.5;
                char *p_tmp = realloc (s, size);
     
                if (p_tmp != NULL)
                {
                   s = p_tmp;
                   s[i++] = c;
                }
                else
                {
                   fin = 1;
                }
             }
             else
             {
                s[i++] = c;
             }
          }
     
          s[i] = '\0';
       }
       return s;
    }
     
    int main (void)
    {
       char *s = get_line ();
       if (s != NULL)
       {
          printf ("s='%s'\n", s);
          free (s);
       }
       else
       {
          printf ("erreur d'allocation memoire\n");
       }
       return 0;
    }
    Malgré une instrumentation poussée (au prix d'une légère modification)
    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
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <assert.h>
    #include <string.h>
     
    #define get_line() fget_line (stdin)
     
    char *fget_line (FILE * fp)
    {
       size_t size = 2;
       char *s = malloc (size);
     
       if (s != NULL)
       {
          int c;
          int fin = 0;
          size_t i = 0;
     
          memset (s, '?', size);
     
          while ((c = fgetc (fp)) != '\n' && c != EOF && !fin)
          {
             if (i >= size - 1)
             {
                char *p_tmp = realloc (s, size * 1.5);
     
                if (p_tmp != NULL)
                {
                   /* ne pas factoriser. Calculs entiers... */
                   memset (p_tmp + size, '?', (size * 1.5) - size);
                   size *= 1.5;
                   s = p_tmp;
                   assert (i < size - 1);
    /* -ed-
                   s[i++] = c;
       a eviter
    */
                   s[i] = c;
                   i++;
                }
                else
                {
                   fin = 1;
                }
             }
             else
             {
                assert (i < size - 1);
                s[i] = c;
                i++;
             }
          }
     
          assert (i < size);
          s[i] = '\0';
       }
       return s;
    }
     
    int main (void)
    {
       int fin = 0;
       while (!fin)
       {
          char *s = get_line ();
          if (s != NULL)
          {
             printf ("s='%s'\n", s);
             fin = *s == 0;
             free (s);
     
          }
          else
          {
             printf ("erreur d'allocation memoire\n");
             fin = 1;
          }
       }
       return 0;
    }
    Je n'ai pas pu mettre ce code en défaut.

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

Discussions similaires

  1. [PL/SQL] Chaine de caractères avec une quote
    Par Titouf dans le forum Oracle
    Réponses: 2
    Dernier message: 15/05/2006, 14h36

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