C에서 int를 문자열로 변환하는 방법은 무엇입니까?


225

int(정수)를 문자열 로 어떻게 변환 합니까? struct파일 의 데이터를 문자열로 변환하여 파일로 저장 하는 함수를 만들려고 합니다.


3
printf또는 사촌 중 한 명이 트릭을 수행해야합니다
pmg


1
직렬화에 대한 이 FAQ 와 C의 직렬화와 관련된 다음 질문 을 참조 할 수도 있습니다 . (a) , (b) , (c) 실제 의도를 달성합니다.
moooeeeep

2
내 평소 애완 동물 의미 론적 여기. 아무것도 변환하고 싶지 않습니다. 의 값에 대한 (기본 10?) 표현이 포함 된 문자열을 얻으려고합니다 int. 그래, 알아 매우 일반적인 지름길이지만 여전히 버그가 있습니다.
dmckee --- 전 운영자 고양이

답변:


92

편집 : 의견에서 지적했듯이 itoa()표준이 아니므로 경쟁 답변에서 제안 된 sprintf () 접근 방식을 더 잘 사용하십시오!


itoa()함수를 사용 하여 정수 값을 문자열 로 변환 할 수 있습니다 .

예를 들면 다음과 같습니다.

int num = 321;
char snum[5];

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

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

구조를 파일로 출력하려면 미리 값을 변환 할 필요가 없습니다. 당신은 바로 사용할 수 의 printf 형식 사양을 출력하는 방법에 대한 당신의 가치를 나타내며에서 연산자 중 하나를 사용하는 printf와 가족 데이터를 출력.


29
itoa표준이 아닙니다-예를 들어 stackoverflow.com/questions/190229/…
Paul R

1
@PaulR 이제는 몰랐습니다! 설명해 주셔서 감사합니다.
Christian Rau

1
@PaulR 감사합니다, 나는 그것을 몰랐습니다!
Alexander Galkin

@SeanRamey 이것 itoa()과 동일한 버퍼 오버 플로우 가능성이 있습니다 gets().
chux-복원 Monica Monica

itoa는 C에서는 사용할 수 없습니다 (최소한 C99). C ++에서 더 많이 사용 가능
Motti Shneor

211

당신 sprintf이 그것을 할 수 있습니다 , 또는 snprintf당신이 그것을 가지고 있다면 :

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

의 문자 수 (및 종료 문자)는 str다음을 사용하여 계산할 수 있습니다.

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

9
tat ENOUGH가 충분한 지 확인하기 위해 우리는 그것을 할 수 있습니다malloc(sizeof(char)*(int)log10(num))
Hauleth

2
@Hauleth 또는 심지어 +2 (int)log10(42)입니다 1.
Christian Rau

23
또는 컴파일 타임에 계산할 수 있습니다.#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
ceil : ceil (log (100)) = 2.0, 3이 아닌 +1 대신 +1 대신 +2.
not-just-yeti

24
빼기 부호와 로케일은 고려하지 않습니다 (천 단위 구분 기호 및 그룹화). 다음과 같이하십시오 : int length = snprintf(NULL, 0,"%d",42);길이를 얻는 데 사용 length+1하고 문자열에 문자를 할당 하십시오.
user2622016

69

짧은 대답은 다음과 같습니다.

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

더 길면 : 먼저 충분한 크기를 찾아야합니다. 첫 번째 매개 변수로 snprintf호출하면 길이를 알려줍니다 NULL, 0.

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

널 종료자를 위해 한 문자를 더 할당하십시오.

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

모든 형식 문자열에 대해 작동하므로을 사용하여 float 또는 double을 문자열 "%g"로 변환 할 수 있으면 을 사용하여 int를 16 진수로 변환 할 수 있습니다 "%x".


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

@ user1821961 감사합니다.이 헤더 파일들을 포함시켜야한다는 것이 실제로 언급되어야합니다.
byxor

나는이 책을 가장 강력하고 "책으로"사랑합니다.
Motti Shneor

30

