Comment convertir un int en chaîne en C?


225

Comment convertir un int(entier) en chaîne? J'essaie de créer une fonction qui convertit les données d'un structen une chaîne pour l'enregistrer dans un fichier.


3
printfou l'un de ses cousins ​​devrait faire l'affaire
pmg


1
vous pouvez également consulter cette FAQ sur la sérialisation, et peut-être les questions suivantes relatives à la sérialisation en C: (a) , (b) , (c) pour atteindre votre intention réelle.
moooeeeep

2
Ma bête sémantique habituelle pour animaux de compagnie ici. Vous ne voulez rien convertir; vous souhaitez obtenir une chaîne contenant une représentation (base 10?) de la valeur de int. Ouais je sais. C'est un raccourci très courant, mais ça me dérange toujours.
dmckee --- chaton ex-modérateur

Réponses:


92

EDIT: Comme indiqué dans le commentaire, ce itoa()n'est pas une norme, il vaut donc mieux utiliser l'approche sprintf () suggérée dans la réponse concurrente!


Vous pouvez utiliser la itoa()fonction pour convertir votre valeur entière en chaîne.

Voici un exemple:

int num = 321;
char snum[5];

// convert 123 to string [buf]
itoa(num, snum, 10);

// print our string
printf("%s\n", snum);

Si vous souhaitez sortir votre structure dans un fichier, il n'est pas nécessaire de convertir une valeur au préalable. Vous pouvez simplement utiliser la spécification du format printf pour indiquer comment sortir vos valeurs et utiliser l'un des opérateurs de la famille printf pour sortir vos données.


30
itoan'est pas standard - voir par exemple stackoverflow.com/questions/190229/…
Paul R

1
@PaulR Maintenant, je ne le savais pas! Merci pour la clarification.
Christian Rau

1
@PaulR Merci, je ne le savais pas!
Alexander Galkin,

@SeanRamey Cela itoa()souffre du même potentiel de débordement de tampon que gets().
chux

itoa n'est pas disponible en C (C99 au moins). il est plus disponible en C ++
Motti Shneor

211

Vous pouvez utiliser sprintfpour le faire, ou peut snprintf- être si vous l'avez:

char str[ENOUGH];
sprintf(str, "%d", 42);

Où le nombre de caractères (plus le caractère de fin) dans le strpeut être calculé en utilisant:

(int)((ceil(log10(num))+1)*sizeof(char))

9
Pour être sûrs que cela ENOUGHsuffit, nous pouvons le faire parmalloc(sizeof(char)*(int)log10(num))
Hauleth

2
@Hauleth Ou même +2, étant donné que (int)log10(42)c'est le cas 1.
Christian Rau

23
Ou vous pouvez le calculer au moment de la compilation:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth Toujours +2 au lieu de +1, même avec ceil: ceil (log (100)) = 2.0, pas 3. Donc +1 pour les puissances exactes de 10, et encore +1 pour terminer null.
not-just-yeti

24
Vous ne considérez pas le signe moins et les paramètres régionaux: séparateur et regroupement de milliers. Veuillez le faire de cette façon: utilisez int length = snprintf(NULL, 0,"%d",42);pour obtenir la longueur, puis allouez les length+1caractères pour la chaîne.
user2622016

70

La réponse courte est:

snprintf( str, size, "%d", x );

Le plus long est: vous devez d'abord trouver une taille suffisante. snprintfvous indique la longueur si vous l'appelez avec NULL, 0comme premiers paramètres:

snprintf( NULL, 0, "%d", x );

Attribuez un caractère de plus pour null-terminator.

#include <stdio.h> 
#include <stdlib.h>

int x = -42;
int length = snprintf( NULL, 0, "%d", x );
char* str = malloc( length + 1 );
snprintf( str, length + 1, "%d", x );
...
free(str);

Si fonctionne pour chaque chaîne de format, vous pouvez donc convertir float ou double en chaîne en utilisant "%g", vous pouvez convertir int en hex en utilisant "%x", et ainsi de suite.


3
#include <stdio.h> #include <stdlib.h>
user1821961

@ user1821961 Merci, il faut vraiment mentionner que ces fichiers d'en-tête doivent être inclus.
byxor

