Setelah memahami bahwa string di C adalah array char yang diakhiri null terminator, pertanyaan berikutnya adalah: bagaimana cara mendeklarasikan variabel string? Ada beberapa pola deklarasi yang masing-masing memiliki implikasi berbeda pada alokasi memori, mutabilitas, dan ukuran buffer. Pilihan pola yang tepat menentukan apakah string bisa dimodifikasi, apakah ukuran buffer tetap atau dinamis, dan apakah buffer berada di stack, data segment, atau memori lainnya. Pada chapter ini kita akan menelusuri tiga pola deklarasi utama: array dengan ukuran otomatis, array dengan ukuran eksplisit, dan pointer ke string literal. Kita juga akan membahas apa yang terjadi pada byte-byte sisa ketika buffer lebih besar dari initializer.
Deklarasi Array char Tiga Pola #
Cara paling umum mendeklarasikan string di C adalah dengan array char. Tiga variasi yang sering dijumpai:
#include <stdio.h>
int main(void) {
/* Deklarasi dengan ukuran eksplisit */
char nama[10] = "Budi";
/* Deklarasi dengan ukuran otomatis dari initializer */
char kota[] = "Bandung";
/* Deklarasi dengan initializer list (harus sertakan '\0') */
char inisial[] = {'I', 'd', '\0'};
printf("nama = %s\n", nama);
printf("kota = %s\n", kota);
printf("inisial = %s\n", inisial);
printf("sizeof nama = %zu\n", sizeof nama);
printf("sizeof kota = %zu\n", sizeof kota);
printf("sizeof inisial = %zu\n", sizeof inisial);
return 0;
}Output yang Dihasilkan:
nama = Budi
kota = Bandung
inisial = Id
sizeof nama = 10
sizeof kota = 8
sizeof inisial = 3Mari kita telaah baris-baris kode di atas:
- Baris 5 (
char nama[10] = "Budi";): kita mendeklarasikan array sepanjang 10 byte dan menginisialisasi 5 byte pertama dengan"Budi"(termasuk null terminator). Lima byte sisanya otomatis diisi0oleh compiler karena aturan inisialisasi parsial C. - Baris 8 (
char kota[] = "Bandung";): kita tidak menyebutkan ukuran. Compiler menghitung panjang initializer ("Bandung"= 7 karakter + 1 null terminator = 8 byte) dan mengalokasikan array sepanjang 8 byte. - Baris 11 (
char inisial[] = {'I', 'd', '\0'};): kita menggunakan initializer list (bukan string literal). Daftar eksplisit harus menyertakan'\0'bila ingin memperlakukan array sebagai string. Compiler mengalokasikan tepat 3 byte. - Baris 17-19 (
printf("sizeof ...")): mencetak ukuran array.nama10 byte (sesuai deklarasi eksplisit),kota8 byte (otomatis dari initializer),inisial3 byte (jumlah elemen list).
Buffer Lebih Besar dan Lebih Kecil dari Initializer #
Saat kita mendeklarasikan array dengan ukuran eksplisit, ada dua skenario: buffer lebih besar dari initializer atau lebih kecil. Keduanya berperilaku berbeda.
#include <stdio.h>
#include <string.h>
int main(void) {
/* Buffer lebih besar dari string: byte sisanya di-nol-kan */
char buf1[10] = "ABC";
printf("sizeof buf1 = %zu\n", sizeof buf1);
printf("buf1 bytes : %d %d %d %d %d %d\n",
buf1[0], buf1[1], buf1[2], buf1[3], buf1[4], buf1[9]);
/* Buffer terlalu kecil compile error:
char buf2[3] = "ABC"; * butuh 4 byte (A B C \0) *
*/
/* Array tak terinisialisasi: isi awal tidak menentu */
char buf3[8];
buf3[0] = 'H';
buf3[1] = 'i';
buf3[2] = '\0';
printf("buf3 sebagai string = %s\n", buf3);
/* strcpy ke buffer yang sudah dialokasikan */
char buf4[20];
strcpy(buf4, "Belajar C");
printf("buf4 = %s (panjang %zu)\n", buf4, strlen(buf4));
return 0;
}Output yang Dihasilkan:
sizeof buf1 = 10
buf1 bytes : 65 66 67 0 0 0
buf3 sebagai string = Hi
buf4 = Belajar C (panjang 9)Pada buf1[10] = "ABC", compiler menempatkan A, B, C, '\0' di empat byte pertama, lalu mengisi enam byte sisanya dengan 0. Baris printf("buf1 bytes : %d %d %d %d %d %d\n", ...) menampilkan nilai numerik byte ke-0 sampai ke-4 dan ke-9: semuanya 0 setelah posisi ke-3. Buffer buf3[8] dideklarasikan tanpa initializer sehingga isi awalnya tidak menentu—bila kita langsung mencetaknya sebagai string, output tidak terduga. Karena itu kita wajib menulis buf3[2] = '\0'; sebelum memperlakukannya sebagai string. Buffer buf4[20] adalah pola umum: alokasikan buffer kosong dengan ukuran yang cukup, lalu isi lewat strcpy atau pembacaan input.
Pointer ke String Literal #
Cara kedua mendeklarasikan “string” adalah lewat pointer char * yang menunjuk ke string literal. Tampak mirip secara sintaksis tetapi berperilaku sangat berbeda.
#include <stdio.h>
int main(void) {
/* Pointer menunjuk ke string literal */
const char *pesan = "Halo dari pointer";
/* Array char dengan isi yang sama */
char salinan[] = "Halo dari pointer";
/* Keduanya bisa dibaca dengan %s */
printf("pesan = %s\n", pesan);
printf("salinan = %s\n", salinan);
/* sizeof: pointer vs array */
printf("sizeof pesan = %zu (ukuran pointer)\n", sizeof pesan);
printf("sizeof salinan = %zu (ukuran array)\n", sizeof salinan);
return 0;
}Output yang Dihasilkan:
pesan = Halo dari pointer
salinan = Halo dari pointer
sizeof pesan = 8 (ukuran pointer)
sizeof salinan = 18 (ukuran array)Pada const char *pesan = "Halo dari pointer";, compiler menempatkan literal di read-only data segment (memori hanya-baca). Variabel pesan sendiri hanyalah sebuah pointer (8 byte pada x86-64) yang menyimpan alamat byte pertama literal tersebut. Pada char salinan[] = "Halo dari pointer";, compiler mengalokasikan array 18 byte (17 karakter + null terminator) di stack dan menyalin byte per byte dari literal ke array tersebut. Konsekuensinya: sizeof pesan = 8 (ukuran pointer), sizeof salinan = 18 (ukuran array). Selain itu, salinan bisa dimutasi (salinan[0] = 'h'; sah) sedangkan pesan[0] = 'h'; adalah undefined behavior karena literal berada di memori hanya-baca. Perbedaan mendasar inilah yang akan kita perdalam pada chapter String Literals dan Array char dan Pointer char.
Ringkasan Konsep #
Deklarasi string di C dapat dilakukan melalui tiga jalur utama: array dengan ukuran eksplisit (char nama[10] = "Budi";), array dengan ukuran otomatis (char kota[] = "Bandung";), atau pointer ke string literal (const char *pesan = "...";). Pilihan pola menentukan sifat mutabilitas, lokasi memori (stack vs read-only data segment), dan ukuran yang dilaporkan sizeof. Buffer lebih besar dari initializer otomatis di-pad dengan 0, sedangkan buffer lebih kecil dari initializer menyebabkan compile error. Bila kita butuh string yang dapat dimodifikasi sepanjang program berjalan, gunakan array char; bila kita hanya perlu membaca teks konstan, pointer ke string literal lebih ringkas. Pada chapter berikutnya kita akan membahas secara mendalam perilaku string literal di memori hanya-baca dan jebakan undefined behavior yang sering dialami pemula saat mencoba memutasi literal.