Operasi teks yang paling sering dibutuhkan sudah disediakan pustaka standar melalui header string.h. Topik ini membahas lima fungsi intinya, yaitu strlen, strcpy, strcat, strcmp, dan strstr, beserta risiko buffer overflow yang menyertainya. Setelah membacanya, pengolahan string dasar dapat dilakukan sambil tahu kapan setiap fungsi aman dipakai.
Mengukur panjang dengan strlen#
Fungsi strlen menghitung jumlah karakter sebelum penanda akhir, tanpa ikut menghitung '\0'. Nilai kembaliannya bertipe size_t, yaitu tipe bilangan bulat tak bertanda untuk ukuran memori, sehingga penentu formatnya adalah %zu. Header string.h perlu disertakan lewat #include <string.h> sebelum fungsinya dipakai.
#include <stdio.h>
#include <string.h>
int main(void) {
char kota[] = "Bandung";
char kosong[] = "";
printf("Panjang \"%s\" = %zu\n", kota, strlen(kota));
printf("Ukuran array kota = %zu byte\n", sizeof kota);
printf("Panjang string kosong = %zu\n", strlen(kosong));
return 0;
}Panjang "Bandung" = 7
Ukuran array kota = 8 byte
Panjang string kosong = 0Angka 7 dan 8 pada keluaran di atas menunjukkan perbedaan panjang string dan ukuran arraynya. strlen bekerja dengan menelusuri byte satu per satu sampai menemukan '\0', sehingga biayanya sebanding dengan panjang string. Memanggilnya di setiap putaran perulangan berarti menelusuri ulang string itu terus-menerus, sehingga hasilnya sebaiknya disimpan bila dipakai berkali-kali. Apabila stringnya memuat karakter non-ASCII yang tersimpan dalam lebih dari satu byte, hasilnya menghitung byte dan bukan jumlah huruf yang terlihat.
Tipe size_t tidak memiliki nilai negatif. Ekspresi seperti strlen(s) - 10 pada string pendek tidak menghasilkan angka negatif, melainkan bilangan besar karena nilai tak bertandanya melingkar (wrap around). Perbandingan yang aman adalah menyingkirkan pengurangan tersebut, misalnya menuliskan strlen(s) >= 10 dan bukan strlen(s) - 10 >= 0.
Menyalin dan menggabungkan dengan strcpy dan strcat#
Fungsi strcpy menyalin seluruh isi string sumber, termasuk penanda akhirnya, ke tujuan. Fungsi strcat menempelkan string sumber ke akhir string tujuan. Keduanya tidak memeriksa kapasitas tujuan, sehingga ukurannya menjadi tanggung jawab penuh kode yang memanggilnya. Area memori bertipe array yang disiapkan untuk menampung string disebut buffer, dan nilai kembali kedua fungsi adalah pointer tujuan yang jarang diperlukan.
#include <stdio.h>
#include <string.h>
int main(void) {
char sumber[] = "Kelas C";
char salinan[16];
char sapaan[32] = "Halo, ";
strcpy(salinan, sumber);
strcat(sapaan, sumber);
printf("Salinan = %s\n", salinan);
printf("Sapaan = %s\n", sapaan);
return 0;
}Salinan = Kelas C
Sapaan = Halo, Kelas CPada program di atas, buffer salinan berukuran 16 byte cukup untuk teks tujuh karakter ditambah penandanya, dan buffer sapaan berukuran 32 byte cukup untuk hasil gabungan 13 karakternya. Hitungan untuk strcat serupa, yaitu panjang isi tujuan ditambah panjang sumber ditambah satu untuk '\0'.
Membandingkan isi dengan strcmp#
Fungsi strcmp membandingkan dua string karakter demi karakter dan nilai kembaliannya dinilai dari tandanya. Hasilnya negatif bila string pertama berada sebelum string kedua dalam urutan byte, nol bila isinya identik, dan positif bila berada sesudahnya. Nilai pastinya tidak ditentukan standar, sehingga kode hanya boleh bergantung pada tandanya dan bukan angkanya.
#include <stdio.h>
#include <string.h>
int main(void) {
char a[] = "apel";
char b[] = "jeruk";
if (strcmp(a, b) < 0) {
printf("\"%s\" berada sebelum \"%s\" dalam urutan kamus\n", a, b);
}
if (strcmp(a, a) == 0) {
printf("Dua teks yang identik menghasilkan nilai 0\n");
}
if (strcmp("Apel", "apel") < 0) {
printf("Huruf besar dibandingkan sebelum huruf kecil\n");
}
return 0;
}"apel" berada sebelum "jeruk" dalam urutan kamus
Dua teks yang identik menghasilkan nilai 0
Huruf besar dibandingkan sebelum huruf kecilUrutan byte yang dipakai strcmp mengikuti tabel karakter pada lingkungan tempat program berjalan, dan pada ASCII huruf besar berada sebelum huruf kecil. Akibatnya, “Apel” berada sebelum “apel”, sehingga perilaku ini perlu diperhatikan ketika mengurutkan teks yang membedakan huruf besar-kecil. Apabila perbandingan hanya perlu mencakup sebagian awal teks, variannya strncmp menambahkan parameter jumlah karakter yang dibandingkan, dan tandanya dipakai dengan cara yang sama.
Mencari teks dengan strstr#
Fungsi strstr mencari kemunculan pertama sebuah substring, yaitu potongan string, di dalam string lain. Argumen pertamanya adalah string yang ditelusuri dan argumen keduanya adalah teks yang dicari. Nilai kembaliannya berupa pointer ke posisi kemunculan itu, atau NULL bila tidak ditemukan, dan selisih pointer hasil dengan pointer awal string memberikan indeks kemunculannya.
Pointer yang dikembalikan menunjuk ke dalam string asal dan bukan salinan, sehingga perubahan lewat pointer itu mengubah kalimat aslinya. Bila hasil pencarian perlu diolah tanpa menyentuh sumbernya, salin terlebih dahulu ke buffer sendiri.
#include <stdio.h>
#include <string.h>
int main(void) {
char kalimat[] = "belajar string di bahasa C";
char *posisi = strstr(kalimat, "string");
if (posisi != NULL) {
printf("Kata ditemukan pada indeks %td\n", posisi - kalimat);
printf("Sisa kalimat: \"%s\"\n", posisi);
}
if (strstr(kalimat, "STRING") == NULL) {
printf("Pencarian \"STRING\" tidak menemukan apa pun\n");
}
return 0;
}Kata ditemukan pada indeks 8
Sisa kalimat: "string di bahasa C"
Pencarian "STRING" tidak menemukan apa punPencarian strstr sensitif terhadap huruf besar-kecil, sehingga kata “STRING” tidak akan ditemukan di dalam “string”. Pointer NULL yang dikembalikan pada kegagalan wajib diperiksa sebelum dipakai, karena membaca lewat pointer NULL membuat program berhenti. Apabila kemunculan kedua perlu dicari, pencarian dilanjutkan dari satu posisi setelah pointer hasil pertama.
Mencegah buffer overflow#
Buffer adalah area memori berukuran tetap yang disiapkan untuk menampung data, dan array char adalah bentuknya yang paling umum. Buffer overflow terjadi ketika data yang ditulis melebihi kapasitas buffer, dan strcpy sering menjadi penyebabnya.
// tidak-dijalankan
char kata[8];
strcpy(kata, "Pemrograman"); /* butuh 12 byte, tersedia 8 */Pola pada contoh di atas menulis melebihi buffer tanpa peringatan apa pun pada saat kompilasi maupun saat berjalan. Kebiasaan yang aman adalah mengukur panjang sumber terlebih dahulu dan menyalin hanya bila tujuan pasti cukup, seperti pada program berikut.
#include <stdio.h>
#include <string.h>
/* menyalin teks hanya bila tujuan cukup; mengembalikan 1 bila berhasil */
int salinAman(char *tujuan, size_t kapasitas, const char *sumber) {
if (strlen(sumber) + 1 > kapasitas) {
return 0;
}
strcpy(tujuan, sumber);
return 1;
}
int main(void) {
char sumber[] = "Pemrograman C";
char tujuan[8];
if (salinAman(tujuan, sizeof tujuan, sumber)) {
printf("Isi tujuan: %s\n", tujuan);
} else {
printf("Sumber terlalu panjang untuk buffer %zu byte\n", sizeof tujuan);
}
return 0;
}Sumber terlalu panjang untuk buffer 8 byteAlternatif lain adalah snprintf dari header stdio.h, yang menuliskan paling banyak kapasitas dikurangi satu byte dan selalu mengakhiri hasilnya dengan '\0'. Fungsi salinAman pada program di atas menerapkan prinsip yang sama secara eksplisit, yaitu memeriksa dulu dan menolak menyalin bila tidak muat. Prinsip yang sama juga berlaku untuk masukan dari pengguna, yaitu membatasi panjang bacaan agar buffer tidak pernah kelebihan isi.
Kesalahan umum#
- Membandingkan string dengan operator
==. Perbandingan itu menguji kesamaan alamat dan bukan isi, sehingga hasilnya tidak sesuai harapan. Gunakanstrcmpdan uji tandanya. - Lupa menyisakan satu byte untuk
'\0'. Array sepanjang teksnya tepat membuat penanda akhir tidak kebagian tempat, dan string yang dihasilkan tidak sah. - Menempelkan teks dengan
strcatke tujuan yang belum berisi string. Fungsi itu mencari akhir string tujuan, sehingga buffer yang tidak diinisialisasi membuat pencariannya berjalan ke memori di luar buffer. - Mengira seluruh fungsi pada header ini memeriksa kapasitas. Fungsi tanpa batas panjang mengandalkan disiplin pemanggil, sedangkan varian dengan batas panjang hanya aman bila perilakunya dipahami dengan benar.
Ringkasan#
strlenmenghitung panjang string tanpa penanda akhir dan mengembalikansize_t.strcpydanstrcattidak memeriksa kapasitas tujuan, sehingga ukuran buffer dihitung manual, yaitu panjang isi ditambah satu.strcmpmengembalikan tanda urutan dua string, dan operator==tidak dapat dipakai untuk membandingkan isi.strstrmengembalikan pointer kemunculan pertama atauNULL, dan hasilnya wajib diperiksa sebelum dipakai.
Referensi#
- strlen(3) — Linux manual page — Dokumentasi strlen beserta catatan perilakunya.
- strcpy(3) — Linux manual page — Dokumentasi strcpy untuk penyalinan string.
- strcat(3) — Linux manual page — Dokumentasi strcat untuk penggabungan string.
- strcmp(3) — Linux manual page — Dokumentasi fungsi perbandingan string.
- strstr(3) — Linux manual page — Dokumentasi pencarian substring.