Array hanya bermanfaat jika kita bisa membaca dan mengubah isinya secara tepat. Kunci aksesnya satu: indeks. Elemen pertama berindeks 0, elemen terakhir berindeks jumlah - 1, dan setiap elemen di antaranya dijangkau dengan menuliskan posisinya di dalam kurung siku. Aturan sederhana ini punya sisi gelap yang wajib dipahami sejak dini: C++ tidak memeriksa batas indeks pada array C-style, sehingga akses di luar batas menjadi undefined behavior — program boleh crash, boleh diam-diam menghitung salah, atau boleh tampak normal. Pada Chapter ini kita berlatih akses yang benar, membiasakan pola penulisan yang aman, dan memahami apa yang sebenarnya terjadi saat indeks melenceng.

Membaca dan Mengubah Elemen #

Program berikut merangkum operasi akses yang paling sering dipakai: membaca satu elemen, mengubah satu elemen, menelusuri seluruh array, dan menjumlahkan isinya:

cpp
#include <iostream>

int main() {
    int nilai[5] = {70, 85, 60, 90, 75};
    const int jumlah = sizeof(nilai) / sizeof(nilai[0]);  // 5

    // membaca elemen tertentu lewat indeks
    std::cout << "Elemen pertama : " << nilai[0] << "\n";
    std::cout << "Elemen terakhir: " << nilai[jumlah - 1] << "\n";

    // mengubah satu elemen lewat indeks
    nilai[2] = 65;  // koreksi nilai ujian ketiga

    // menelusuri semua elemen dengan batas yang benar: 0 sampai jumlah-1
    for (int i = 0; i < jumlah; ++i) {
        std::cout << "nilai[" << i << "] = " << nilai[i] << "\n";
    }

    // menjumlahkan seluruh elemen
    int total = 0;
    for (int i = 0; i < jumlah; ++i) {
        total += nilai[i];
    }
    std::cout << "Total nilai    : " << total << "\n";

    return 0;
}

Output yang Dihasilkan:

text
Elemen pertama : 70
Elemen terakhir: 75
nilai[0] = 70
nilai[1] = 85
nilai[2] = 65
nilai[3] = 90
nilai[4] = 75
Total nilai    : 385

Mari kita bedah:

  1. Baris 6 (const int jumlah = ...): kita menghitung jumlah elemen sekali dan menyimpannya sebagai konstanta, sehingga batas loop tidak pernah salah tulis. Ini mengulang trik sizeof dari Chapter Array C Style.
  2. Baris 9-10 (nilai[0], nilai[jumlah - 1]): membaca elemen adalah ekspresi biasa — indeks bisa berupa angka langsung maupun ekspresi. Elemen terakhir selalu berada di indeks jumlah - 1, bukan jumlah.
  3. Baris 13 (nilai[2] = 65;): menulis elemen memakai indeks yang sama seperti membaca. Ekspresi nilai[2] di sisi kiri = berperan sebagai lvalue, yaitu alamat penyimpanan yang menerima nilai baru.
  4. Baris 16-19 (loop penelusuran): kondisi i < jumlah menjaga indeks tetap di 0..4. Inilah pola penelusuran array yang harus dibiasakan: mulai dari 0, berhenti sebelum jumlah.
  5. Baris 22-27 (akumulasi): variabel total memulai dari 0 lalu menambah setiap elemen. Pola akumulasi seperti ini mendasar untuk menghitung rata-rata, maksimum, dan pencarian.

Undefined Behavior Saat Indeks Melenceng #

Pada banyak bahasa (Java, Python, C#), membaca di luar batas melempar pengecualian yang jelas. C++ memilih jalan lain demi kecepatan: compiler tidak menambahkan pemeriksaan batas untuk array C-style. Ekspresi nilai[5] pada array berukuran lima tetap diterima compiler dan diterjemahkan menjadi “baca 4 byte pada alamat elemen ke-6”. Memori di alamat itu bukan milik array kita — bisa jadi milik variabel lain di sebelahnya, atau area memori yang dilindungi sistem.

Kode seperti ini adalah kesalahan serius, dan kita tampilkan sebagai contoh bermasalah tanpa mengklaim hasil eksekusinya:

cpp oob.cpp — kode BERMASALAH, jangan ditiru
#include <iostream>

int main() {
    int nilai[5] = {70, 85, 60, 90, 75};

    // SALAH: indeks 5 berada di luar batas (sah: 0 sampai 4)
    std::cout << nilai[5] << "\n";
    return 0;
}

Apa yang terjadi saat program bermasalah ini dijalankan? Jawaban standarnya: tidak ada yang dijamin. Istilah resminya undefined behavior (perilaku tidak terdefinisi) — standar C++ tidak menentukan hasilnya, sehingga compiler bebas menganggap kode seperti itu tidak pernah terjadi. Pada percobaan kami, program ini tidak crash dan justru mencetak sebuah angka seolah normal, karena slot memori di belakang nilai[5] kebetulan berisi nol. Perilaku “tampak berjalan baik” inilah jebakan terburuk: kesalahan bisa lolos dari pengujian lalu muncul di mesin lain dengan hasil yang berbeda-beda.

Untuk mendeteksinya secara jelas, compiler GCC menyediakan sanitizer AddressSanitizer. Ketika kode bermasalah di atas dikompilasi dengan -fsanitize=address, program berhenti dan memberi laporan yang merujuk persis ke baris pelanggaran:

text Laporan AddressSanitizer (cuplikan; alamat berbeda antar mesin)
==13598==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7fb1eaa00034 ...
READ of size 4 at 0x7fb1eaa00034 thread T0
    #0 ... in main /tmp/oob.cpp:7
...
  This frame has 1 object(s):
    [32, 52) 'nilai' (line 4) <== Memory access at offset 52 overflows this variable
SUMMARY: AddressSanitizer: stack-buffer-overflow /tmp/oob.cpp:7 in main

Pesan stack-buffer-overflow dengan penanda overflows this variable menyebut nama array nilai dan posisi barisnya, sehingga kesalahan langsung ketemu. Pemeriksaan ini hanya aktif pada versi program yang dikompilasi dengan sanitizer; pada program biasa tidak ada penjaga semacam itu. Pembahasan lengkap undefined behavior dan alat deteksinya tersedia pada Section Keamanan dan Undefined Behavior.

Pola Akses yang Aman #

Berbekal pemahaman di atas, tiga kebiasaan berikut membuat akses array C-style kita terkendali. Pertama, selalu turunkan batas dari sizeof atau konstanta bernama — jangan magic number yang diketik terpisah dari deklarasi array. Kedua, gunakan kondisi i < jumlah (bukan i <= jumlah); kesalahan satu tanda ini sudah cukup melampaui batas. Ketiga, bila program berjalan di lingkungan yang kritis, kompilasi sesekali dengan -fsanitize=address,undefined untuk menangkap pelanggaran yang lolos mata.

Disiplin yang sama berlaku saat menulis ke elemen: nilai[jumlah] = 0; pada array berukuran jumlah sama berbahayanya dengan membaca — menimpa memori milik variabel lain. Karena tidak ada penjaga otomatis, banyak tim C++ memakai konvensi: array C-style hanya untuk data yang ukurannya jelas dari konteks, sedangkan koleksi umum diberikan ke std::array (Chapter std::array) yang punya anggota .at() dengan pemeriksaan batas sungguhan.

Chapter berikutnya membuka dimensi kedua: array multidimensi, tempat pola “mulai 0, kurang dari jumlah” diterapkan berlapis pada baris dan kolom.

Rujukan resmi: cppreference — Array declaration , cppreference — Undefined behavior .