J'adore celui-ci, étant le plus robuste et le plus "à la mode".
Motti Shneor

30

Après avoir examiné différentes versions d'itoa pour gcc, la version la plus flexible que j'ai trouvée qui est capable de gérer les conversions en binaire, décimal et hexadécimal, à la fois positive et négative est la quatrième version trouvée sur http://www.strudel.org .uk / itoa / . Bien que sprintf/ snprintfaient des avantages, ils ne traiteront pas les nombres négatifs pour autre chose que la conversion décimale. Étant donné que le lien ci-dessus est hors ligne ou n'est plus actif, j'ai inclus leur 4ème version ci-dessous:

/**
 * C++ version 0.4 char* style "itoa":
 * Written by Lukás Chmela
 * Released under GPLv3.
 */
char* itoa(int value, char* result, int base) {
    // check that the base if valid
    if (base < 2 || base > 36) { *result = '\0'; return result; }

    char* ptr = result, *ptr1 = result, tmp_char;
    int tmp_value;

    do {
        tmp_value = value;
        value /= base;
        *ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
    } while ( value );

    // Apply negative sign
    if (tmp_value < 0) *ptr++ = '-';
    *ptr-- = '\0';
    while(ptr1 < ptr) {
        tmp_char = *ptr;
        *ptr--= *ptr1;
        *ptr1++ = tmp_char;
    }
    return result;
}

4
En outre, cela est considérablement plus rapide que sprintf. Pourrait être important lors du dumping de gros fichiers.
Eugene Ryabtsev

@Eugene Ryabtsev C ne spécifie pas la note de performance de sprintf()et "c'est beaucoup plus rapide que sprintf" peut être vrai sur votre compilateur mais pas toujours tenir. Un compilateur peut l'examiner sprintf(str, "%d", 42);et l'optimiser pour une itoa()fonction similaire optimisée - certainement plus rapide que cet utilisateur. code.
chux

3
@chux Oui, un compilateur pourrait optimiser sprintf(str, "%d", 42);en ajoutant deux caractères const, mais c'est de la théorie. Dans la pratique, les gens ne sprintent pas et l'itoa ci-dessus est presque aussi optimisé que possible. Au moins, vous pourriez être sûr à 100% que vous n'obtiendrez pas des ordres de grandeur de déclassement d'un sprintf générique. Ce serait bien de voir le contre-exemple que vous avez en tête, avec la version et les paramètres du compilateur.
Eugene Ryabtsev

1
@chux Si cela se termine par un appel, cela n'explique pas grand-chose à moins que nous comparions la routine appelée à la routine ci-dessus (tout le long jusqu'à plus d'appels; en assembleur, si vous le souhaitez). Si vous le faites en tant que réponse avec la version et les paramètres du compilateur, je le jugerai utile.
Eugene Ryabtsev

2
Il serait bon de fournir un moyen de récupérer la longueur de sortie. Je l'ai fait ici: stackoverflow.com/a/52111436/895245 + tests unitaires.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9

C'est vieux mais voici une autre façon.

#include <stdio.h>

#define atoa(x) #x

int main(int argc, char *argv[])
{
    char *string = atoa(1234567890);
    printf("%s\n", string);
    return 0;
}

32
Fonctionne uniquement pour les constantes, pas pour les variables.
Nakedible

7

Si vous utilisez GCC, vous pouvez utiliser la fonction d'extension GNU asprintf.

char* str;
asprintf (&str, "%i", 12313);
free(str);

7

La conversion de n'importe quoi en chaîne doit soit 1) allouer la chaîne résultante, soit 2) transmettre une char *destination et une taille. Exemple de code ci-dessous:

Les deux fonctionnent pour tous, inty compris INT_MIN. Ils fournissent une sortie cohérente contrairement à snprintf()ce qui dépend des paramètres régionaux actuels.

Méthode 1: retour NULLsur mémoire insuffisante.

#define INT_DECIMAL_STRING_SIZE(int_type) ((CHAR_BIT*sizeof(int_type)-1)*10/33+3)

