Bagaimana cara mengubah int ke string di C?


225

Bagaimana Anda mengonversi int(integer) ke string? Saya mencoba membuat fungsi yang mengubah data structmenjadi string untuk menyimpannya dalam file.


3
printfatau salah satu sepupunya harus melakukan trik
pmg


1
Anda mungkin juga ingin melihat FAQ ini tentang serialisasi, dan mungkin pertanyaan-pertanyaan berikut yang berkaitan dengan serialisasi dalam C: (a) , (b) , (c) untuk mencapai maksud Anda yang sebenarnya.
moooeeeep

2
Semantik hewan peliharaan saya seperti biasa di sini. Anda tidak ingin mengonversi apa pun; Anda ingin mendapatkan string yang berisi representasi (basis 10?) dari nilai int. Ya aku tahu. Ini jalan pintas yang sangat umum, tetapi masih mengganggu saya.
dmckee --- ex-moderator kitten

kemungkinan rangkap dari Konversi int ke string di c
nawfal

Jawaban:


92

EDIT: Seperti yang ditunjukkan dalam komentar, itoa()bukan standar, jadi lebih baik gunakan pendekatan sprintf () yang disarankan dalam jawaban yang bersaing!


Anda bisa menggunakan itoa()fungsi untuk mengonversi nilai integer Anda menjadi sebuah string.

Berikut ini sebuah contoh:

int num = 321;
char snum[5];

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

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

Jika Anda ingin menampilkan struktur Anda menjadi file, Anda tidak perlu mengonversi nilai apa pun sebelumnya. Anda bisa menggunakan spesifikasi format printf untuk menunjukkan cara menampilkan nilai Anda dan menggunakan salah satu operator dari keluarga printf untuk menampilkan data Anda.


30
itoatidak standar - lihat misalnya stackoverflow.com/questions/190229/…
Paul R

1
@ PaulR Sekarang saya tidak tahu itu! Terimakasih atas klarifikasinya.
Christian Rau

1
@ PaulR Terima kasih, saya tidak tahu itu!
Alexander Galkin

@SeanRamey Ini itoa()mengalami potensi buffer overflow yang sama dengan gets().
chux - Reinstate Monica

itoa tidak tersedia dalam C (setidaknya C99). lebih tersedia di C ++
Motti Shneor

211

Anda dapat menggunakannya sprintfuntuk melakukannya, atau mungkin snprintfjika Anda memilikinya:

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

Di mana jumlah karakter (plus karakter terminasi) di str dapat dihitung menggunakan:

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

9
Yang pasti tat ENOUGHsudah cukup kita bisa melakukannya denganmalloc(sizeof(char)*(int)log10(num))
Hauleth

2
@Hauleth Atau bahkan 2, mengingat (int)log10(42)ini 1.
Christian Rau

23
Atau Anda dapat menghitungnya pada waktu kompilasi:#define ENOUGH ((CHAR_BIT * sizeof(int) - 1) / 3 + 2)
caf

4
@hauleth Still +2 bukannya +1, bahkan dengan ceil: ceil (log (100)) = 2.0, bukan 3. Jadi +1 untuk nilai tepat-of-10, dan +1 lainnya untuk mengakhiri nol.
not-just-yeti

24
Anda tidak mempertimbangkan tanda minus dan lokal: ribuan pemisah dan pengelompokan. Silakan lakukan seperti ini: gunakan int length = snprintf(NULL, 0,"%d",42);untuk mendapatkan panjang, dan kemudian alokasikan length+1karakter untuk string.
user2622016

70

Jawaban singkatnya adalah:

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

Semakin lama: pertama Anda perlu mengetahui ukuran yang cukup. snprintfmemberi tahu Anda panjangnya jika Anda menyebutnya dengan NULL, 0sebagai parameter pertama:

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

Alokasikan satu karakter lebih banyak untuk 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);

Jika berfungsi untuk setiap string format, jadi Anda bisa mengonversi float atau double ke string dengan menggunakan "%g", Anda bisa mengonversi int ke hex menggunakan "%x", dan sebagainya.


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

@ user1821961 Terima kasih, harus benar-benar disebutkan bahwa file header ini harus disertakan.
byxor

Saya suka yang ini, menjadi cara yang paling kuat dan "menurut buku".
Motti Shneor

30

Setelah melihat berbagai versi itoa untuk gcc, versi paling fleksibel yang saya temukan yang mampu menangani konversi ke biner, desimal dan heksadesimal, baik positif dan negatif adalah versi keempat yang ditemukan di http://www.strudel.org .uk / itoa / . Sementara sprintf/ snprintfmemiliki keunggulan, mereka tidak akan menangani angka negatif untuk apa saja selain konversi desimal. Karena tautan di atas tidak aktif atau tidak aktif lagi, saya telah menyertakan versi ke-4 di bawah ini:

