Dalam banyak bahasa pemrograman tinggi seperti Python atau Java, string adalah tipe data primitif yang mengetahui panjangnya sendiri. Di C, tidak ada tipe string bawaan. Yang ada hanyalah tipe char (satu karakter) dan array dari char. Sebuah “string” di C sebenarnya adalah konvensi: deretan byte char yang diakhiri oleh karakter khusus bernama null terminator ('\0'). Konvensi sederhana inilah yang dipakai seluruh standard library C—mulai dari printf("%s"), strlen, strcpy, hingga strcmp. Pada chapter ini kita akan menelusuri apa itu string di C, bagaimana compiler menyimpannya di memori, dan bagaimana kita mengaksesnya baik per byte maupun sebagai satu kesatuan utuh.

String sebagai Array char #

String di C adalah array of char yang byte terakhirnya bernilai 0 (karakter '\0'). Tipe ini tidak membawa informasi panjang; semua fungsi string library mencari akhir string dengan cara mengiterasi byte demi byte sampai menemui '\0'. Karena itu, setiap buffer yang ingin diperlakukan sebagai string wajib menyediakan ruang untuk null terminator.

Kita dapat mengakses string dengan dua cara: indeks array biasa (s[i]) atau lewat pointer arithmetic. Keduanya ekuivalen karena nama array di C decay menjadi pointer ke elemen pertama saat dipakai sebagai ekspresi.

c
#include <stdio.h>

int main(void) {
    /* String disimpan sebagai array char */
    char nama[] = "Budi";

    /* Akses karakter per karakter seperti array biasa */
    printf("nama[0]  = %c\n", nama[0]);
    printf("nama[1]  = %c\n", nama[1]);
    printf("nama[2]  = %c\n", nama[2]);
    printf("nama[3]  = %c\n", nama[3]);
    printf("nama[4]  = %d (kode ASCII null terminator)\n", nama[4]);

    /* Cetak sebagai string utuh menggunakan %s */
    printf("Nama: %s\n", nama);
    return 0;
}

Output yang Dihasilkan:

text
nama[0]  = B
nama[1]  = u
nama[2]  = d
nama[3]  = i
nama[4]  = 0 (kode ASCII null terminator)
Nama: Budi

Mari kita telaah baris-baris kode di atas:

  1. Baris 5 (char nama[] = "Budi";): compiler mengalokasikan array char sepanjang 5 byte di stack. Empat byte pertama berisi kode ASCII 'B', 'u', 'd', 'i'. Byte kelima otomatis diisi '\0' (nilai 0) karena initializer berupa string literal.
  2. Baris 8-11 (printf("nama[0] = %c\n", ...)): kita membaca karakter satu per satu dengan indeks. Format specifier %c mencetak satu karakter.
  3. Baris 12 (printf("nama[4] = %d ...", nama[4])): kita membaca byte kelima sebagai integer (%d) untuk membuktikan bahwa compiler memang menempatkan 0 di sana. Inilah yang disebut null terminator.
  4. Baris 15 (printf("Nama: %s\n", nama)): format specifier %s memerintahkan printf mengiterasi byte mulai dari nama[0], mencetak satu per satu, dan berhenti tepat ketika menemui byte 0. Tanpa null terminator, printf akan terus membaca memori sampai kebetulan menemui byte 0—perilaku yang tidak terdefinisi (undefined behavior, UB).

Menghitung Panjang String Manual #

Karena string tidak menyimpan panjangnya sendiri, kita bisa menghitung panjang dengan mengiterasi sampai menemui null terminator. Standard library C menyediakan fungsi strlen (akan dibahas pada chapter terpisah), tetapi memahami implementasi manual akan memperkuat intuisi tentang cara kerja string.

c
#include <stdio.h>

/* Fungsi hitung panjang manual */
size_t panjang_string(const char *s) {
    size_t n = 0;
    while (s[n] != '\0') {
        n++;
    }
    return n;
}

int main(void) {
    char kota[] = "Bandung";
    char kosong[] = "";

    printf("Panjang \"Bandung\" = %zu\n", panjang_string(kota));
    printf("Panjang \"\"        = %zu\n", panjang_string(kosong));

    /* Iterasi karakter per karakter sampai null terminator */
    for (size_t i = 0; kota[i] != '\0'; i++) {
        printf("kota[%zu] = %c (ASCII %d)\n", i, kota[i], kota[i]);
    }
    return 0;
}

Output yang Dihasilkan:

text
Panjang "Bandung" = 7
Panjang ""        = 0
kota[0] = B (ASCII 66)
kota[1] = a (ASCII 97)
kota[2] = n (ASCII 110)
kota[3] = d (ASCII 100)
kota[4] = u (ASCII 117)
kota[5] = n (ASCII 110)
kota[6] = g (ASCII 103)

Pada fungsi panjang_string di atas, kita mengiterasi indeks n mulai dari 0 dan menambah satu setiap kali byte di s[n] bukan '\0'. Saat byte bernilai '\0', perulangan berhenti dan n berisi jumlah karakter sebelum null terminator. String kosong "" memiliki panjang 0 karena byte pertamanya sudah '\0'.

Tiga Cara Membentuk String #

Kita dapat membentuk string yang sama melalui tiga jalur: string literal, initializer list, atau pengisian byte per byte. Hasil akhirnya identik di mata fungsi string library, tetapi cara compiler mengelola memorinya berbeda.

c
#include <stdio.h>

int main(void) {
    /* Tiga cara membentuk string "Halo" */
    char s1[] = "Halo";
    char s2[] = {'H','a','l','o','\0'};
    char s3[5];
    s3[0] = 'H';
    s3[1] = 'a';
    s3[2] = 'l';
    s3[3] = 'o';
    s3[4] = '\0';

    printf("s1 = %s\n", s1);
    printf("s2 = %s\n", s2);
    printf("s3 = %s\n", s3);

    /* sizeof array mencakup null terminator */
    printf("sizeof s1 = %zu byte\n", sizeof s1);
    return 0;
}

Output yang Dihasilkan:

text
s1 = Halo
s2 = Halo
s3 = Halo
sizeof s1 = 5 byte

Pada s1, compiler otomatis menyisipkan '\0' di akhir literal. Pada s2, kita harus menuliskan '\0' secara eksplisit dalam initializer list—bila tidak, array hanya berisi 4 byte tanpa null terminator dan tidak boleh diperlakukan sebagai string. Pada s3, kita mengisi byte demi byte secara manual; ini adalah pola yang umum dipakai ketika kita membangun string dari input dinamis. sizeof s1 bernilai 5 karena array menyimpan 4 karakter ditambah 1 byte null terminator.

Ringkasan Konsep #

String di C bukan tipe data terpisah melainkan konvensi: array of char yang diakhiri byte 0 (null terminator). Karena string tidak menyimpan panjangnya sendiri, semua fungsi standard library yang memproses string mengiterasi byte demi byte sampai menemui null terminator. Konsekuensi praktisnya: setiap buffer yang ingin menjadi string harus menyediakan ruang ekstra satu byte untuk '\0', dan setiap penulisan string baru wajib diakhiri dengan '\0' agar printf, strlen, strcpy, dan kawan-kawan berhenti pada posisi yang benar. Pada chapter-chapter berikutnya kita akan menelusuri detail null terminator, deklarasi string, string literal, dan fungsi-fungsi string library yang menyusun ekosistem pemrosesan teks di C.