Deretan Nilai Berukuran Tetap
Array adalah blok memori yang bersambung dan menyimpan sejumlah nilai bertipe sama yang banyaknya tetap. Kalau satu int menyimpan satu angka, array int menyimpan banyak angka berderet, dan masing-masing bisa dijangkau dengan indeks berupa bilangan bulat.
Kamu mendeklarasikannya dengan menuliskan tipe elemen, sebuah nama, dan ukuran di dalam kurung siku. Tambahkan daftar dalam kurung kurawal untuk mengisinya:
Indeksnya dimulai dari nol: elemen pertama adalah scores[0], dan array berukuran 4 punya indeks valid 0 sampai 3. Ukurannya harus konstanta yang diketahui saat kompilasi. Kamu tidak bisa menulis int n = readInput(); int a[n]; dalam C++ standar (itu ekstensi yang tidak portabel). Kalau kamu butuh ukuran yang ditentukan saat program berjalan, pakai vector saja.
Menginisialisasi Array
Ada beberapa cara mengisi array, dan beberapa jalan pintas yang perlu kamu ketahui:
Jebakan yang perlu kamu ingat: kalau nilai awal yang kamu berikan lebih sedikit daripada ukurannya, sisanya di-value-initialize (nol untuk tipe numerik), bukan dibiarkan berisi sampah. Namun array yang sama sekali tanpa nilai awal, misalnya int e[4]; yang dideklarasikan sebagai variabel lokal, berisi nilai yang tidak tentu, dan membacanya sebelum diisi adalah undefined behavior.
Perulangan pada Array
Karena elemennya disimpan bersambung, kamu menelusuri array dengan loop indeks biasa. Supaya tetap di dalam batas, kendalikan loop dengan panjang array yang sebenarnya, bukan angka yang ditulis langsung:
sizeof(scores) adalah total jumlah byte seluruh array; membaginya dengan sizeof(scores[0]) (ukuran satu elemen) menghasilkan jumlah elemen. Sejak C++17 ada penulisan yang lebih rapi, std::size(scores), yang lebih mudah dibaca dan menolak dikompilasi kalau kamu tidak sengaja memberinya pointer. Lebih sederhana lagi kalau kamu hanya butuh nilainya: range-based for melewati perhitungan indeks sepenuhnya.
Jebakan Out of Bounds
C++ tidak mengecek batas pada arr[i]. Indeks yang melewati elemen terakhir tidak memunculkan exception atau peringatan; program membaca atau menulis memori apa pun yang kebetulan ada di sana. Inilah bug array yang paling umum, dan contoh klasik undefined behavior:
int a[3] = {1, 2, 3};
a[3] = 99; // OOPS - valid indices are 0..2, not 3
cout << a[5]; // garbage, crash, or corruption - undefined behavior
Kesalahan selisih satu (off-by-one) biasanya bersembunyi di kondisi loop. Menulis i <= n alih-alih i < n membuat loop berjalan satu langkah terlalu jauh dan menyentuh arr[n], yang sebenarnya tidak ada:
for (int i = 0; i <= n; i++) // BUG: when i == n, arr[i] is out of bounds
cout << arr[i];
Solusinya adalah disiplin dari bagian sebelumnya: buat loop dengan i < size, jangan pernah <=, dan hitung ukurannya dari array, bukan dengan mengetik ulang angka yang jadi tidak cocok saat kamu menambah elemen.
Array Decay: Pointer yang Tersembunyi
Perilaku array yang paling licin di C++ adalah decay (peluruhan): saat kamu meneruskan array ke sebuah fungsi, array itu diam-diam berubah menjadi pointer ke elemen pertamanya. Informasi ukurannya hilang, jadi sizeof di dalam fungsi mengukur pointer, bukan array.
Perhatikan bahwa int arr[] dan int* arr sama persis sebagai parameter fungsi; kurung sikunya hanya kosmetik. Karena jumlah elemennya hilang, kamu harus meneruskan panjangnya sendiri bersama array:
int sum(const int* arr, int n) {
int total = 0;
for (int i = 0; i < n; i++) total += arr[i];
return total;
}
Pola "teruskan pointer dan panjangnya, lalu berharap keduanya cocok" inilah hambatan yang mendorong sebagian besar kode C++ beralih ke std::array dan std::vector, yang membawa ukurannya sendiri dan tidak pernah meluruh.
Sekilas tentang Array Multidimensi
Kamu bisa menumpuk kurung siku untuk membuat grid. Array 2D sebenarnya adalah array berisi array, yang disusun baris demi baris di memori:
Akses dengan grid[row][col]. Peringatan soal batas dan decay tetap berlaku, bahkan lebih parah, karena meneruskan array 2D ke fungsi mengharuskan kamu menuliskan setiap dimensi kecuali yang pertama (void f(int g[][3])). Untuk apa pun yang lebih dari grid kecil berukuran tetap, vector berisi vector jauh lebih kecil kemungkinan salahnya.
Berikutnya: Vector
Array mentah memang cepat dan bisa ditebak, tetapi ukurannya yang tetap, tidak adanya pengecekan batas, dan perilakunya yang meluruh menjadi pointer membuatnya merepotkan untuk kode sehari-hari. Berikutnya kita akan berkenalan dengan std::vector: array yang bisa berubah ukuran, membesar sesuai kebutuhan, mengingat ukurannya sendiri, dan langsung cocok dengan algoritma STL. Kamu mendapat hampir semua yang ditawarkan array, dengan jauh lebih sedikit cara untuk mencelakai diri sendiri.
Pertanyaan yang sering diajukan
Bagaimana cara mendeklarasikan dan menginisialisasi array di C++?
Tulis tipe elemennya, sebuah nama, dan ukurannya di dalam kurung siku, lalu (opsional) daftar dalam kurung kurawal: int scores[4] = {90, 75, 100, 60};. Kamu boleh tidak menulis ukurannya kalau memberikan nilai awal: int scores[] = {90, 75, 100, 60}; membiarkan compiler menghitungnya untukmu.
Bagaimana cara mendapatkan panjang array di C++?
Untuk array asli yang masih berada dalam scope, pakai std::size(arr) (C++17) atau sizeof(arr) / sizeof(arr[0]). Cara ini tidak berfungsi lagi setelah array meluruh menjadi pointer (misalnya di dalam fungsi yang menerima int arr[]), karena di sana sizeof memberikan ukuran pointer, bukan ukuran array.
Apa yang terjadi kalau array diakses di luar batas di C++?
Itu undefined behavior. C++ tidak mengecek batas pada arr[i], jadi membaca atau menulis melewati ujungnya bisa membuat program crash, mengembalikan nilai sampah, atau diam-diam merusak memori di sekitarnya. Selalu jaga indeksmu di rentang 0 sampai size - 1.