[Linux-C] Convertion entier vers chaine ??

Convertion entier vers chaine ?? [Linux-C] - C++ - Programmation

Marsh Posté le 21-01-2003 à 12:03:59    

Salut, je pose la question pour un ami
 
Comment faire une convertion d'entier vers uen chaine en C sous Linux qd itoa marche pas ?
 
 
Merci d'avance

Reply

Marsh Posté le 21-01-2003 à 12:03:59   

Reply

Marsh Posté le 21-01-2003 à 12:05:23    

Code :
  1. char* int2chaine(int i)
  2. {
  3.   char* tmp = (char*) calloc(sizeof(int), sizeof(char));
  4.   if(tmp != NULL)
  5.     sprintf(tmp, "%d", i);
  6.   else
  7.     {
  8.       perror("impossible de convertir un int en char*" );
  9.       exit(1);
  10.     }
  11.   return tmp;
  12. }

Reply

Marsh Posté le 21-01-2003 à 14:34:13    

western a écrit :

Code :
  1. char* int2chaine(int i)
  2. {
  3.   char* tmp = (char*) calloc(sizeof(int), sizeof(char));
  4.   if(tmp != NULL)
  5.     sprintf(tmp, "%d", i);
  6.   else
  7.     {
  8.       perror("impossible de convertir un int en char*" );
  9.       exit(1);
  10.     }
  11.   return tmp;
  12. }

 


:jap:
j'aurai meme rajouté un isdigit afin de verifier qu'on a bien un nombre et en cas d'erreur un return NULL au lieu du exit().....

Reply

Marsh Posté le 21-01-2003 à 14:38:14    

Depuis que je l'utilise, pas un exit n'est arrivé ;-)

Reply

Marsh Posté le 21-01-2003 à 16:43:36    

western a écrit :

Depuis que je l'utilise, pas un exit n'est arrivé ;-)

normal, tu échoues que si y'a erreur d'allocation

Reply

Marsh Posté le 21-01-2003 à 17:37:13    

c'est pour cela qu'un exit est plus intéressant que ...

Reply

Marsh Posté le 21-01-2003 à 22:28:09    

western a écrit :

Code :
  1. char* int2chaine(int i)
  2. {
  3.   char* tmp = (char*) calloc(sizeof(int), sizeof(char));
  4.   if(tmp != NULL)
  5.     sprintf(tmp, "%d", i);
  6.   else
  7.     {
  8.       perror("impossible de convertir un int en char*" );
  9.       exit(1);
  10.     }
  11.   return tmp;
  12. }

 


 
 
euuuuuuuh et int2chaine(111111111) t'as déjà essayé ??? :heink:

Reply

Marsh Posté le 22-01-2003 à 05:15:40    

Citation :

char* tmp = (char*) calloc(sizeof(int), sizeof(char));


Hum...
sizeof(int) donne le nombre d'octets pour stocker un int en représentation binaire.
En représentation chaîne décimale, il faut plus.
Il est parfaitement possible que ça n'aie jamais planté, vu que les allocations se font souvent par multiple d'un minimum (16 par exemple).
 
Et puis calloc... au cas ou on oublie d'écrire le nombre ça évites un bogue ?
 
Empiriquement:

Code :
  1. char* tmp = (char*)malloc(sizeof(int)*2.5 + 1 +1 +1); //+1 pour le signe, +1 pour '\0', +1 par sécurité


Personnellement, les fonctions qui font des allocations, ou quittent le programme, bof...

Code :
  1. int int2str(char* str, int i){
  2. return sprintf(str, "%d", i); //renvoie le nombre de caractères
  3. }


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le 22-01-2003 à 08:15:08    

Musaran> t'es sur de ton 2.5? moi j'aurais plutot vu le plus petit entier N tel que N >= CHAR_BITS*ln(2)/ln(10) ce qui doit faire sur nos machines 32 bits N=10
 
[edit] marne, c'est vrai que 8*0.3... ça fait 2.5 :D. au moins 'jai donné une explication du nombre magique et ma solution est plus portable :p :sol:[/edit]
 
