Menu

String ke Int di C: atoi, strtol, dan Mengubah Angka Menjadi Teks

Mengonversi antara teks dan angka di C: kenapa atoi tidak bisa melaporkan error, cara memakai strtol dan strtod dengan benar lewat endptr dan errno, mengubah angka menjadi string dengan snprintf, dan trik satu digit dengan '0'.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Teks dari pengguna, file, dan command line datang sebagai karakter. "42" adalah tiga byte, yaitu '4', '2', '\0', dan tidak ada satu pun yang merupakan angka 42 sampai kamu mengonversinya. C menawarkan dua generasi fungsi konversi: yang lama dan pendek yang tidak bisa melaporkan error, dan yang lebih panjang yang bisa. Halaman ini menunjukkan keduanya dan menjelaskan kenapa program sungguhan memakai set yang kedua.

Keluarga Lama: atoi, atol, atof

Namanya sudah menjelaskan isinya: ASCII ke int, ke long, ke double. Satu argumen, satu hasil.

Spasi di awal dilewati, tanda opsional dibaca, digit-digitnya diambil, dan semua yang ada sesudahnya diabaikan. Itu praktis sampai input-nya salah:

Ketiganya mencetak 0. Tidak ada kode kembalian, tidak ada flag, tidak ada cara untuk bertanya "berhasil atau tidak?", dan nilai yang melebihi batas int adalah undefined behavior, bukan error yang dilaporkan. Untuk literal yang ditulis langsung di program mainan, itu masih bisa ditoleransi. Untuk apa pun yang bisa diberikan oleh orang atau file, fungsi ini adalah pabrik bug yang diam-diam.

Alat yang Tepat: strtol

strtol (string to long) melakukan konversi yang sama dengan dua jalur untuk melaporkan apa yang terjadi.

long strtol(const char *text, char **endptr, int base);

endptr diisi dengan karakter pertama yang tidak dibaca fungsi tersebut. base adalah basis bilangan: pakai 10, atau 0 untuk membiarkan prefiks literal itu sendiri yang menentukan (0x untuk heksadesimal, 0 di depan untuk oktal).

Membaca endptr menjawab pertanyaan yang tidak bisa dijawab atoi:

  • end == input berarti tidak ada yang dikonversi: teksnya tidak diawali angka.
  • *end != '\0' berarti ada isi tambahan di belakang. Apakah itu error atau bukan, kamu yang menentukan: tidak masalah saat mengurai "42 apples", tetapi jadi masalah jika seluruh baris seharusnya berupa angka.

Overflow dilaporkan secara terpisah lewat errno. Pola lengkap yang benar ini layak ditulis sekali lalu dipakai ulang:

Tiga detail membuat kode ini benar. errno = 0 sebelum pemanggilan itu penting karena library hanya pernah mengisi errno dan tidak pernah mengosongkannya, sehingga nilai lama dari pemanggilan sebelumnya bisa terbaca sebagai kegagalan pemanggilan ini. strtol mengembalikan long, yang bisa lebih lebar daripada int, jadi pengecekan rentang terhadap INT_MIN/INT_MAX terpisah dari ERANGE. Terakhir, mengembalikan status keberhasilan sambil mengirim nilainya lewat pointer adalah cara fungsi C melaporkan "entah sebuah nilai, entah sebuah kegagalan", karena nilai kembalian tidak bisa melakukan dua tugas sekaligus.

strtoul adalah versi unsigned-nya, dan strtoll/strtoull menangani long long.

Basis Lain

Basis 16 membaca heksadesimal; basis 0 memeriksa prefiksnya dan memutuskan sendiri. Untuk mengecek arti sebuah string di basis lain, tempelkan ke pengonversi basis bilangan.

Basis 0 menjadi jebakan dalam satu kasus khusus: desimal yang diawali nol seperti "012" dibaca sebagai oktal dan hasilnya 10. Jika input-mu desimal, tulis 10 secara eksplisit.