/**
 * 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
Juga, ini jauh lebih cepat daripada sprintf. Bisa jadi penting saat membuang file besar.
Eugene Ryabtsev

@Eugene Ryabtsev C tidak menentukan peringkat kinerja sprintf()dan "ini jauh lebih cepat daripada sprintf" mungkin benar pada kompiler Anda tetapi tidak selalu berlaku. Kompiler dapat melihat sprintf(str, "%d", 42);dan mengoptimalkannya ke itoa()fungsi seperti dioptimalkan - tentu saja lebih cepat dari pengguna ini. kode.
chux - Reinstate Monica

3
@ chux Ya, kompiler dapat dioptimalkan sprintf(str, "%d", 42);sebagai menambahkan dua karakter const, tapi itu teori. Dalam prakteknya orang tidak berlari cepat dan itoa di atas hampir sama optimalnya dengan yang didapat. Setidaknya Anda bisa 100% yakin Anda tidak akan mendapatkan pesanan penurunan peringkat dari sprintf generik. Akan lebih baik untuk melihat contoh balik apa pun yang ada dalam pikiran Anda, dengan versi dan pengaturan kompiler.
Eugene Ryabtsev

1
@ chux Jika berakhir dengan panggilan, itu tidak menjelaskan banyak kecuali kita membandingkan rutin yang dipanggil dengan rutin di atas (semua jalan ke tidak ada lagi panggilan; dalam perakitan, jika Anda suka). Jika Anda melakukannya sebagai jawaban dengan versi dan pengaturan kompiler, saya akan menambahkannya sebagai berguna.
Eugene Ryabtsev

2
Akan lebih baik untuk menyediakan cara untuk mendapatkan panjang output kembali. Saya sudah melakukannya di sini: stackoverflow.com/a/52111436/895245 + unit test.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

9

Ini sudah tua tapi ini cara lain.

#include <stdio.h>

#define atoa(x) #x

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

32
Hanya berfungsi untuk konstanta, bukan untuk variabel.
Nakedible

7

Jika Anda menggunakan GCC, Anda dapat menggunakan fungsi GNU extension asprintf.

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

7

Mengubah apapun menjadi string harus 1) mengalokasikan string yang dihasilkan atau 2) meneruskan a char * tujuan dan ukuran. Kode contoh di bawah ini:

Keduanya bekerja untuk semua inttermasuk INT_MIN. Mereka memberikan hasil yang konsisten tidak sepertisnprintf() yang tergantung pada lokal saat ini.

Metode 1: Mengembalikan NULLkehabisan memori.

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

Metode 2: Ini kembali NULLjika buffer terlalu kecil.

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

[Sunting] sebagai permintaan oleh @Alter Mann

(CHAR_BIT*sizeof(int_type)-1)*10/33+3paling tidak adalah jumlah maksimum yang chardiperlukan untuk menyandikan beberapa tipe integer yang ditandatangani sebagai string yang terdiri dari tanda negatif opsional, digit, dan karakter nol.

Jumlah bit non-masuk dalam bilangan bulat yang ditandatangani tidak lebih dari CHAR_BIT*sizeof(int_type)-1. Representasi basis-10 dari nangka biner -bit membutuhkan hingga n*log10(2) + 1digit. 10/33sedikit lebih dari log10(2). +1 untuk tanda chardan +1 untuk karakter nol. Fraksi lain dapat digunakan seperti 28/93.


Metode 3: Jika seseorang ingin hidup di tepi dan buffer overflow bukan masalah, solusi C99 sederhana atau lebih baru mengikuti yang menangani semua 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));
}

Output sampel

0
1
-1
12345
2147483646
2147483647
-2147483647
-2147483648

Hei chux, apakah Anda tahu jika ada cara untuk mengekspos implementasi internal glibc? sourceware.org/git/?p=glibc.git;a=blob;f=stdio-common/…
Ciro Santilli 郝海东 冠状 病 六四 六四 事件 法轮功

1
@CiroSantilli 新疆 改造 中心 六四 事件 法轮功 Saya tidak terbiasa dengan implementasi internal glibc.
chux - Reinstate Monica

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

Jika Anda ingin menampilkan struktur Anda menjadi file, Anda tidak perlu mengkonversi nilai apa pun sebelumnya. Anda bisa menggunakan spesifikasi format printf untuk menunjukkan cara menampilkan nilai Anda dan menggunakan salah satu operator dari keluarga printf untuk menampilkan data Anda.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.