plus simplement
donc j'allouerais sizeof(int)*CHAR_BITS*ceil(ln(2.)/ln(10.))+1
 
en tout cas tu ferais peut etre aussi bien faire attention avec les flottants dans des endroits dangereux comme ça, peut etre il serait plus simple de rester dans un calcul entier en faisant des arrondis  par exces: on allouera peut etre un peu trop, mais bon, on est pas quelques octets prets apparemment


Message édité par Taz le 22-01-2003 à 08:25:31
Reply

Marsh Posté le 22-01-2003 à 09:22:42    

oui j'ai essayé 111111111 et ça marche ...
je ne vois pas (mais vraiment pas) l'intérêt d'allouer

Code :
  1. sizeof(int)*2.5*...+...+...+...

(<- original, un float pour l'allocation)

Reply

Marsh Posté le 22-01-2003 à 09:22:42   

Reply

Marsh Posté le 22-01-2003 à 11:48:00    

western a écrit :

oui j'ai essayé 111111111 et ça marche ...
je ne vois pas (mais vraiment pas) l'intérêt d'allouer

Code :
  1. sizeof(int)*2.5*...+...+...+...

(<- original, un float pour l'allocation)


ben t'as de la chance alors, cf l'explication de musaran plus haut.  parce que la chaine pour representer 111111111 elle a besoin de 9+1 characteres et que tu n'en as alloué que 4

Reply

Marsh Posté le 22-01-2003 à 11:57:23    

avant de parler de chances, fait le test!

Reply

Marsh Posté le 22-01-2003 à 12:09:54    

western a écrit :

avant de parler de chances, fait le test!


[:tapai]

Reply

Marsh Posté le 22-01-2003 à 12:14:51    

Juste pour rigoler ...

Code :
  1. int t = -1111111, tt = 1111111;
  2.   for(int i = 0; ; i++)
  3.     {
  4.       t-=10; //- et 10 peuvent être remplacé: * ou 10000
  5.       tt+=10;//+ et 10 peuvent être remplacé: * ou 10000
  6.       printf("%d\n%s\n",t, int2chaine(t));
  7.       printf("%d\n%s\n",tt, int2chaine(tt));
  8.     }


J'ai attent les limites des INT et ... ça marche toujours ... finalement, ce code (que j'ai copié dans un truc qui parlait de Bjarne Stroustrup)  est correcte ...

Reply

Marsh Posté le 22-01-2003 à 13:03:10    

western a écrit :

Juste pour rigoler ...

Code :
  1. int t = -1111111, tt = 1111111;
  2.   for(int i = 0; ; i++)
  3.     {
  4.       t-=10; //- et 10 peuvent être remplacé: * ou 10000
  5.       tt+=10;//+ et 10 peuvent être remplacé: * ou 10000
  6.       printf("%d\n%s\n",t, int2chaine(t));
  7.       printf("%d\n%s\n",tt, int2chaine(tt));
  8.     }


J'ai attent les limites des INT et ... ça marche toujours ... finalement, ce code (que j'ai copié dans un truc qui parlait de Bjarne Stroustrup)  est correcte ...


bon, je reprends: ton calloc reserve QUATRE octets. Ta chaine en fait une bonne dizaine. Donc, ton sprintf écrit en dehors de la zone réservée par ton calloc. Chez toi ça passe parce que ton calloc a réservé 16 octets ou qqch comme ça [ça c'est un coup de bol], mais sur une autre machine ça ne sera peut etre pas le cas.  
 
Lance ton code avec purify/valgrind ou n'importe quel malloc-debuggeur tu vas voir comme il t'insulte

Reply

Marsh Posté le 22-01-2003 à 13:30:27    

chez lui ca passe parce qu'aucune donnée important n'est ecrit apres le 4eme car, mais ca peut planter!!!!

Reply

Marsh Posté le 22-01-2003 à 14:33:12    

ok! valgrid m'insulte ... alors j'ai essaié vos trucs (2.5*..., etc.) il m'insulte toujours ;-) donc ma question (outre qu'aucun d'entre vous n'a toujours pas proposé de solutions valables) s'adresse au Captain: combien faut-il allouer?  
PS. sprintf écrit 10 octets et si je mets 10 + 1 en dure, je suis toujours insulté ...