Bilangan Pecahan: strtod

strtod punya bentuk yang sama untuk double, dan atof punya kelemahan yang sama dengan atoi.

strtod juga menerima notasi ilmiah ("1.5e3"), float heksadesimal, serta kata "inf" dan "nan". Locale memengaruhi pemisah desimal, dan ini sering mengejutkan orang yang mengurai file yang ditulis di tempat lain. Di locale "C" bawaan, pemisahnya selalu titik.

Angka ke Teks: snprintf

Untuk arah sebaliknya, snprintf adalah jawaban standarnya. Fungsi ini menulis paling banyak sebesar ukuran yang kamu berikan, selalu mengakhiri string, dan mengembalikan panjang yang dibutuhkan hasil lengkapnya.

Nilai kembalian itulah pengecekan pemotongannya. Jika nilainya lebih besar dari atau sama dengan ukuran buffer, teksnya tidak muat:

Dua hal yang sebaiknya tidak kamu pakai: itoa bukan bagian dari C standar, jadi kode yang memakainya tidak bisa di-compile di semua tempat; dan sprintf adalah snprintf tanpa batas ukuran, artinya fungsi ini akan menulis melewati ujung buffer-mu tanpa protes.

Karakter Tunggal dan '0'

Karakter digit '0' sampai '9' dijamin berurutan, jadi pengurangan biasa sudah cukup untuk mengonversi antara karakter digit dan nilainya.

Hanya digit yang berperilaku seperti ini. Huruf tidak wajib berurutan, jadi c - 'a' tidak portabel untuk aritmetika alfabet. Lindungi pengurangannya dengan isdigit sebelum memercayainya:

Cast ke unsigned char diperlukan dengan alasan yang sama seperti pada string: fungsi-fungsi <ctype.h> tidak terdefinisi untuk argumen negatif, dan char biasa bisa bersifat signed.

Fungsi Mana yang Dipakai

  • Teks dari pengguna, file, atau argv → strtol / strtod dengan pengecekan lengkap.
  • Literal yang kamu tulis dan kendalikan sendiri → atoi masih bisa diterima, walau biasa saja.
  • Angka ke dalam buffer → snprintf, lalu cek nilai kembaliannya.
  • Satu karakter digit → kurangi dengan '0', setelah isdigit.
  • Jangan pernah → gets, sprintf, itoa.

Pertanyaan yang sering diajukan

Bagaimana cara mengubah string menjadi int di C?

strtol(text, &end, 10) adalah jawaban yang benar: fungsi ini mengembalikan nilainya, mengisi end dengan karakter pertama yang tidak ia baca, dan melaporkan overflow lewat errno. atoi(text) lebih pendek, tetapi mengembalikan 0 baik untuk "0" maupun "hello" tanpa cara untuk membedakan keduanya.

Apa masalahnya dengan atoi di C?

Fungsi ini tidak bisa melaporkan kegagalan. atoi("abc") mengembalikan 0, yang tidak bisa dibedakan dari nol sungguhan, dan overflow adalah undefined behavior, bukan error yang dilaporkan. Pakai strtol setiap kali teksnya berasal dari pengguna, file, atau argumen command line.

Bagaimana cara mengubah int menjadi string di C?

snprintf(buf, sizeof buf, "%d", n). Fungsi ini standar, dibatasi ukuran buffer, dan mengembalikan jumlah karakter yang dibutuhkan hasil lengkapnya, sehingga nilai kembalian yang sama dengan atau lebih dari sizeof buf memberitahumu bahwa teksnya terpotong. itoa bukan bagian dari C standar.

Bagaimana cara mengubah karakter '7' menjadi angka 7 di C?

Kurangi dengan '0': int digit = c - '0';. Karakter digit selalu berurutan di setiap set karakter C, jadi pengurangan ini menghasilkan 0 sampai 9. Lindungi dulu dengan isdigit((unsigned char)c), karena aritmetika ini tidak bermakna untuk karakter lain.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai