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 :

Programmer une boucle de saisie chaine de caractère.


Sujet :

C

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 33
    Par défaut Programmer une boucle de saisie chaine de caractère.
    Bonjour à tous!

    Voila, je débute en C, et là je bloque sur un petit truc qui va sûrement vous sembler minable. Mais bon je me lance et tanpis pour ma fierté

    Vu qu'en C il n'y a aucun type pour les chaînes de caractères, j'ai bien compris qu'il faille passer par un tableau de char.

    Ca c'est ok, mais je n'arrive pas à trouver une solution pour que le tableau s'adapte à la taille du mot que l'utilisateur va entrer.

    par exple, pour une boucle de saisie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    for(i=1;i<nb_lettres;i++)
    {
            mot[i]=getch();
    }
    le problème c'est que l'on doit connaitre le nombre de lettres du mot que l'utilisateur va entrer.

    Je voudrais savoir si il existe un moyen de stopper la boucle si l'utilisateur appui sur "Entrée" comme chacun le ferait à la fin du mot.

    J'éspère que je ne suis pas trop confu ds mes explications et que je n'ai pas trop blasphémé

    merci à vous !

    Spike

  2. #2
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    Tu viens de poser un des problèmes chers au programmeurs C++ car c'est une des jusitifications au passage de C à C++ : en C on ne sait pas résoudre de façon élégante ce problème.
    Il faut prendre une chaîne de caractères "assez grande" et ensuite l'agrandir si besoin est, il faut utliser un malloc pour le premier tableau, puis si celui-ci est trop petit, faire des realloc.
    A toi de réfléchir à cette solution.
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  3. #3
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    Et pour s'arrêter sur la touche "entrée", tu compares le caractère reçu avec le caractère '\r' : code de contrôle CR = Carriage Return (Retour Chariot, un terme datant des machines à écrire), valeur 13 (0x0D)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 142
    Par défaut
    Pour résumer le tout :

    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
     
    #define TAILLE_MAX_CHAINE 256
     
    char c;
    char *mot;
    int nbLettre = 0;
    int nbAlloc = 1;
     
    /* allocation initiale de la chaine */
    mot = malloc(sizeof(char) * (TAILLE_MAX_CHAINE + 1));
     
    /* boucle tant que l'utilisateur n'a pas tapé sur <entrée> */
    while ((c = getch()) != 13) {
       mot[nbLettre] = c;
       nbLettre++;
       if (nbLettre > (TAILLE_MAX_CHAINE * nbAlloc)) {
          /* on a dépassé la taille max, il faut réallouer la chaine */
          nbAlloc++;
          mot = realloc(mot, sizeof(char) * (TAILLE_MAX_CHAINE * nbAlloc + 1);
       }
    }
    /* important le caractère de fin de chaine !! */
    mot[nbLettre] = '\0'
    Si j'ai pas écris de bêtises ça devrait fonctionner.
    N'hésite pas si tu as des questions, entre nous ta question est loin d'être minable, ça fait partie des principaux problèmes de tout programmeur débutant en C !!

    (pour les pros du C : j'ai volontairement clarifié le code )

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 33
    Par défaut
    Médinoc: J'étais parti sur la bonne idée alors, car j'ai essayé hier de comparer à '\n' de valeur 10 si je me souviens bien...

    Trap D: Merci pour ces explications, je vais alors essayer de me renseigner sur les allocations et réallocations... Ca m'a l'air bien lourd comme procédé pour une simple saisie de chaine de caractère

    merci à vous pour votre rapidité!

    Spike

  6. #6
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    tomasha >> tu as oublié de tester les retours de malloc et realloc, on ne sait jamais. Peut-être est-ce ta clarification ?
    Par contre par définition, sizeof(char) = 1, donc on peut encore clarifier
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  7. #7
    Membre Expert
    Inscrit en
    Décembre 2004
    Messages
    1 478
    Détails du profil
    Informations forums :
    Inscription : Décembre 2004
    Messages : 1 478
    Par défaut
    Citation Envoyé par Spike Spiegel
    Ca m'a l'air bien lourd comme procédé pour une simple saisie de chaine de caractère
    Le C n'est pas le langage le plus approprie a toutes les applications...

  8. #8
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 142
    Par défaut
    Citation Envoyé par Trap D
    tomasha >> tu as oublié de tester les retours de malloc et realloc, on ne sait jamais. Peut-être est-ce ta clarification ?
    Pas là non il s'agit d'un oubli !!
    Citation Envoyé par Trap D
    Par contre par définition, sizeof(char) = 1, donc on peut encore clarifier
    C'est vrai, mais quand il voudra allouer autre chose que du char, il aura déjà plus d'éléments en connaissant l'utilisation de sizeof!!

  9. #9
    Membre averti
    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    33
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 33
    Par défaut
    merci tomasha! Je vois que tu as utilisé les pointeurs, helas je n'en suis pas encore là dans mes connaissances !

    Alors je vais de ce pas trouver un cours sur les pointeurs et essayer de decrypter ton code!

    merci pour ton aide.

    Spike

  10. #10
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 142
    Par défaut
    Citation Envoyé par Spike Spiegel
    merci tomasha! Je vois que tu as utilisé les pointeurs, helas je n'en suis pas encore là dans mes connaissances !

    Alors je vais de ce pas trouver un cours sur les pointeurs et essayer de decrypter ton code!

    merci pour ton aide.

    Spike
    Pointeurs et chaines de caractères dynamiques sont indissociables !

  11. #11
    Rédacteur/Modérateur
    Avatar de Trap D
    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    4 942
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 4 942
    Par défaut
    Citation Envoyé par tomasha
    C'est vrai, mais quand il voudra allouer autre chose que du char, il aura déjà plus d'éléments en connaissant l'utilisation de sizeof!!
    Tu as raison, nous avons affaire un débutant en C
    "La haine seule fait des choix" - Koan Zen
    "Il ne faut pas être meilleur que les autres, il faut être meilleur que soi." Albert Jacquard
    "Ceux qui savent où ils ont posé leur parapluie ne sont pas alcooliques." - pgibonne.
    Faites du Prolog, ça vous changera les idées !
    Ma page Prolog
    Mes codes sources commentés

    Mon avatar : La Madeleine à la veilleuse de Georges de La Tour

  12. #12
    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 Re: Programmer une boucle de saisie chaine de caractère.
    Citation Envoyé par Spike Spiegel
    Vu qu'en C il n'y a aucun type pour les chaînes de caractères, j'ai bien compris qu'il faille passer par un tableau de char.

    Ca c'est ok, mais je n'arrive pas à trouver une solution pour que le tableau s'adapte à la taille du mot que l'utilisateur va entrer.
    fgets() permet la saisie d'une ligne limitée en taille. Il est ensuite possible de savoir si la ligne est tronquée ou non (présence ou non du '\n'). Si la ligne est tronquée, on peut agrandir le tableau, rappeler fgets(), ceci autant de fois que nécessaire pour obtenir le '\n'...

    L'ago n'est pas trivial, mais il constitue un bon exercice d'allocation / reallocation. On optimise en doublant la taille à chaque tour (en demarrant de 8 ou 16, par exemple)

    http://emmanuel-delahaye.developpez....tes.htm#saisie
    http://emmanuel-delahaye.developpez....s.htm#fichiers
    http://emmanuel-delahaye.developpez....tes.htm#malloc
    http://emmanuel-delahaye.developpez....es.htm#realloc

  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 Médinoc
    Et pour s'arrêter sur la touche "entrée", tu compares le caractère reçu avec le caractère '\r' : code de contrôle CR = Carriage Return (Retour Chariot, un terme datant des machines à écrire), valeur 13 (0x0D)
    Ne fonctionne qu'en mode 'raw' (extension unixoide/termios). En mode standard, le caractère est '\n'.

  14. #14
    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 tomasha
    • getch() n'est pas standard
    • sizeof (char) vaut 1 par définition.
    • Erreurs de frappes (code non compilé, non testé)

    Mise au point.
    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
     
    #include <stdlib.h>
    #include <stdio.h>
     
    #define DBG 1
     
    static char *getline (void)
    {
       int err = 0;
       size_t size = 1;
     
    /* allocation initiale de la chaine */
       char *mot = malloc (size + 1);
       if (mot != NULL)
       {
          size_t nbLettre = 0;
          int c;
     
          mot[size] = 0;
     
    /* boucle tant qu'un '\n' n'a pas ete detecte */
          while ((c = getchar ()) != '\n' && c != EOF && !err)
          {
             mot[nbLettre] = c;
             assert (mot[size] == 0);
     
             nbLettre++;
             if (nbLettre == size)
             {
                char *tmp = realloc (mot, (size * 2) + 1);
     
                if (tmp != NULL)
                {
                   size *= 2;
    #if DBG
                   printf ("realloc() %lu\n", (unsigned long) size);
    #endif
                   mot = tmp;
                   mot[size - 1] = 0;
                }
                else
                {
                   free (mot), mot = NULL;
                   err = 1;
                }
             }
          }
     
    /* important le caractère de fin de chaine !! */
          mot[nbLettre] = '\0';
          assert (nbLettre <= size);
          assert (mot[size] == 0);
       }
       return mot;
    }
    int main (int argc, char **argv)
    {
       char *s = getline ();
     
       if (s != NULL)
       {
          printf ("'%s' (%lu)\n", s, strlen (s));
          free (s), s = NULL;
       }
       return 0;
    }
    Essai :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    J'aime les bananes parce qu'y a pas d'os dedans...
    realloc() 2
    realloc() 4
    realloc() 8
    realloc() 16
    realloc() 32
    realloc() 64
    'J'aime les bananes parce qu'y a pas d'os dedans...' (50)

  15. #15
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 142
    Par défaut
    En passant :
    - je ne faisais pas de réalloc à chaque boucle (seulement tous les 256 caractères)
    - je n'ai pas voulu pondre le code parfait mais une ligne directrice pour aider.

  16. #16
    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 tomasha
    En passant :
    - je ne faisais pas de réalloc à chaque boucle (seulement tous les 256 caractères)
    Exact, je corrige.
    - je n'ai pas voulu pondre le code parfait mais une ligne directrice pour aider.
    Euh, avec des fautes de frappes et du code non standard ?

  17. #17
    Membre éprouvé
    Profil pro
    Inscrit en
    Août 2005
    Messages
    142
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2005
    Messages : 142
    Par défaut
    Je n'ai pas voulu trop modifier son code, mais bon de toute façon tu as complètement raison, si c'est pour apprendre, autant apprendre bien (standart et tout), même si c'est plus dur !

  18. #18
    Expert éminent
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 395
    Par défaut
    C'est surtout plus gênant dans certaines applications: le code "standard" a l'inconvénient de ne pas trater les touches tant qu'on n'a pas entré une ligne complète (A moins que vous ne connaissiez des codes portables pour passer le terminal en mode "caractère" au lieu de "ligne" quelle que soit la plate-forme).

    Car sans un tel code, pas moyen par exemple de faire un beau champ "mot de passe" qui affiche une étoile pour chaque caractère, ni un menu qui ne réclame pas absolument la touche entrée...

    (S'il n'y a pas de code standard pour cela, alors quitte à programmer en non-standard, autant le faire pour de bon...)
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  19. #19
    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 Médinoc
    le code "standard" a l'inconvénient de ne pas trater les touches tant qu'on n'a pas entré une ligne complète.

    Car sans un tel code, pas moyen par exemple de faire un beau champ "mot de passe" qui affiche une étoile pour chaque caractère, ni un menu qui ne réclame pas absolument la touche entrée...

    (S'il n'y a pas de code standard pour cela, alors quitte à programmer en non-standard, autant le faire pour de bon...)
    Pour saisir les mots de passe, il y a les fonctions getpass() et autres qui font partie de POSIX.1 C'est pas du standard C, mais c'est portable sur toute machine supportant POSIX.1

    Quand au mode plein ecran, il n'y a pas de solution POSIX.1. Mais j'ai entendu dire que curses avait été porté sous Windows... (alors qu'a ma connaisance, conio n'existe pas sous unixoide).

    Pour les sorties, il y a aussi la possibilité de compter sur les capacités du terminal (VT-100, Vidéotex, HTML...) qui ne necessitent qu'un simple stdout standard...

  20. #20
    Membre éclairé
    Profil pro
    Inscrit en
    Septembre 2005
    Messages
    66
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2005
    Messages : 66
    Par défaut
    Citation Envoyé par Spike Spiegel
    Médinoc: J'étais parti sur la bonne idée alors, car j'ai essayé hier de comparer à '\n' de valeur 10 si je me souviens bien...

    Trap D: Merci pour ces explications, je vais alors essayer de me renseigner sur les allocations et réallocations... Ca m'a l'air bien lourd comme procédé pour une simple saisie de chaine de caractère

    merci à vous pour votre rapidité!

    Spike
    ça dépend du système d'exploitation ! sous DOS, je crois que c'est \13 et sous unix, c'est \10\13. Je ne sais plus exactement, mais il y a d'abord un linefeed, puis un cariage return. quand tu tape entrée sous UNIX, tu rajoute donc 2 caractères !! fait bien attention de lire les deux !

Discussions similaires

  1. scanf : utilisation dans une boucle de saisie
    Par kromartien dans le forum Bibliothèque standard
    Réponses: 4
    Dernier message: 03/12/2007, 23h50
  2. Réponses: 1
    Dernier message: 14/11/2007, 11h53
  3. Réponses: 10
    Dernier message: 18/07/2007, 11h47
  4. [Débutant] Programmer une boucle
    Par driver dans le forum Pascal
    Réponses: 2
    Dernier message: 25/02/2007, 20h59

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