Как преобразовать int в строку в C?


225

Как преобразовать int(целое число) в строку? Я пытаюсь сделать функцию, которая преобразует данные structв строку, чтобы сохранить их в файле.


3
printfили один из его двоюродных братьев должен сделать трюк
pmg


1
Вы также можете захотеть увидеть этот FAQ по сериализации и, возможно, следующие вопросы, которые относятся к сериализации в C: (a) , (b) , (c) для достижения ваших реальных целей.
moooeeeep

2
Мой обычный питомец семантическая мозоль здесь. Вы не хотите ничего конвертировать; Вы хотите получить строку, содержащую (основание 10?) представление значения int. Да, я знаю. Это очень распространенный вариант, но он все еще меня беспокоит.
dmckee --- котенок экс-модератора

возможный дубликат преобразования int в строку в c
nawfal

Ответы:


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 для вывода ваших данных.


30
itoaне является стандартным - см., например, stackoverflow.com/questions/190229/…
Пол Р

1
@PaulR Теперь я этого не знал! Спасибо за разъяснения.
Кристиан Рау

1
@PaulR Спасибо, я этого не знал!
Александр Галкин

@SeanRamey Это itoa()имеет тот же потенциал переполнения буфера, что и gets().
chux - Восстановить Монику

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
Чтобы быть уверенным, что тата ENOUGHдостаточно, мы можем сделать этоmalloc(sizeof(char)*(int)log10(num))
Hauleth

2
@ Хаулет Или даже +2, учитывая, что (int)log10(42)это так 1.
Кристиан Рау

23
Или вы можете рассчитать его во время компиляции:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth Все равно +2 вместо +1, даже с ceil: ceil (log (100)) = 2.0, а не 3. Так что +1 для точных степеней-10, и еще +1 для завершения нуля.
не только йети

24
Вы не учитываете знак минуса и локаль: разделитель тысяч и группировка. Пожалуйста, сделайте это следующим образом: используйте int length = snprintf(NULL, 0,"%d",42);для получения длины, а затем выделите length+1символы для строки.
user2622016

70

Краткий ответ:

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

Если работает для каждой строки формата, поэтому вы можете конвертировать число с плавающей запятой или двойное в строку с помощью "%g", вы можете преобразовать int в шестнадцатеричное с помощью "%x", и так далее.


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

@ user1821961 Спасибо, нужно отметить, что эти файлы заголовков должны быть включены.
byxor

Я люблю этот, будучи самым надежным и «по книге».
Мотти Шнеор

30

Изучив различные версии itoa для gcc, я обнаружил, что самая гибкая версия, способная обрабатывать преобразования в двоичные, десятичные и шестнадцатеричные, как положительные, так и отрицательные, - четвертая версия, найденная на http://www.strudel.org. .uk / itoa / . Хотя sprintf/ snprintfимеют преимущества, они не будут обрабатывать отрицательные числа ни для чего, кроме десятичного преобразования. Так как ссылка выше отключена или больше не активна, я включил их 4-ю версию ниже:

/**
 * 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 C не указывает рейтинг производительности, sprintf()и «это значительно быстрее, чем sprintf» может быть верно для вашего компилятора, но не всегда верно. Компилятор может изучить sprintf(str, "%d", 42);и оптимизировать его для оптимизированной itoa()подобной функции - конечно, быстрее, чем этот пользователь. код.
Chux - Восстановить Монику

3
@chux Да, компилятор может оптимизировать sprintf(str, "%d", 42);как добавление двух константных символов, но это теория. На практике люди не разбираются в константных значениях, и вышеупомянутая itoa почти настолько же оптимизирована, насколько это возможно. По крайней мере, вы можете быть на 100% уверены, что не получите понижения порядка общего спринта. Было бы неплохо увидеть любой контрпример, который вы имеете в виду, с версией компилятора и настройками.
Евгений Рябцев

1
@chux Если он заканчивается вызовом, он ничего не объясняет, если мы не сравним вызываемую процедуру с приведенной выше процедурой (вплоть до того, что вызовов больше не будет; в сборке, если хотите). Если вы сделаете это в качестве ответа с версией и настройками компилятора, я опишу это как полезное.
Евгений Рябцев

2
Было бы хорошо предоставить способ вернуть длину вывода. Я сделал это здесь: stackoverflow.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

7

Если вы используете GCC, вы можете использовать функцию asprintf расширения GNU.

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. Основное-10 представление n-битного двоичного числа занимает до n*log10(2) + 1цифр. 10/33чуть больше чем log10(2). +1 для знака charи +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

Эй, Чукс, ты знаешь, есть ли способ раскрыть внутреннюю реализацию glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 法轮功 改造 中心 g 事件 法轮功 Я не знаком с внутренней реализацией 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 для вывода ваших данных.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.