Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
3260 connectés 

  FORUM HardWare.fr
  Programmation
  C

  fonction saisie ligne sans limite

 



 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

fonction saisie ligne sans limite

n°1660245
ngkreator
Posté le 18-12-2007 à 21:46:03  profilanswer
 

Bonjour, j'essaie de faire une fonction qui me permette de récupérer une ligne entrée au clavier sans le '\n' final.
 
Mon but est de faire une fonction qui n'ai pas besoin de limite dans la taille de la ligne à saisir. J'ai donc pensé à realloc, je trouve ça bourrin, mais ça marche:
 

Code :
  1. char * getlineStdin(void)
  2. {
  3.     char * strIn = NULL;
  4.     char c;
  5.     size_t count = 0;
  6.     while((c = getchar()) != '\n' && c != EOF)
  7.     {
  8.         strIn = realloc(strIn,(count+1));
  9.         if(strIn == NULL) return NULL;
  10.         strIn[count] = c;
  11.         count++;
  12.     }
  13.     strIn = realloc(strIn,count+1);
  14.     if(strIn == NULL) return NULL;
  15.     strIn[count] = '\0';
  16.     return strIn;
  17. }


 
Je compte l'utiliser souvent donc j'aimerais bien avoir des retours SVP, merci d'avance.


Message édité par ngkreator le 18-12-2007 à 21:48:53
mood
Publicité
Posté le 18-12-2007 à 21:46:03  profilanswer
 

n°1660382
matafan
Posté le 18-12-2007 à 22:48:56  profilanswer
 

Tu devrais éviter de faire un realloc() à chaque char, c'est très pénalisant. Fait plutôt tes reallocs() par blocs : quand tu n'as plus de place dans le buffer tu lui ajoutes un bloc de 4096 octets par exemple, et ensuite tu es tranquile pour 4096 getchar().
 
Ensuite une fois que tu realloc() par bloc, tu peux aussi faire les lectures par blocs avec fgets(). Ca t'évitera autant d'appels de fonction.
 
Enfin, si ton système dispose de getline(), c'est exactement ce que tu veux.

n°1660447
Trap D
Posté le 19-12-2007 à 08:24:39  profilanswer
 

On peut commencer par 4096 et il est conseillé pour la reallocation de multiplier la taille par le nombre d'or.

n°1660497
Elmoricq
Modérateur
Posté le 19-12-2007 à 10:13:16  profilanswer
 

La fonction que j'avais créée à cette fin, je l'utilisais pour lire des fichiers de données, et donc plutôt que de refaire à chaque ligne lue les mêmes phases de réallocations, je stockais la taille du bloc dans un static.  
La taille initiale était assez petite (dans les 100-200 je crois), à chaque réallocation je doublais, et je stockais la nouvelle taille. Comme ça, à chaque allocation j'allouais le plus gros bloc déjà alloué auparavant, le but étant de minimiser le nombre de realloc() lors de la lecture de nombreuses lignes de tailles similaires.


Message édité par Elmoricq le 19-12-2007 à 10:13:50
n°1660512
spotaszn
Posté le 19-12-2007 à 10:37:48  profilanswer
 

Bonjour,
 

Code :
  1. strIn = realloc(strIn,count+1);
  2. if(strIn == NULL) return NULL;


 
Il y a une fuite de mémoire si 'realloc' échoue, il me semble...
Extrait du man :


realloc() renvoie un pointeur sur la mémoire nouvellement allouée, qui est correctement alignée pour  n'importe
quel  type  de variable, et qui peut être différent de ptr, ou NULL si la demande échoue, ou si size vaut zéro.
Si realloc() échoue, le bloc mémoire original reste intact, il n'est ni libéré ni déplacé.


n°1660516
matafan
Posté le 19-12-2007 à 10:41:09  profilanswer
 

Trap D a écrit :

On peut commencer par 4096 et il est conseillé pour la reallocation de multiplier la taille par le nombre d'or.


Seulement les jours de pleine lune ;)

n°1660523
Elmoricq
Modérateur
Posté le 19-12-2007 à 10:48:37  profilanswer
 

spotaszn a écrit :

Il y a une fuite de mémoire si 'realloc' échoue, il me semble...


 
Il te semble bien. :jap:
Pour correctement utiliser realloc(), si l'on souhaite poursuivre le programme après échec, il faut effectivement passer par une variable temporaire, ce qui laisse le pointeur initialement utilisé intact.

n°1660618
ngkreator
Posté le 19-12-2007 à 13:04:42  profilanswer
 

Merci pour toutes vos réponses!
 

  • allocation par bloc -> ok mais je vais faire ça avec des plus petits bloc, c'est pour lire des caractères écrits aux clavier donc j'ai besoin de beaucoup moins de place.
  • fonction getline -> je connais celles du C++ mais pas pour C.
  • fuite de mémoire -> ok pour la variable temporaire.

n°1660638
Taz
bisounours-codeur
Posté le 19-12-2007 à 14:32:43  profilanswer
 

matafan a écrit :


Seulement les jours de pleine lune ;)


Plutôt avec un allocateur best fit. Mais osef, on parle de quelques octets. 4096 c'est peut être excessif cependant comme départ.

n°1660639
Taz
bisounours-codeur
Posté le 19-12-2007 à 14:33:32  profilanswer
 

ngkreator a écrit :