Reply

Marsh Posté le 22-01-2003 à 15:36:58    

j'ai trouvé "tout seul"
version finale et SANS BUGS!

Code :
  1. char* int2chaine(int i)
  2. {
  3.   char* tmp = (char*) calloc((unsigned int)(log(abs(i)) + 1 + (i<0 ? 1 : 0)) , sizeof(char));
  4.   if(tmp != NULL)
  5.     printf("%d caracteres ecrits\n", sprintf(tmp, "%d", i));
  6.   else
  7.     {
  8.       perror("impossible de convertir un int en char*" );
  9.       exit(1);
  10.     }
  11.   return tmp;
  12. }


Pourquoi?
Dans /usr/include/limits.h , on trouve :

Code :
  1. #  define INT_MAX 2147483647
  2. #  define UINT_MAX 4294967295U
  3. #   define LONG_MAX 9223372036854775807L
  4. #   define ULONG_MAX 18446744073709551615UL


Ce qui donne bien 10 chiffres (donc char) + le signe + le '\0' final.
 
Avec des entiers sur 64 bits c'est juste 2 fois plus long (pour autres plate-formes ;-).
Donc, la taille minimale est pour un entier i à convertir en notation décimale :

Code :
  1. log(abs(i)) + 1 + (i<0 ? 1 : 0)


 
Je pense que ceux-ci close le débat (à moins de s'exciter sur free())!!!
Finalement, je dois remercier les personnes qui ont "trollé" sur le sujet ainsi quelqu'unes autres qui ne sont pas là ...


Message édité par western le 22-01-2003 à 15:40:20
Reply

Marsh Posté le 22-01-2003 à 16:47:29    

western a écrit :

j'ai trouvé "tout seul"
version finale et SANS BUGS!


 
Pour en remettre une couche, un truc plus général c'est d'utiliser la valeur de retour de snprintf(NULL,0,"%d",i) qui renvoie le nb de caractère necessaires

Reply

Marsh Posté le 22-01-2003 à 17:13:35    

pourquoi pas mais il faut peut-être tester sur une plate-forme 64 bits ...

Reply

Marsh Posté le 22-01-2003 à 17:47:09    

western a écrit :

pourquoi pas mais il faut peut-être tester sur une plate-forme 64 bits ...


 
ça doit marcher, à moins de tomber sur un vieille version de sprintf qui renvoie pas la longueur. Sinon, pour conclure une bonne fois pour toutes ;) ce que j'aurais fait si j'avais du faire ce genre de fonction c'est tmp=malloc(256), snprintf(tmp, 256, '%d';), tmp=realloc(tmp,strlen(tmp)+1), c'est quand même moins tordu que d'aller tapper dans des log(i).. par contre ça marchera pas sur une architecture avec des entiers en 1024bits ;)

Reply

Marsh Posté le 22-01-2003 à 18:01:57    

:pt1cable:

Reply

Marsh Posté le 22-01-2003 à 23:46:31    

J'avais vaguement pensé à cette approche par logarithme, sans avoir le courage de le faire.
 
À mon avis, on peut tout aussi bien toujours allouer la taille maximum, l'économie théorique de place n'en valant pas la peine.
Pour que le calcul soit une constante de compilation sans coût d'exécution, je ferais comme ça:

Code :
  1. //transforme du texte brut en chaine littérale
  2. #define stringer(t) #t
  3. //idem, en évaluant les macros d'abord
  4. #define stringereval(t) stringer(t)
  5. ...malloc( sizeof stringereval(INT_MAX) / sizeof(char) + 1); //+1 pour le signe


Le problème est que INT_MAX peut être défini autrement qu'en nombre simple.
C'est pour ça que je n'utilises pas INT_MIN directement: '(-2147483647 - 1)' sur mon système.
 
Allocation en C == prise de tête [:iznogoud_23].


---------------
Bricocheap: Montage de ventilo sur paté de mastic silicone
Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed