Array adalah struktur data paling dasar: kumpulan elemen bertipe sama yang tersimpan berurutan di memori. Banyak algoritma klasik — sorting, searching, prefix sum — memodelkan input sebagai array. C++ mewarisi array gaya C yang sangat efisien namun punya banyak keterbatasan. Pada Chapter ini kita akan mempelajari cara mendeklarasikan dan mengakses C-style array, lalu memahami mengapa di DSA modern kita lebih memilih std::vector atau std::array.
Deklarasi dan Akses #
C-style array dideklarasikan dengan tipe dan ukuran konstan dalam tanda kurung siku. Indeks dimulai dari 0. Elemen diakses dengan array[indeks].
Mekanisme: Penyimpanan Berurutan di Memori #
Elemen array C diletakkan berurutan di memori tanpa celah. Untuk int data[5] di mana sizeof(int) == 4, total memori yang dipakai adalah 20 byte. Alamat data[i] sama dengan data + i * sizeof(int). Inilah sebabnya akses data[i] sangat cepat: satu operasi perkalian dan penambahan alamat.
Kode: Deklarasi dan Iterasi Array #
#include <iostream>
int main() {
int data[5] = {10, 20, 30, 40, 50};
std::cout << "data[0] = " << data[0] << '\n';
std::cout << "data[4] = " << data[4] << '\n';
// Ukuran array gaya lama
std::size_t ukuran = sizeof(data) / sizeof(data[0]);
std::cout << "ukuran = " << ukuran << '\n';
// std::size sejak C++17
std::cout << "size = " << std::size(data) << '\n';
long long total = 0;
for (std::size_t i = 0; i < std::size(data); ++i) {
total += data[i];
}
std::cout << "total = " << total << '\n';
return 0;
}Output yang Dihasilkan:
data[0] = 10
data[4] = 50
ukuran = 5
size = 5
total = 150- Baris
int data[5] = {10, 20, 30, 40, 50};: deklarasi array dengan 5 elemen dan inisialisasi nilai. Bila kita menulisint data[5] = {10, 20};, sisanya otomatis0. - Baris
data[0]: akses elemen pertama. Indeks0karena alamat base sudah menunjuk elemen pertama tanpa offset. - Baris
sizeof(data) / sizeof(data[0]): trik klasik untuk memperoleh ukuran array — total byte dibagi byte per elemen. Hanya bekerja di scope deklarasi, bukan setelah array dilewatkan ke fungsi. - Baris
std::size(data): cara C++17 yang lebih aman dan ekspresif.
Array Multidimensi #
Array multidimensi dideklarasikan dengan dua pasang kurung siku, misalnya int matriks[3][4]. Penyimpanan tetap berurutan (row-major): seluruh baris pertama, lalu baris kedua, dst.
Kode: Matriks 3x3 #
#include <iostream>
int main() {
int m[3][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
// Akses elemen diagonal utama
std::cout << "diagonal:";
for (int i = 0; i < 3; ++i) {
std::cout << ' ' << m[i][i];
}
std::cout << '\n';
// Jumlah semua elemen
long long total = 0;
for (int i = 0; i < 3; ++i)
for (int j = 0; j < 3; ++j)
total += m[i][j];
std::cout << "total = " << total << '\n';
return 0;
}Output yang Dihasilkan:
diagonal: 1 5 9
total = 45- Baris
int m[3][3] = {{1,2,3}, ...};: matriks 3x3 dengan inisialisasi baris-per-baris. Setiap{}dalam mewakili satu baris. - Baris
m[i][i]: elemen diagonal utama — indeks baris sama dengan indeks kolom. - Loop bersarang: loop luar untuk baris, loop dalam untuk kolom. Total iterasi
3 * 3 = 9kali.
Keterbatasan: Array Decay #
Ketika array C-style dilewatkan ke fungsi, tipenya meluruh menjadi pointer ke elemen pertama. Akibatnya, fungsi tidak tahu ukuran asli array, dan sizeof di dalam fungsi hanya mengembalikan ukuran pointer.
Mekanisme: Pointer Decay #
Parameter int arr[] di signature fungsi sebenarnya diinterpretasikan sebagai int* arr. Semua informasi ukuran hilang. Inilah alasan fungsi C klasik seperti std::qsort meminta parameter tambahan berupa jumlah elemen.
Kode: Ukuran yang Hilang #
#include <iostream>
void cetak(int arr[]) {
// sizeof(arr) di sini = sizeof(int*), bukan ukuran array!
std::cout << "sizeof di fungsi = " << sizeof(arr) << '\n';
std::cout << "tidak tahu panjang asli\n";
}
int main() {
int data[5] = {1, 2, 3, 4, 5};
std::cout << "sizeof di main = " << sizeof(data) << '\n';
cetak(data);
return 0;
}Output yang Dihasilkan:
sizeof di main = 20
sizeof di fungsi = 8
tidak tahu panjang asli- Baris
sizeof(data)dimain:datamasih berupa array —5 * sizeof(int) = 20byte. - Baris
sizeof(arr)dicetak:arrsudah meluruh menjadiint*— ukurannya8byte (pointer di sistem 64-bit), bukan ukuran array asli. - Akibatnya, fungsi penerima array C-style harus diberi tahu ukuran secara terpisah melalui parameter lain.
Batas Ukuran Statis #
C-style array dialokasikan di stack bila dideklarasikan secara lokal. Stack berukuran terbatas (biasanya 1–8 MB per thread), sehingga array besar seperti int data[10'000'000] dapat memicu stack overflow.
Mengapa Beralih ke std::vector dan std::array #
Tabel berikut merangkum alasan perpindahan dari C-style array ke container STL:
| Aspek | C-style array | std::array<T,N> | std::vector<T> |
|---|---|---|---|
| Ukuran | Tetap, di stack | Tetap, di stack | Dinamis, di heap |
| Tahu ukuran sendiri | Hanya di scope asal | Ya (size()) | Ya (size()) |
| Aman dari decay | Tidak | Ya | Ya |
Bisa di-copy dengan = | Tidak langsung | Ya | Ya |
| Iterator STL | Tidak langsung | Ya | Ya |
std::array adalah pembungkus tipis di atas array C dengan ukuran tetap — pilihan ideal bila ukuran diketahui saat kompilasi dan kita ingin antarmuka yang konsisten dengan STL. std::vector menyediakan ukuran dinamis dengan antarmuka yang sama.
Ringkasan #
- C-style array efisien dan ringan, tetapi ukurannya tetap dan tidak tahu panjangnya sendiri setelah decay.
sizeof(arr) / sizeof(arr[0])ataustd::size(arr)hanya bekerja di scope deklarasi.- Array multidimensi disimpan dalam row-major order.
- Array decay menjadi pointer saat dilewatkan ke fungsi — informasi ukuran hilang.
- Untuk DSA modern, utamakan
std::vector(dinamis) ataustd::array(statis) yang aman dan konsisten dengan STL.