gcc에 대한 다양한 버전의 itoa를 살펴본 후, 내가 찾은 가장 유연한 버전은 2 진, 10 진수 및 16 진으로의 변환을 처리 할 수 ​​있으며, 양수 및 음수 모두 http://www.strudel.org에 있는 네 번째 버전입니다 . .uk / itoa / . 반면 sprintf/는 snprintf장점을 가지고, 그들은 소수 변환 외의 항목에 음수를 처리하지 않습니다. 위의 링크가 오프라인이거나 더 이상 활성화되어 있지 않으므로 아래에 네 번째 버전을 포함 시켰습니다.

/**
 * 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
또한 이것은 sprintf보다 훨씬 빠릅니다. 큰 파일을 덤프 할 때 중요 할 수 있습니다.
Eugene Ryabtsev

@Eugene Ryabtsev C는 성능 등급을 지정하지 않으며 sprintf()컴파일러에서 "sprintf보다 상당히 빠르다"는 것은 사실이지만 항상 유지하는 것은 아닙니다. 컴파일러는 이 사용자보다 확실히 빠른 sprintf(str, "%d", 42);최적화 된 itoa()함수 를 찾아 최적화 할 수 있습니다. 암호.
chux-복원 Monica Monica

3
@chux 예, 컴파일러는 sprintf(str, "%d", 42);두 개의 const 문자를 추가하여 최적화 할 수 있지만 이론입니다. 실제로 사람들은 const ints를 단속하지 않으며 위의 itoa는 거의 최적화되어 있습니다. 최소한 일반 스프린트의 다운 그레이드가 발생하지 않을 것이라고 100 % 확신 할 수 있습니다. 컴파일러 버전과 설정을 사용하여 기억해야 할 반례를 보는 것이 좋습니다.
유진 Ryabtsev

1
@chux 호출이 끝나면 호출 된 루틴을 위의 루틴과 비교하지 않는 한 많이 설명하지 않습니다 (원하는 경우 어셈블리에서 더 이상 호출하지 않음). 컴파일러 버전 및 설정에 대한 답변으로 수행하면 유용하다고 생각합니다.
Eugene Ryabtsev

2
출력 길이를 다시 얻는 방법을 제공하는 것이 좋습니다. 여기에서 스택 오버플로 .com / a / 52111436 / 895245 + 단위 테스트를 수행했습니다.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9

이것은 오래되었지만 여기 다른 방법이 있습니다.

#include <stdio.h>

#define atoa(x) #x

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

32
상수가 아닌 변수에 대해서만 작동합니다.
Nakedible 2019

7

GCC를 사용하는 경우 GNU 확장 프로그램 asprintf 기능을 사용할 수 있습니다.

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

7

문자열로 변환하려면 1) 결과 문자열을 할당하거나 2) char *대상 및 크기를 전달해야 합니다. 아래 샘플 코드 :

모두를 int포함하여 모두 작동합니다 INT_MIN. 그들은 달리 일관된 출력을 제공합니다snprintf()현재 로케일에 따라 .

방법 1 : NULL메모리 부족으로 반환 합니다.

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

방법 2 : NULL버퍼가 너무 작은 경우 반환 합니다.

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

@Alter Mann의 요청에 따라 [편집]

(CHAR_BIT*sizeof(int_type)-1)*10/33+3최소한 char부호있는 정수 유형을 선택적 음수 부호, 숫자 및 널 문자로 구성된 문자열로 인코딩하는 데 필요한 최대 수입니다 .

부호있는 정수의 부호없는 비트 수는 개를 초과하지 않습니다 CHAR_BIT*sizeof(int_type)-1. - n비트 이진수 의 10 진 표현은 n*log10(2) + 1숫자 까지 입니다. 10/33보다 약간 큽니다 log10(2). 부호는 char+1, 널 문자는 +1 다른 분획은 28/93과 같이 사용될 수 있습니다.


방법 3 : 하나의 가장자리에 살고 오버 플로우가 중요하지 않은 버퍼하고자하는 경우, 간단한 C99 이상 솔루션을 처리하는 다음 모두를 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));
}

샘플 출력

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Chux, glibc 내부 구현을 공개 할 방법이 있는지 아십니까? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 나는 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

구조를 파일로 출력하려면 미리 값을 변환 할 필요가 없습니다. printf 형식 스펙을 사용하여 값을 출력하는 방법을 표시하고 printf 제품군의 연산자를 사용하여 데이터를 출력 할 수 있습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.