Come convertire un int in stringa in C?


225

Come si converte un int(numero intero) in una stringa? Sto cercando di creare una funzione che converta i dati di astruct in una stringa per salvarli in un file.


3
printfo uno dei suoi cugini dovrebbe fare il trucco
pmg


1
potresti anche voler vedere queste FAQ sulla serializzazione e forse le seguenti domande relative alla serializzazione in C: (a) , (b) , (c) per raggiungere il tuo intento reale.
Moooeeeep,

2
La mia solita pipì semantica da compagnia qui. Non vuoi convertire nulla; si desidera ottenere una stringa contenente una rappresentazione (base 10?) del valore di int. Si lo so. È una scorciatoia molto comune, ma mi infastidisce ancora.
dmckee --- ex gattino moderatore

Risposte:


92

EDIT: Come sottolineato nel commento, itoa()non è uno standard, quindi meglio usare l'approccio sprintf () suggerito nella risposta rivale!


È possibile utilizzare la itoa()funzione per convertire il valore intero in una stringa.

Ecco un esempio:

int num = 321;
char snum[5];

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

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

Se si desidera generare la propria struttura in un file, non è necessario convertire alcun valore in anticipo. Puoi semplicemente utilizzare la specifica del formato printf per indicare come generare i tuoi valori e utilizzare uno degli operatori della famiglia printf per produrre i tuoi dati.


30
itoanon è standard - vedi ad esempio stackoverflow.com/questions/190229/…
Paul R

1
@PaulR Ora non lo sapevo! Grazie per il chiarimento.
Christian Rau,

1
@PaulR Grazie, non lo sapevo!
Alexander Galkin,

@SeanRamey Questo presenta itoa()lo stesso potenziale di overflow del buffer di gets().
chux - Ripristina Monica il

itoa non è disponibile in C (almeno C99). è più disponibile in C ++
Motti Shneor il

211

Puoi usarlo sprintfper farlo, o forse snprintfse ce l'hai:

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

Dove il numero di caratteri (più il carattere di chiusura) in strpuò essere calcolato usando:

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

9
Per essere sicuri che tat ENOUGHsia abbastanza, possiamo farlo entromalloc(sizeof(char)*(int)log10(num))
Hauleth,

2
@Hauleth O anche +2, considerando che lo (int)log10(42)è 1.
Christian Rau,

23
Oppure puoi calcolarlo in fase di compilazione:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth Ancora +2 invece di +1, anche con ceil: ceil (log (100)) = 2.0, non 3. Quindi +1 per i poteri esatti di 10 e un altro +1 per terminare null.
non-solo-yeti,

24
Non consideri il segno meno e la locale: migliaia di separatori e raggruppamenti. Si prega di farlo in questo modo: usare int length = snprintf(NULL, 0,"%d",42);per ottenere la lunghezza, quindi allocare i length+1caratteri per la stringa.
user2622016,

70

La risposta breve è:

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

Più è lungo: prima devi scoprire dimensioni sufficienti. snprintfti dice la lunghezza se la chiami con NULL, 0i primi parametri:

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

Allocare un carattere in più per 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);

Se funziona per ogni stringa di formato, quindi puoi convertire float o double in stringa usando "%g", puoi convertire int in hex usando "%x"e così via.


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

@ user1821961 Grazie, si dovrebbe davvero ricordare che è necessario includere questi file di intestazione.
byxor,

Adoro questo, essendo il modo più robusto e "dal libro".
Motti Shneor,

30

Dopo aver esaminato varie versioni di itoa per gcc, la versione più flessibile che ho trovato in grado di gestire le conversioni in binario, decimale ed esadecimale, sia positiva che negativa è la quarta versione trovata su http://www.strudel.org .uk / itoa / . Sebbene sprintf/ snprintfabbiano vantaggi, non gestiranno numeri negativi per qualcosa di diverso dalla conversione decimale. Poiché il link sopra è off-line o non è più attivo, ho incluso la loro quarta versione di seguito:

/**
 * 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
Inoltre, questo è notevolmente più veloce di sprintf. Potrebbe essere importante durante il dumping di file di grandi dimensioni.
Eugene Ryabtsev,

@Eugene Ryabtsev C non specifica la valutazione delle prestazioni di sprintf()e "questo è considerevolmente più veloce di sprintf" può essere vero sul tuo compilatore ma non sempre vale. Un compilatore può esaminarlo sprintf(str, "%d", 42);e ottimizzarlo in una itoa()funzione simile ottimizzata , sicuramente più veloce di questo utente. codice.
chux - Ripristina Monica il

3
@chux Sì, un compilatore potrebbe ottimizzare sprintf(str, "%d", 42);come aggiunta di due caratteri costanti, ma questa è teoria. In pratica, le persone non sprintano le costanti e gli itoa sopra sono quasi ottimizzati come si arriva. Almeno potresti essere sicuro al 100% di non ottenere ordini di grandezza declassati di uno sprintf generico. Sarebbe bello vedere qualunque controesempio tu abbia in mente, con la versione e le impostazioni del compilatore.
Eugene Ryabtsev,

1
@chux Se termina in una chiamata, non spiega molto a meno che non confrontiamo la routine chiamata con la routine precedente (fino in fondo a non più chiamate; in assembly, se lo desideri). Se lo fai come una risposta con la versione e le impostazioni del compilatore, lo voterò come utile.
Eugene Ryabtsev,

2
Sarebbe utile fornire un modo per ripristinare la lunghezza dell'output. L'ho fatto qui: stackoverflow.com/a/52111436/895245 + test unitari.
Ciro Santilli 3 冠状 病 六四 事件 法轮功

9

Questo è vecchio ma ecco un altro modo.

#include <stdio.h>

#define atoa(x) #x

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

32
Funziona solo per le costanti, non per le variabili.
Nakedible,

7

Se stai usando GCC, puoi usare l'estensione GNU come funzione asprintf.

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

7

La conversione di qualsiasi cosa in una stringa dovrebbe o 1) allocare la stringa risultante o 2) passare in a char * destinazione e dimensione. Codice di esempio di seguito:

Entrambi funzionano per tutti intcompresi INT_MIN. Forniscono un output coerente a differenzasnprintf() che dipende dalle impostazioni internazionali correnti.

Metodo 1: restituisce NULLmemoria insufficiente.

#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;
}

Metodo 2: restituisce NULLse il buffer era troppo piccolo.

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;
}

[Modifica] come richiesto da @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3 è almeno il numero massimo di char necessario per codificare il tipo intero con segno come una stringa costituita da un segno negativo facoltativo, cifre e un carattere null.

Il numero di bit non di segno in un numero intero con segno non è maggiore di CHAR_BIT*sizeof(int_type)-1. Una rappresentazione in base 10 di un nnumero binario a bit richiede fino a n*log10(2) + 1cifre. 10/33è leggermente più di log10(2). +1 per il segno chare +1 per il carattere null. Altre frazioni potrebbero essere usate come 28/93.


Metodo 3: Se si vuole vivere al limite e il buffer overflow non è un problema, segue una semplice soluzione C99 o successiva che gestisce tutto 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));
}

Uscita campione

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Ehi chux, sai se c'è un modo per esporre l'implementazione interna di glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 Non ho familiarità con l'implementazione interna di glibc.
chux - Ripristina Monica il

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

Se si desidera generare la propria struttura in un file, non è necessario convertire alcun valore in anticipo. Puoi semplicemente utilizzare la specifica del formato printf per indicare come generare i tuoi valori e utilizzare uno degli operatori della famiglia printf per produrre i tuoi dati.


Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.