Merci pour toutes vos réponses!

  • fonction getline -> je connais celles du C++ mais pas pour C.

y a getline en C mais pas standard, extension GNU.

mood
Publicité
Posté le 19-12-2007 à 14:33:32  profilanswer
 

n°1660653
ngkreator
Posté le 19-12-2007 à 14:44:57  profilanswer
 

Ah oui donc je vais rester sur du standard.
 

Code :
  1. char * getlineStdin(void)
  2. {
  3.     size_t size = GETLINE_STDIN_INPUT_SIZE;
  4.     char * strIn = NULL;
  5.     char * strTmp = NULL;
  6.     char c;
  7.     size_t count = 0;
  8.     strIn = malloc(size);
  9.     if(strIn != NULL)
  10.     {
  11.         while((c = getchar()) != '\n' && c != EOF && strIn != NULL)
  12.         {
  13.             if(count < size-1)
  14.                 strIn[count] = c;
  15.             else
  16.             {
  17.                 size *= 2;
  18.                 strTmp = (char*) realloc(strIn,size);
  19.                 if(strTmp != NULL)
  20.                 {
  21.                     strIn = strTmp;
  22.                     strIn[count] = c;
  23.                 }
  24.                 else
  25.                 {
  26.                     free(strIn);
  27.                     strIn = NULL;
  28.                 }
  29.             }
  30.             count++;
  31.         }
  32.         if(strIn != NULL)
  33.             strIn[count] = '\0';
  34.     }
  35.     return strIn;
  36. }


 
Porblème:  
 

Code :
  1. strTmp = (char*) realloc(strIn,size);
  2. if(strTmp != NULL)
  3.     strIn = strTmp;


 
Si le bloc mémoire pointé par strIn est déplacé (lors de la réallocation) de l'emplacement mémoire A vers B on pourrait libérer A. Mais on ne sais pas quand il y a eu déplacement ou non. On ne peut donc pas faire:
 

Code :
  1. strTmp = (char*) realloc(strIn,size);
  2. if(strTmp != NULL)
  3. {
  4.     free(strIn);
  5.     strIn = strTmp;
  6. }


 
Au grand risque de libérer A alors que strTmp pointe également vers A.
 
Comment faire?
 
Il faut aussi que je gère la vidange du stdin avant de commencer d'ailleurs.


Message édité par ngkreator le 19-12-2007 à 14:58:27
n°1660925
dreameddea​th
Posté le 20-12-2007 à 01:27:07  profilanswer
 

Attention, le realloc "libère" de lui-même (ou plutôt remet à disposition dans la heap) la mémoire originelle du pointeur si la ré-allocation c'est bien passé. D'ailleurs dans le cas présent, il ne faut surtout pas essayer de faire un free sur le strIn, qui pointe vers l'ancienne zone mémoire (voir pire la même) et cela fera ce que l'on appelle de la memory corruption.
 
donc pour moi ton code initial est bon et ne comporte pas de fuite.
 
Par contre, pour la beauté du geste, je n'aime pas écrire 2 fois le même code,comme la ligne suivante qui y est 2 fois  :

Code :
  1. strIn[count] = c;


 
en réflechissant un peu, tu verras qu'il est possible de d'abord mettre le caractère dans le tableau, faire le ++ et ensuite (avec la bonne condition, une simple égalité) faire si nécessaire l'augmentation de la taille du buffer...
Le if initial est inutile, surtout si tu réordonance un peu la condition dans le while (si ton souhait est d'éviter un getchar dont tu ne ferais rien)
 
D'ailleurs, la politique du *=2 me parrait un peu violente, mais c'est un choix
 
Mais tout cela n'est que détail :)
 
Au final je verais qqch du style  

Code :
  1. char * getlineStdin(void)
  2. {
  3.      size_t size = GETLINE_STDIN_INPUT_SIZE;
  4.      char * strIn = NULL;
  5.      char * strTmp = NULL;
  6.      char c;
  7.      size_t count = 0;
  8.      strIn = malloc(size);
  9.      while ( [la bonne condition] ) {
  10.            strIn[count] = c;
  11.            count++;
  12.            if([la bonne condition]){
  13.                  size *= 2; /* éventuellement remplacer par un += GETLINE_STDIN_INPUT_SIZE */
  14.                  strTmp = (char*) realloc(strIn,size);
  15.                  if(strTmp==NULL) free(strIn);
  16.                  strIn=strTmp; /*c'est inutilement sioux, je sais, faire le else proprement, c'est + lisible*/
  17.            }
  18.     }
  19.     if(strIn!=NULL){
  20.         strIn[count]="\0";
  21.     }
  22.     return strIn;
  23. }


 
Bon courage


Message édité par dreameddeath le 20-12-2007 à 01:27:39

Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C

  fonction saisie ligne sans limite

 

Sujets relatifs
utiliser la fonction number_format() pour ajouter une virgule[VBA] Ajout automatique d'une ligne dans une liste déroulante
vente en ligne[résolu] Automatiser une fonction excel sur vba
[C] fwrite ajoute des caractères de fin de ligne ...[Sed] Modifier une ligne dans un .bat
CMS fonction annuaireFonction random sous Firefox
Macro Taille LigneConfigurer la fonction mail de appache (php.ini)
Plus de sujets relatifs à : fonction saisie ligne sans limite


Copyright © 1997-2018 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR