Wie konvertiere ich ein int in einen String in C?


225

Wie konvertiert man eine int(Ganzzahl) in eine Zeichenfolge? Ich versuche eine Funktion zu erstellen, die die Daten von a structin eine Zeichenfolge konvertiert , um sie in einer Datei zu speichern.


3
printfoder einer seiner Cousins ​​sollte den Trick machen
pmg


1
Möglicherweise möchten Sie auch diese FAQ zur Serialisierung und möglicherweise die folgenden Fragen zur Serialisierung in C lesen: (a) , (b) , (c) , um Ihre tatsächliche Absicht zu erreichen.
Moooeeeep

2
Mein üblicher Haustier semantischer Ärger hier. Sie möchten nichts konvertieren. Sie möchten eine Zeichenfolge erhalten, die eine (Basis 10?) Darstellung des Werts von enthält int. Ja ich weiß. Es ist eine sehr häufige Abkürzung, aber es nervt mich immer noch.
dmckee --- Ex-Moderator Kätzchen

mögliches Duplikat von Konvertieren von int in String in c
nawfal

Antworten:


92

BEARBEITEN: Wie im Kommentar erwähnt, itoa()handelt es sich nicht um einen Standard. Verwenden Sie daher besser den in der konkurrierenden Antwort vorgeschlagenen sprintf () -Ansatz!


Mit der itoa()Funktion können Sie Ihren ganzzahligen Wert in eine Zeichenfolge konvertieren .

Hier ist ein Beispiel:

int num = 321;
char snum[5];

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

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

Wenn Sie Ihre Struktur in eine Datei ausgeben möchten, müssen Sie zuvor keinen Wert konvertieren. Sie können einfach die printf-Formatspezifikation verwenden, um anzugeben, wie Ihre Werte ausgegeben werden sollen, und einen der Operatoren aus der printf-Familie verwenden, um Ihre Daten auszugeben.


28
itoaist nicht Standard - siehe z. B. stackoverflow.com/questions/190229/…
Paul R

1
@PaulR Jetzt wusste ich das nicht! Danke für die Klarstellung.
Christian Rau

1
@PaulR Danke, das wusste ich nicht!
Alexander Galkin

@SeanRamey Dies hat itoa()das gleiche Pufferüberlaufpotential wie gets().
chux

itoa ist in C nicht verfügbar (mindestens C99). es ist mehr verfügbar in C ++
Motti Shneor

210

Sie können sprintfes verwenden, oder vielleicht, snprintfwenn Sie es haben:

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

Wobei die Anzahl der Zeichen (plus Abschlusszeichen) in strberechnet werden kann mit:

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

9
Um sicher zu sein tat ENOUGHgenügt wir tun können , es durchmalloc(sizeof(char)*(int)log10(num))
Hauleth

2
@Hauleth Oder sogar zwei, wenn man bedenkt , dass (int)log10(42)ist 1.
Christian Rau

23
Oder Sie können es zur Kompilierungszeit berechnen:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
Café

4
@hauleth Immer noch +2 statt +1, auch bei Ceil: Ceil (log (100)) = 2,0, nicht 3. Also +1 für die exakten Potenzen von 10 und weitere +1 für die Beendigung von Null.
Nicht-nur-Yeti

24
Minuszeichen und Gebietsschema werden nicht berücksichtigt: Tausendertrennzeichen und Gruppierung. Bitte machen Sie es so: Verwenden Sie int length = snprintf(NULL, 0,"%d",42);, um die Länge zu ermitteln, und weisen Sie dann length+1Zeichen für die Zeichenfolge zu.
user2622016

69

Die kurze Antwort lautet:

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

Je länger ist: Zuerst müssen Sie die ausreichende Größe herausfinden. snprintfgibt Ihnen die Länge an, wenn Sie es NULL, 0als ersten Parameter aufrufen :

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

Weisen Sie dem Nullterminator ein Zeichen mehr zu.

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

Wenn dies für jede Formatzeichenfolge funktioniert, sodass Sie float oder double mithilfe von verwenden können "%g", können Sie int mithilfe von "%x"usw. in hex konvertieren und so weiter.


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

@ user1821961 Danke, es sollte wirklich erwähnt werden, dass diese Header-Dateien enthalten sein müssen.
Byxor

Ich liebe dieses, weil es das robusteste und "nach dem Buch" ist.
Motti Shneor

30

Nachdem ich mir verschiedene Versionen von itoa für gcc angesehen habe, ist die vierteste Version unter http://www.strudel.org die flexibelste Version, die ich gefunden habe und die Konvertierungen in binäre, dezimale und hexadezimale, sowohl positive als auch negative, verarbeiten kann .uk / itoa / . Während sprintf/ snprintfVorteile haben, werden sie behandeln nicht negative Zahlen für etwas anderes als Dezimal - Umwandlung. Da der obige Link entweder offline oder nicht mehr aktiv ist, habe ich die 4. Version unten eingefügt:

