Partage
  • Partager sur Facebook
  • Partager sur Twitter

Saisie et malloc

Sujet résolu
    9 mars 2008 à 12:48:36

    Salut !

    Petite question sans doute débile, mais comment faire pour récupérer une chaine de caractère sans utiliser de tableau statique ?

    Mon idée :
    - Vider stdin
    - Remplir stdin (par le biais de quelle fonction? fputs? fputc? Mais là on laisse plus le choix à l'utlisateur :p )
    - Prendre le nombre de caractère qu'il y a dans stdin
    - Faire une allocation dynamique en fonction du nombre de caractère
    - Prendre le contenu de stdin, le mettre dans le tableau créé
    - Vider stdin


    Est-ce possible (si oui, comment, et quelles sont les précautions à prendre?) ou est-ce totalement utopique?

    Merci d'avance !
    • Partager sur Facebook
    • Partager sur Twitter
    Anonyme
      9 mars 2008 à 12:57:10

      Boucle de getchar pour avoir le nombre de caractères. A chaque tour de boucle, on ungetc dans stdin pour replacer le caractère ni vu ni connu.
      On avance d'un caractère.
      On alloue dynamiquement un tableau suffisant en se servant de malloc et de la taille précédemment récupérée.
      On rembobine de la taille de la chaine.
      fgets(tableau, taille, stdin);

      Je n'ai pas testé, mais en théorie ça marche !

      EDIT: Après test, et tout plein de bidouillages, ça n'a pas l'air de marcher ... Une solution serait de stocker les caractères non pas dans un tableau, mais dans une liste chainée, mais là, bonjour le bouffage de mémoire !
      • Partager sur Facebook
      • Partager sur Twitter
        9 mars 2008 à 14:45:00

        Oula ...
        Ya pas plus simple ? :p
        Merci de ton aide.
        • Partager sur Facebook
        • Partager sur Twitter
          9 mars 2008 à 15:04:31

          Et avec un scanf ou un fscanf et un tableau de caractère dynamique ?
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            9 mars 2008 à 15:07:05

            Citation : mathedit

            Et avec un scanf ou un fscanf et un tableau de caractère dynamique ?


            scanf ne permet pas de contrôler les caractères rentrés ...
            • Partager sur Facebook
            • Partager sur Twitter
              9 mars 2008 à 15:17:09

              Citation : Vico21

              Petite question sans doute débile, mais comment faire pour récupérer une chaine de caractère sans utiliser de tableau statique ?


              En utilisant un tableau dynamique ?

              Citation : Pas de titre

              Mon idée :
              - Vider stdin


              C'est pas à toi de le faire. C'est à l'appel précédant de laisser propre.

              Citation : Pas de titre

              - Remplir stdin (par le biais de quelle fonction? fputs? fputc? Mais là on laisse plus le choix à l'utlisateur :p )


              ungetc(), mais je ne suis pas sûr que ça fonctionne dans tous les cas...

              Citation : Pas de titre


              - Prendre le nombre de caractère qu'il y a dans stdin
              - Faire une allocation dynamique en fonction du nombre de caractère
              - Prendre le contenu de stdin, le mettre dans le tableau créé
              - Vider stdin


              J'ai un peu du mal à comprendre le but de la manœuvre... Pour faire une saisie dynamique, il n'y a pas besoin de tout ce bazar...

              Si tu veux que la saisie vienne d'ailleurs (fichier, par exemple), utilise une indirection :

              monappli < input.txt
              • Partager sur Facebook
              • Partager sur Twitter
              Music only !
                9 mars 2008 à 15:24:53

                Salut,

                À défaut de connaître la taille de la chaîne (et donc de pouvoir allouer dès le début un tableau suffisamment grand), on peut :

                - allouer un tableau de taille N (arbitraire) ;
                - lire au plus N-1 caractères et les stocker dans le tableau ;
                - s'il reste des caractères à lire, on réalloue le tableau en augmentant sa taille de N et on recommence...

                C'est en substance ce que fait, par exemple, la fonction getline (3) de la bibliothèque C GNU (attention, c'est une fonction propre à la GNU libc, elle n'est pas du tout standard).
                • Partager sur Facebook
                • Partager sur Twitter
                  9 mars 2008 à 15:26:35

                  Ouais, je crois que je suis pas très clair.
                  Je veux tout simplement récupérer une chaîne de caractère rentrée par l'utilisateur, et la stocker dans un tableau qui aurait pile la bonne taille (un tableau dynamique donc). Je sais faire cela en utilisant un tableau statique assez grand pour accueillir la chaîne, puis créer ensuite un tableau dynamique avec la bonne taille.

                  Ma question est : peut-on se passer de l'étape "réception de la saisie dans un tableau statique" ?

                  Ma théorie était donc d'inviter l'utilisateur à saisir une chaine de caractère (comme avec un fgets ou un scanf), mais de ne pas le stocker dans un tableau statique et de garder le tout dans stdin. Après il suffirait en théorie de travailler avec stdin pour récupérer la chaine et la place correctement dans le tableau dynamique.

                  Est-ce possible "facilement"?

                  edit > gouttegd, c'est à peu près ça que je veux faire, mais sans le tableau de départ ;)
                  • Partager sur Facebook
                  • Partager sur Twitter
                    9 mars 2008 à 17:23:51

                    Ben, quelle importance d'allouer le tableau dès le départ, de toute façon il faudra bien l'allouer à un moment ou à un autre...

                    Quant à ce que tu veux faire avec stdin, je ne suis pas sûr que ce soit possible, du moins en C standard. C'est un flux ("stream"), tu ne peux rien y "stocker".

                    Certes, sous le capot il y a un tampon (il y en a même sans doute au moins deux : un au niveau du système d'exploitation, et un au niveau de la bibliothèque C), mais c'est un détail d'implémentation, je doute que le C standard y donne accès...

                    Et quand bien même il le ferait, tu ne pourrais pas y stocker une chaîne plus grande que le tampon, donc en fait tu retomberais dans la même situation qu'avec un tableau statique.
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      9 mars 2008 à 17:27:15

                      Si j'ai bien compris ce que tu as dis, gouttegd, deux solutions seulement sont possibles :
                      • Stocker les caractères dans une liste chainée au lieu d'un tableau.
                      • Intervenir au niveau du système.

                      C'est bien ça ?
                      • Partager sur Facebook
                      • Partager sur Twitter
                        9 mars 2008 à 17:30:24

                        Citation : gouttegd

                        Ben, quelle importance d'allouer le tableau dès le départ, de toute façon il faudra bien l'allouer à un moment ou à un autre...

                        Quant à ce que tu veux faire avec stdin, je ne suis pas sûr que ce soit possible, du moins en C standard. C'est un flux ("stream"), tu ne peux rien y "stocker".

                        Certes, sous le capot il y a un tampon (il y en a même sans doute au moins deux : un au niveau du système d'exploitation, et un au niveau de la bibliothèque C), mais c'est un détail d'implémentation, je doute que le C standard y donne accès...

                        Et quand bien même il le ferait, tu ne pourrais pas y stocker une chaîne plus grande que le tampon, donc en fait tu retomberais dans la même situation qu'avec un tableau statique.


                        Tu as raison. Bon bah je vais me mettre à coder cette petite fonction ! :)

                        Merci pour ton aide.
                        • Partager sur Facebook
                        • Partager sur Twitter
                          9 mars 2008 à 17:48:42

                          Citation : 1337833K

                          Si j'ai bien compris ce que tu as dis, gouttegd, deux solutions seulement sont possibles :

                          • Stocker les caractères dans une liste chainée au lieu d'un tableau.
                          • Intervenir au niveau du système.


                          C'est bien ça ?


                          Oulà, je m'exprime si mal que ça ? :o

                          Non, la solution que je préconise (enfin, quand je dis "je", ce n'est pas moi qui l'ai inventée, hein ^^ ), c'est d'utiliser un tableau que l'on redimmensionnera au fur et à mesure que l'on lire des données depuis le flux.

                          Donc, par exemple, on commence par allouer (avec malloc) un tableau de 512 caractères. Puis on demande à lire 512 caractères depuis le flux (avec fgets, ou fread, selon les besoins), en les stockant dans le tableau. Ensuite, deux possibilités : on est à la fin du flux, donc on a terminé et on peut renvoyer le tableau ; ou bien il reste encore des données dans le flux, donc on augmente la taille du tableau de 512 (avec realloc) et on demande à lire les 512 caractères suivants, et ainsi de suite.

                          La taille initiale du tableau (ici 512) est arbitraire. L'idée est de trouver un compromis entre :
                          - un tableau initial suffisamment grand afin que, avec un peu de chance (si la chaîne à lire n'est pas longue), il ne soit pas nécessaire de réallouer ;
                          - un tableau initial suffisamment petit afin que, si la chaîne est vraiment courte, on n'alloue pas un grand tableau pour rien.

                          Nul besoin de listes chaînées. Et c'est entièrement faisable en C standard, sans aller chercher des fonctions propres à un système. :)
                          • Partager sur Facebook
                          • Partager sur Twitter
                            9 mars 2008 à 18:03:52

                            Citation : Vico21

                            Ouais, je crois que je suis pas très clair.
                            Je veux tout simplement récupérer une chaîne de caractère rentrée par l'utilisateur, et la stocker dans un tableau qui aurait pile la bonne taille (un tableau dynamique donc).


                            Pourquoi 'pile la bonne taille' ? C'est grave si il est plus grand ? Ce qui compte c'est que soit fiable, non ? Pour avoir 'pile la bonne taille', il faut soit allouer les caractères un par un (pas efficace), soit fait comme le propose goutted, mais en allouant au final un bloc de la bonne taille, ce qui entraine une copie supplémentaire. Il faut savoir de toutes façon, qu'un malloc() de 1 alloue probablement un bloc de 16 ou de 32 bytes, alors je ne crois pas que ta manœuvre ait un sens...


                            Citation : Pas de titre

                            Après il suffirait en théorie de travailler avec stdin pour récupérer la chaine et la place correctement dans le tableau dynamique.

                            Est-ce possible "facilement"?


                            Non. On a pas accès directement aux données de stdin.
                            • Partager sur Facebook
                            • Partager sur Twitter
                            Music only !
                              9 mars 2008 à 18:30:41

                              Pour revenir sur l'utilisation d'une liste chaînée : ça fonctionnerait, certes, mais quand on y réfléchit deux minutes, c'est super bourrin et pas du tout élégant...

                              D'abord, en terme d'occupation mémoire. Chaque maillon de la chaîne devrait ressembler à ça :
                              1. struct item {
                              2.     char character;
                              3.     struct item *next;
                              4. };

                              Donc en supposant que l'on est sur une machine où les char sont codés sur un octet et les pointeurs sur 4, chaque maillon de la chaîne occuperait théoriquement 5 octets, et certainement même 8 (puisque le compilateur va probablement ajouter 3 octets de "remplissage" afin d'avoir une structure dont la taille est "alignable" sur 4 octets).

                              En d'autres termes, par rapport à un tableau de char, une liste chaînée demanderait ici 8 fois plus de mémoire !

                              Ensuite, en termes d'efficacité. Avec une telle liste, il faut rajouter un maillon à chaque nouveau caractère lu, ce que veut dire qu'il faudrait allouer continuellement 8 octets. Même en supposant que l'implémentation de malloc est suffisamment "intelligente" pour "fusionner" certaines de ces allocations, je doute que ce soit très efficace.

                              Enfin, comme il est probable que le code appelant veut recevoir une chaîne de caractères "classique" (caractères stockés de façon contiguë, se terminant par un caractère nul) et non une liste chaînée, il faudrait, une fois la liste complète, déterminer sa taille, allouer un tableau de ladite taille et y copier les caractères un par un...

                              J'admets que les goûts et les couleurs ne se discutent pas, mais quand même, si quelqu'un trouve ça élégant (sans même parler de l'efficacité), je m'inquiète pour lui. ^^
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Saisie et malloc

                              × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                              × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                              • Editeur
                              • Markdown