char *int_to_string_alloc(int x) {
  int i = x;
  char buf[INT_DECIMAL_STRING_SIZE(int)];
  char *p = &buf[sizeof buf - 1];
  *p = '\0';
  if (i >= 0) {
    i = -i;
  }
  do {
    p--;
    *p = (char) ('0' - i % 10);
    i /= 10;
  } while (i);
  if (x < 0) {
    p--;
    *p = '-';
  }
  size_t len = (size_t) (&buf[sizeof buf] - p);
  char *s = malloc(len);
  if (s) {
    memcpy(s, p, len);
  }
  return s;
}

Méthode 2: elle retourne NULLsi le tampon était trop petit.

static char *int_to_string_helper(char *dest, size_t n, int x) {
  if (n == 0) {
    return NULL;
  }
  if (x <= -10) {
    dest = int_to_string_helper(dest, n - 1, x / 10);
    if (dest == NULL) return NULL;
  }
  *dest = (char) ('0' - x % 10);
  return dest + 1;
}

char *int_to_string(char *dest, size_t n, int x) {
  char *p = dest;
  if (n == 0) {
    return NULL;
  }
  n--;
  if (x < 0) {
    if (n == 0) return NULL;
    n--;
    *p++ = '-';
  } else {
    x = -x;
  }
  p = int_to_string_helper(p, n, x);
  if (p == NULL) return NULL;
  *p = 0;
  return dest;
}

[Modifier] tel que demandé par @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3est au moins le nombre maximum de charnécessaire pour coder le type d'entier signé sous la forme d'une chaîne composée d'un signe négatif facultatif, de chiffres et d'un caractère nul.

Le nombre de bits non signés dans un entier signé n'est pas supérieur à CHAR_BIT*sizeof(int_type)-1. Une représentation en base 10 d'un nnombre binaire de bits prend jusqu'à n*log10(2) + 1chiffres. 10/33est un peu plus que log10(2). +1 pour le signe charet +1 pour le caractère nul. D'autres fractions pourraient être utilisées comme 28/93.


Méthode 3: Si l'on veut vivre sur le bord et que le débordement de tampon n'est pas un problème, une simple solution C99 ou ultérieure suit qui gère tout int .

#include <limits.h>
#include <stdio.h>

static char *itoa_simple_helper(char *dest, int i) {
  if (i <= -10) {
    dest = itoa_simple_helper(dest, i/10);
  }
  *dest++ = '0' - i%10;
  return dest;
}

char *itoa_simple(char *dest, int i) {
  char *s = dest;
  if (i < 0) {
    *s++ = '-';
  } else {
    i = -i;
  }
  *itoa_simple_helper(s, i) = '\0';
  return dest;
}

int main() {
  char s[100];
  puts(itoa_simple(s, 0));
  puts(itoa_simple(s, 1));
  puts(itoa_simple(s, -1));
  puts(itoa_simple(s, 12345));
  puts(itoa_simple(s, INT_MAX-1));
  puts(itoa_simple(s, INT_MAX));
  puts(itoa_simple(s, INT_MIN+1));
  puts(itoa_simple(s, INT_MIN));
}

Exemple de sortie

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Hé chux, savez-vous s'il existe un moyen d'exposer l'implémentation interne de la glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 Je ne connais pas l'implémentation interne de la glibc.
chux

3
/*Function return size of string and convert signed  *
 *integer to ascii value and store them in array of  *
 *character with NULL at the end of the array        */

int itoa(int value,char *ptr)
     {
        int count=0,temp;
        if(ptr==NULL)
            return 0;   
        if(value==0)
        {   
            *ptr='0';
            return 1;
        }

        if(value<0)
        {
            value*=(-1);    
            *ptr++='-';
            count++;
        }
        for(temp=value;temp>0;temp/=10,ptr++);
        *ptr='\0';
        for(temp=value;temp>0;temp/=10)
        {
            *--ptr=temp%10+'0';
            count++;
        }
        return count;
     }

2

Si vous souhaitez sortir votre structure dans un fichier, il n'est pas nécessaire de convertir une valeur au préalable. Vous pouvez simplement utiliser la spécification du format printf pour indiquer comment sortir vos valeurs et utiliser l'un des opérateurs de la famille printf pour sortir vos données.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.