/**
 * 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
Auch das ist deutlich schneller als Sprintf. Kann beim Speichern großer Dateien wichtig sein.
Eugene Ryabtsev

@Eugene Ryabtsev C gibt die Leistungsbewertung von nicht an sprintf()und "dies ist erheblich schneller als sprintf" kann auf Ihrem Compiler zutreffen, aber nicht immer halten. Ein Compiler kann es prüfen sprintf(str, "%d", 42);und auf eine optimierte itoa()ähnliche Funktion optimieren - sicherlich schneller als dieser Benutzer. Code.
chux

3
@chux Ja, ein Compiler könnte das sprintf(str, "%d", 42);Anhängen von zwei konstanten Zeichen optimieren , aber das ist Theorie. In der Praxis sprinten die Leute keine Konstanten und die oben genannte itoa ist fast so optimiert wie es nur geht. Zumindest könnten Sie 100% sicher sein, dass Sie keine Herabstufung eines generischen Sprintf um Größenordnungen erhalten würden. Es wäre schön zu sehen, welches Gegenbeispiel Sie im Sinn haben, mit der Compiler-Version und den Einstellungen.
Eugene Ryabtsev

1
@chux Wenn es in einem Aufruf endet, erklärt es nicht viel, es sei denn, wir vergleichen die aufgerufene Routine mit der obigen Routine (bis hinunter zu keinen weiteren Aufrufen; in Assembly, wenn Sie möchten). Wenn Sie dies als Antwort mit der Compiler-Version und den Einstellungen tun, werde ich es als nützlich bewerten.
Eugene Ryabtsev

2
Es wäre gut, eine Möglichkeit bereitzustellen, um die Ausgabelänge zurückzugewinnen. Ich habe das hier gemacht: stackoverflow.com/a/52111436/895245 + Unit-Tests.
Ciro Santilli 3 冠状 病 六四 事件 3

9

Das ist alt, aber hier ist ein anderer Weg.

#include <stdio.h>

#define atoa(x) #x

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

32
Funktioniert nur für Konstanten, nicht für Variablen.
Nakedible

7

Wenn Sie GCC verwenden, können Sie die asprintf-Funktion der GNU-Erweiterung verwenden.

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

7

Das Konvertieren von etwas in eine Zeichenfolge sollte entweder 1) die resultierende Zeichenfolge zuweisen oder 2) ein char *Ziel und eine Größe übergeben. Beispielcode unten:

Beide arbeiten für alle inteinschließlich INT_MIN. Sie bieten eine konsistente Ausgabe, snprintf()die nicht vom aktuellen Gebietsschema abhängt.

Methode 1: Rückgabe NULLbei Speichermangel.

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

Methode 2: NULLWird zurückgegeben, wenn der Puffer zu klein war.

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

[Bearbeiten] als Anfrage von @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3ist mindestens die maximale Anzahl, die charerforderlich ist, um den Ganzzahlentyp mit Vorzeichen als Zeichenfolge zu codieren, die aus einem optionalen negativen Vorzeichen, Ziffern und einem Nullzeichen besteht.

Die Anzahl der nicht vorzeichenbehafteten Bits in einer vorzeichenbehafteten Ganzzahl beträgt nicht mehr als CHAR_BIT*sizeof(int_type)-1. Eine Basis-10-Darstellung einer n-bit-Binärzahl nimmt n*log10(2) + 1Ziffern auf. 10/33ist etwas mehr als log10(2). +1 für das Vorzeichen charund +1 für das Nullzeichen. Andere Fraktionen könnten wie 28/93 verwendet werden.


Methode 3: Wenn man am Rande leben möchte und der Pufferüberlauf kein Problem darstellt, folgt eine einfache C99-Lösung oder eine spätere Lösung, die alle Probleme löst 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));
}

Beispielausgabe

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Hey chux, weißt du, ob es eine Möglichkeit gibt, die interne Implementierung von glibc verfügbar zu machen? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

1
@CiroSantilli 法轮功 改造 中心 六四 六四 法轮功 Ich bin mit der internen Implementierung von glibc nicht vertraut.
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

Wenn Sie Ihre Struktur in eine Datei ausgeben möchten, müssen Sie zuvor keinen Wert konvertieren. Sie können einfach die printf-Formatspezifikation verwenden, um anzugeben, wie Ihre Werte ausgegeben werden sollen, und einen der Operatoren aus der printf-Familie verwenden, um Ihre Daten auszugeben.


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.