Jak przekonwertować int na string w C?


225

Jak przekonwertować int(liczbę całkowitą) na ciąg? Próbuję utworzyć funkcję, która konwertuje dane ciągu structna ciąg znaków, aby zapisać go w pliku.


3
printflub jeden z jego kuzynów powinien załatwić
sprawę


1
możesz również zapoznać się z często zadawanymi pytaniami na temat serializacji i być może z następującymi pytaniami, które dotyczą serializacji w C: (a) , (b) , (c), aby osiągnąć swój rzeczywisty zamiar.
moooeeeep 24.11.11

2
Moja zwykła semantyczna siusiu tutaj. Nie chcesz niczego konwertować; chcesz otrzymać ciąg zawierający (podstawową 10?) reprezentację wartości int. Tak, wiem. Jest to bardzo popularny skrót, ale wciąż mnie wkurza.
dmckee --- były moderator kociak

Odpowiedzi:


92

EDYCJA: Jak wskazano w komentarzu, itoa()nie jest standardem, dlatego lepiej zastosować podejście sprintf () sugerowane w odpowiedzi rywalizującej!


Możesz użyć itoa()funkcji do konwersji wartości całkowitej na ciąg.

Oto przykład:

int num = 321;
char snum[5];

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

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

Jeśli chcesz wyprowadzić swoją strukturę do pliku, nie musisz wcześniej konwertować żadnej wartości. Możesz po prostu użyć specyfikacji formatu printf, aby wskazać, jak wyprowadzać swoje wartości, i użyć dowolnego operatora z rodziny printf do wyprowadzenia danych.


29
itoanie jest standardem - patrz np. stackoverflow.com/questions/190229/…
Paul R

1
@PaulR Teraz tego nie wiedziałem! Dziękuję za wyjaśnienie.
Christian Rau,

1
@PaulR Dzięki, nie wiedziałem o tym!
Alexander Galkin

@SeanRamey Ma itoa()to taki sam potencjał przepełnienia bufora jak gets().
chux - Przywróć Monikę

itoa nie jest dostępny w C (przynajmniej C99). jest bardziej dostępny w C ++
Motti Shneor

211

Możesz sprintfto zrobić, a snprintfjeśli masz:

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

Gdzie liczbę znaków (plus znak kończący) w strmożna obliczyć za pomocą:

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

9
Aby mieć pewność, że tat ENOUGHwystarczy, możemy to zrobićmalloc(sizeof(char)*(int)log10(num))
Hauleth,

2
@Hauleth Lub nawet +2, biorąc pod uwagę, że tak (int)log10(42)jest 1.
Christian Rau

23
Lub możesz to obliczyć w czasie kompilacji:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth Nadal +2 zamiast +1, nawet przy ceil: ceil (log (100)) = 2,0, a nie 3. Więc +1 za dokładną potęgę-10 i kolejne +1 za zakończenie zerowania.
not-just-yeti

24
Nie bierzesz pod uwagę znaku minus i lokalizacji: separator tysięcy i grupowanie. Zrób to w ten sposób: użyj, int length = snprintf(NULL, 0,"%d",42);aby uzyskać długość, a następnie przydziel length+1znaki do łańcucha.
user2622016

69

Krótka odpowiedź brzmi:

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

Im dłużej: najpierw musisz znaleźć odpowiedni rozmiar. snprintfpodaje długość, jeśli wywołasz ją NULL, 0jako pierwsze parametry:

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

Przydziel jeszcze jeden znak dla 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);

Jeśli działa dla każdego formatu formatu, więc możesz przekonwertować zmiennoprzecinkowe lub podwójne na łańcuch przy użyciu "%g", możesz przekonwertować int na hex przy użyciu "%x"i tak dalej.


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

@ user1821961 Dzięki, naprawdę należy wspomnieć, że te pliki nagłówkowe muszą zostać dołączone.
byxor

Uwielbiam ten, ponieważ jest najsolidniejszy i „z książki”.
Motti Shneor

30

Po przejrzeniu różnych wersji itoa dla gcc, najbardziej elastyczną wersją, jaką znalazłem, która jest w stanie obsługiwać konwersje na binarne, dziesiętne i szesnastkowe, zarówno pozytywne, jak i negatywne, jest czwarta wersja znaleziona na http://www.strudel.org .uk / itoa / . Chociaż sprintf/ snprintfmają zalety, nie będą obsługiwać liczb ujemnych dla niczego innego niż konwersja dziesiętna. Ponieważ powyższy link jest offline lub nie jest już aktywny, zamieściłem poniżej jego czwartą wersję:

/**
 * 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
Jest to także znacznie szybsze niż sprintf. Może to być ważne podczas zrzutu dużych plików.
Eugene Ryabtsev

@Eugene Ryabtsev C nie określa oceny wydajności, sprintf()a „to jest znacznie szybsze niż sprintf” może być prawdą w twoim kompilatorze, ale nie zawsze się utrzymuje. Kompilator może go przeanalizować sprintf(str, "%d", 42);i zoptymalizować do zoptymalizowanej itoa()funkcji podobnej - na pewno szybciej niż ten użytkownik. kod.
chux - Przywróć Monikę

3
@chux Tak, kompilator może zoptymalizować sprintf(str, "%d", 42);jako dodanie dwóch stałych, ale taka jest teoria. W praktyce ludzie nie sprintf constints i powyższe itoa jest prawie tak zoptymalizowane, jak to możliwe. Przynajmniej możesz być w 100% pewien, że nie dostaniesz obniżenia rzędów wielkości ogólnego sprintu. Byłoby miło zobaczyć cokolwiek kontrprzykład, jaki masz na myśli, z wersją kompilatora i ustawieniami.
Eugene Ryabtsev

1
@chux Jeśli zakończy się wywołaniem, nie wyjaśnia wiele, chyba że porównamy wywoływaną procedurę z powyższą procedurą (aż do braku kolejnych wywołań; w assemblerze, jeśli chcesz). Jeśli zrobisz to jako odpowiedź z wersją kompilatora i ustawieniami, będę go głosować jako przydatny.
Eugene Ryabtsev

2
Dobrze byłoby zapewnić sposób na odzyskanie długości wyjściowej. Zrobiłem to tutaj: stackoverflow.com/a/52111436/895245 + testy jednostkowe.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9

To jest stare, ale oto inny sposób.

#include <stdio.h>

#define atoa(x) #x

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

32
Działa tylko dla stałych, a nie dla zmiennych.
Nakedible

7

Jeśli używasz GCC, możesz użyć funkcji rozszerzenia asprintf GNU.

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

7

Konwersja czegokolwiek na ciąg powinna albo 1) przydzielić wynikowy ciąg, albo 2) przekazać w miejscu char *docelowym i rozmiarze. Przykładowy kod poniżej:

Oba działają dla wszystkich, w inttym INT_MIN. Zapewniają one spójne wyniki, w przeciwieństwie snprintf()do aktualnych ustawień regionalnych.

Metoda 1: Zwraca brak NULLpamięci.

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

Metoda 2: Zwraca, NULLjeśli bufor był zbyt mały.

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

[Edytuj] na żądanie @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3to co najmniej maksymalna liczba charpotrzebna do zakodowania jakiegoś podpisanego typu liczby całkowitej jako ciągu składającego się z opcjonalnego znaku ujemnego, cyfr i znaku zerowego.

Liczba bitów niebędących znakami w całkowitej liczbie ze znakiem jest nie większa niż CHAR_BIT*sizeof(int_type)-1. Reprezentacja 10- nbitowej liczby binarnej zajmuje n*log10(2) + 1cyfry. 10/33jest nieco więcej niż log10(2). +1 za znak chari +1 za znak zerowy. Można stosować inne frakcje, takie jak 28/93.


Metoda 3: Jeśli ktoś chce żyć na krawędzi, a przepełnienie bufora nie stanowi problemu, następuje proste rozwiązanie C99 lub nowsze, które obsługuje wszystkie 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));
}

Próbka wyjściowa

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Hej chux, czy wiesz, czy jest jakiś sposób na ujawnienie wewnętrznej implementacji glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 Nie jestem zaznajomiony z wewnętrzną implementacją glibc.
chux - Przywróć Monikę

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

Jeśli chcesz wyprowadzić swoją strukturę do pliku, nie musisz wcześniej konwertować żadnej wartości. Możesz po prostu użyć specyfikacji formatu printf, aby wskazać, jak wyprowadzać swoje wartości, i użyć dowolnego operatora z rodziny printf do wyprowadzenia danych.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.