Mata Kuliah: Struktur Data dan Algoritma
Kode: SDA201
SKS: 3 SKS (2 Teori + 1 Praktikum)
Pertemuan: 01
Topik: Pengantar Struktur Data dan Review C++ Lanjut
Capaian Pembelajaran: Sub-CPMK-1.1, Sub-CPMK-1.3 — Mampu menjelaskan konsep ADT dan menerapkan teknik pointer lanjut serta dynamic memory management
Estimasi Waktu Belajar: 7 jam
Referensi Utama: Cormen Ch.10; Weiss Ch.1; Hubbard Ch.1-2
Setelah menyelesaikan modul ini, mahasiswa diharapkan mampu:
new dan deleteDefinisi: Struktur data adalah cara mengorganisasikan, menyimpan, dan mengelola data dalam memori komputer sehingga dapat diakses dan dimodifikasi secara efisien.
Dalam konteks pemrograman, struktur data bukan hanya tentang “menyimpan data”, tetapi juga tentang:
Pemilihan struktur data yang tepat sangat mempengaruhi efisiensi program. Sebuah program dengan algoritma yang baik tetapi struktur data yang tidak tepat dapat berjalan sangat lambat, dan sebaliknya.
Bayangkan sebuah sistem Command, Control, Communications, Computers, Cyber, Intelligence, Surveillance, and Reconnaissance (C6ISR) yang harus mengelola ribuan data posisi unit militer secara real-time. Tanpa struktur data yang tepat:
Dengan struktur data yang tepat (misalnya hash table untuk pencarian cepat, atau tree untuk data hierarkis), operasi-operasi tersebut dapat dilakukan dalam waktu yang sangat singkat.

Gambar 1.1: Klasifikasi struktur data — Linear vs Non-Linear
| Jenis | Karakteristik | Contoh Penggunaan |
|---|---|---|
| Linear | Elemen tersusun berurutan, satu demi satu | Antrian pesan, history command |
| Non-Linear | Elemen dapat terhubung ke banyak elemen lain | Struktur organisasi, jaringan komunikasi |
Definisi: Abstract Data Type (ADT) adalah model matematis untuk tipe data yang didefinisikan oleh perilakunya (semantik) dari sudut pandang pengguna, khususnya dalam hal nilai yang mungkin, operasi yang dapat dilakukan, dan perilaku operasi tersebut.
ADT berbeda dengan struktur data konkret:
| Aspek | ADT | Struktur Data Konkret |
|---|---|---|
| Level | Abstrak/Konseptual | Implementasi |
| Fokus | APA yang dilakukan | BAGAIMANA melakukannya |
| Detail Implementasi | Tersembunyi | Terlihat |
| Contoh | Stack (konsep LIFO) | Array-based Stack, Linked Stack |
Setiap ADT memiliki tiga komponen utama:
Contoh ADT Stack:
ADT Stack:
Data:
- Kumpulan elemen dengan tipe T
Operasi:
- push(item): Menambah item ke puncak stack
- pop(): Menghapus dan mengembalikan item dari puncak
- peek()/top(): Melihat item di puncak tanpa menghapus
- isEmpty(): Mengecek apakah stack kosong
- size(): Mengembalikan jumlah elemen
Aturan:
- LIFO (Last In First Out)
- push lalu pop mengembalikan item yang sama
- pop pada stack kosong menghasilkan error
Soal: Sebutkan dan jelaskan tiga operasi dasar yang harus dimiliki oleh ADT Queue!
Penyelesaian:
ADT Queue memiliki tiga operasi dasar berikut:
Operasi tambahan yang sering disertakan: isEmpty(), size(), dan isFull() (untuk implementasi dengan kapasitas terbatas).
Soal: Jelaskan perbedaan antara ADT dan struktur data konkret dengan contoh!
Penyelesaian:
ADT adalah spesifikasi abstrak yang mendefinisikan:
Struktur Data Konkret adalah implementasi nyata dari ADT.
Contoh dengan ADT List:
| ADT List (Spesifikasi) | Implementasi Konkret |
|---|---|
insert(index, item) |
Array: geser elemen, masukkan di posisi |
| Linked List: buat node baru, hubungkan pointer | |
delete(index) |
Array: geser elemen ke kiri |
| Linked List: ubah pointer, dealokasi node | |
get(index) |
Array: akses langsung arr[index] |
| Linked List: traverse dari head |
Satu ADT (List) dapat memiliki banyak implementasi (Array-based, Linked List, dll), masing-masing dengan trade-off berbeda.
Definisi: Pointer adalah variabel yang menyimpan alamat memori dari variabel lain.
Pointer merupakan salah satu fitur paling powerful sekaligus berbahaya dalam C++. Pemahaman yang baik tentang pointer sangat penting untuk implementasi struktur data.
#include <iostream>
using namespace std;
int main() {
int nilai = 42; // Variabel biasa
int* ptr = &nilai; // Pointer yang menyimpan alamat 'nilai'
cout << "Nilai variabel: " << nilai << endl;
cout << "Alamat variabel: " << &nilai << endl;
cout << "Nilai pointer: " << ptr << endl;
cout << "Nilai yang ditunjuk: " << *ptr << endl;
return 0;
}
Output:
Nilai variabel: 42
Alamat variabel: 0x7ffd5e8c3a4c
Nilai pointer: 0x7ffd5e8c3a4c
Nilai yang ditunjuk: 42
| Operator | Nama | Fungsi | Contoh |
|---|---|---|---|
& |
Address-of | Mengambil alamat variabel | &x → alamat x |
* |
Dereference | Mengakses nilai di alamat | *ptr → nilai di ptr |
-> |
Arrow | Akses member via pointer | ptr->member |
Array dan pointer memiliki hubungan erat dalam C++:
#include <iostream>
using namespace std;
int main() {
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr; // Array name = alamat elemen pertama
// Akses menggunakan indeks
cout << "arr[2] = " << arr[2] << endl;
// Akses menggunakan pointer arithmetic
cout << "*(ptr + 2) = " << *(ptr + 2) << endl;
// Keduanya menghasilkan nilai yang sama: 30
return 0;
}
int arr[5] = {10, 20, 30, 40, 50};
int* ptr = arr;
ptr++; // Pindah ke elemen berikutnya (bukan +1 byte, tapi +sizeof(int))
ptr += 2; // Pindah 2 elemen ke depan
ptr--; // Pindah ke elemen sebelumnya

Gambar 1.2: Ilustrasi pointer arithmetic pada array integer
Soal: Apa output dari kode berikut?
int x = 10;
int* p = &x;
*p = 20;
cout << x << endl;
Penyelesaian:
Output: 20
Penjelasan langkah demi langkah:
int x = 10; → Variabel x dibuat dengan nilai 10int* p = &x; → Pointer p menyimpan alamat x*p = 20; → Nilai di alamat yang ditunjuk p (yaitu x) diubah menjadi 20cout << x << endl; → Mencetak nilai x, yang sekarang adalah 20Karena p menunjuk ke x, mengubah *p sama dengan mengubah x secara langsung.
Soal: Tuliskan fungsi yang menukar dua nilai integer menggunakan pointer!
Penyelesaian:
#include <iostream>
using namespace std;
void tukar(int* a, int* b) {
int temp = *a; // Simpan nilai di alamat a
*a = *b; // Copy nilai di alamat b ke alamat a
*b = temp; // Copy temp ke alamat b
}
int main() {
int x = 5, y = 10;
cout << "Sebelum: x = " << x << ", y = " << y << endl;
tukar(&x, &y); // Kirim alamat x dan y
cout << "Sesudah: x = " << x << ", y = " << y << endl;
return 0;
}
Output:
Sebelum: x = 5, y = 10
Sesudah: x = 10, y = 5
Fungsi menerima alamat variabel, sehingga perubahan yang dilakukan di dalam fungsi mempengaruhi variabel asli.
Definisi: Referensi adalah alias (nama lain) untuk variabel yang sudah ada. Setelah diinisialisasi, referensi selalu merujuk ke variabel yang sama.
int nilai = 42;
int& ref = nilai; // ref adalah alias untuk nilai
ref = 100; // Sama dengan nilai = 100
cout << nilai; // Output: 100
| Aspek | Pointer | Referensi |
|---|---|---|
| Inisialisasi | Bisa tanpa nilai awal | Harus langsung diinisialisasi |
| Null | Bisa null | Tidak bisa null |
| Reassignment | Bisa menunjuk ke variabel lain | Selalu merujuk ke variabel yang sama |
| Syntax | Perlu * dan & |
Langsung seperti variabel biasa |
| Memory | Memiliki alamat sendiri | Berbagi alamat dengan variabel asli |
#include <iostream>
using namespace std;
// Pass by value - tidak mengubah variabel asli
void tambahSatu_nilai(int x) {
x = x + 1;
}
// Pass by reference - mengubah variabel asli
void tambahSatu_ref(int& x) {
x = x + 1;
}
int main() {
int a = 5, b = 5;
tambahSatu_nilai(a);
tambahSatu_ref(b);
cout << "a = " << a << endl; // Output: 5 (tidak berubah)
cout << "b = " << b << endl; // Output: 6 (berubah)
return 0;
}
Soal: Apa perbedaan utama antara int* ptr dan int& ref?
Penyelesaian:
| Karakteristik | int* ptr (Pointer) |
int& ref (Referensi) |
|---|---|---|
| Definisi | Variabel yang menyimpan alamat | Alias untuk variabel lain |
| Dapat null | Ya, int* ptr = nullptr; |
Tidak, harus merujuk ke variabel valid |
| Dapat diubah | Ya, ptr = &other; |
Tidak, selalu merujuk ke variabel awal |
| Operator akses | *ptr untuk nilai |
Langsung ref |
| Ukuran memori | Memiliki alamat sendiri | Tidak menambah memori |
| Harus diinisialisasi | Tidak (tapi sebaiknya ya) | Ya, wajib |
Kapan menggunakan masing-masing:
Soal: Tuliskan fungsi yang menghitung panjang string C-style (char array) menggunakan pointer!
Penyelesaian:
#include <iostream>
using namespace std;
int hitungPanjang(const char* str) {
const char* ptr = str; // Pointer untuk traverse
// Traverse sampai menemukan null terminator
while (*ptr != '\0') {
ptr++;
}
// Panjang = selisih posisi akhir dan awal
return ptr - str;
}
int main() {
const char* pesan = "Struktur Data C++";
cout << "String: " << pesan << endl;
cout << "Panjang: " << hitungPanjang(pesan) << " karakter" << endl;
return 0;
}
Output:
String: Struktur Data C++
Panjang: 17 karakter
Penjelasan:
ptr dimulai dari awal string'\0')ptr - str memberikan jumlah karakterDalam C++, memori program dibagi menjadi beberapa segmen:
| Segmen | Karakteristik | Contoh |
|---|---|---|
| Stack | Otomatis dialokasi/dealokasi, ukuran terbatas, cepat | Variabel lokal, parameter fungsi |
| Heap | Manual dialokasi/dealokasi, ukuran besar, lebih lambat | Data dengan new, array dinamis |
| Data | Variabel global dan static | Global variables |
| Code | Instruksi program | Fungsi-fungsi |

Gambar 1.3: Perbandingan Stack dan Heap Memory
new dan deleteC++ menyediakan operator new untuk alokasi memori di heap dan delete untuk dealokasi:
#include <iostream>
using namespace std;
int main() {
// Alokasi single variable
int* ptr = new int; // Alokasi memori untuk satu integer
*ptr = 42;
cout << "Nilai: " << *ptr << endl;
delete ptr; // Dealokasi memori
// Alokasi dengan inisialisasi
int* ptr2 = new int(100);
cout << "Nilai: " << *ptr2 << endl;
delete ptr2;
return 0;
}
#include <iostream>
using namespace std;
int main() {
int ukuran;
cout << "Masukkan ukuran array: ";
cin >> ukuran;
// Alokasi array dinamis
int* arr = new int[ukuran];
// Mengisi array
for (int i = 0; i < ukuran; i++) {
arr[i] = i * 10;
}
// Menampilkan array
cout << "Isi array: ";
for (int i = 0; i < ukuran; i++) {
cout << arr[i] << " ";
}
cout << endl;
// Dealokasi array - PENTING: gunakan delete[]
delete[] arr;
return 0;
}
Penting: Untuk array yang dialokasikan dengan
new[], gunakandelete[]untuk dealokasi. Menggunakandelete(tanpa brackets) untuk array menyebabkan undefined behavior.
Soal: Apa perbedaan antara delete ptr dan delete[] ptr?
Penyelesaian:
| Operator | Penggunaan | Dealokasi |
|---|---|---|
delete ptr |
Untuk single object yang dialokasi dengan new |
Memanggil destructor satu kali, dealokasi satu objek |
delete[] ptr |
Untuk array yang dialokasi dengan new[] |
Memanggil destructor untuk setiap elemen, dealokasi seluruh array |
Contoh penggunaan yang benar:
// Single object
int* single = new int(42);
delete single; // BENAR
// Array
int* arr = new int[10];
delete[] arr; // BENAR
Konsekuensi kesalahan:
delete untuk array: Memory leak, undefined behaviordelete[] untuk single object: Undefined behaviorSoal: Buatlah program yang membuat array dinamis untuk menyimpan nilai sensor suhu, kemudian menghitung rata-ratanya!
Penyelesaian:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int jumlahSensor;
cout << "=== Sistem Monitoring Suhu ===" << endl;
cout << "Jumlah sensor: ";
cin >> jumlahSensor;
// Validasi input
if (jumlahSensor <= 0) {
cout << "Error: Jumlah sensor harus positif!" << endl;
return 1;
}
// Alokasi array dinamis
double* suhu = new double[jumlahSensor];
// Input data suhu
cout << "\nMasukkan data suhu:" << endl;
for (int i = 0; i < jumlahSensor; i++) {
cout << "Sensor " << (i + 1) << ": ";
cin >> suhu[i];
}
// Hitung rata-rata
double total = 0;
double suhuMax = suhu[0];
double suhuMin = suhu[0];
for (int i = 0; i < jumlahSensor; i++) {
total += suhu[i];
if (suhu[i] > suhuMax) suhuMax = suhu[i];
if (suhu[i] < suhuMin) suhuMin = suhu[i];
}
double rataRata = total / jumlahSensor;
// Tampilkan hasil
cout << "\n=== Laporan ===" << endl;
cout << fixed << setprecision(2);
cout << "Rata-rata: " << rataRata << "°C" << endl;
cout << "Suhu maksimum: " << suhuMax << "°C" << endl;
cout << "Suhu minimum: " << suhuMin << "°C" << endl;
// Dealokasi memori
delete[] suhu;
return 0;
}
Contoh Output:
=== Sistem Monitoring Suhu ===
Jumlah sensor: 5
Masukkan data suhu:
Sensor 1: 28.5
Sensor 2: 29.2
Sensor 3: 27.8
Sensor 4: 30.1
Sensor 5: 28.9
=== Laporan ===
Rata-rata: 28.90°C
Suhu maksimum: 30.10°C
Suhu minimum: 27.80°C
Definisi: Memory leak terjadi ketika memori yang dialokasikan di heap tidak pernah didealokasi, menyebabkan memori tersebut tidak dapat digunakan kembali.
Contoh memory leak:
void fungsiMasalah() {
int* data = new int[1000];
// ... melakukan operasi ...
// MASALAH: fungsi berakhir tanpa delete[]
// Memori 1000 integer hilang!
}
int main() {
for (int i = 0; i < 100000; i++) {
fungsiMasalah(); // Setiap panggilan = memory leak
}
// Program mungkin kehabisan memori!
return 0;
}
Penyebab umum memory leak:
delete atau delete[]Definisi: Dangling pointer adalah pointer yang menunjuk ke lokasi memori yang sudah tidak valid (sudah didealokasi atau di luar scope).
Contoh dangling pointer:
#include <iostream>
using namespace std;
int* buatDangling() {
int lokal = 42;
return &lokal; // BAHAYA! mengembalikan alamat variabel lokal
} // lokal dihancurkan saat fungsi berakhir
int main() {
int* ptr = new int(100);
delete ptr; // Memori didealokasi
// ptr sekarang adalah dangling pointer!
cout << *ptr; // UNDEFINED BEHAVIOR
int* danger = buatDangling(); // danger = dangling pointer
cout << *danger; // UNDEFINED BEHAVIOR
return 0;
}
#include <iostream>
using namespace std;
int main() {
// 1. Selalu inisialisasi pointer
int* ptr = nullptr;
// 2. Periksa sebelum menggunakan
if (ptr != nullptr) {
cout << *ptr << endl;
}
// 3. Set ke nullptr setelah delete
ptr = new int(42);
cout << *ptr << endl;
delete ptr;
ptr = nullptr; // Mencegah dangling pointer
// 4. Periksa lagi setelah operasi
if (ptr != nullptr) {
cout << *ptr << endl; // Tidak dieksekusi
}
return 0;
}

Gambar 1.4: Ilustrasi Memory Leak dan Dangling Pointer
Soal: Identifikasi semua masalah dalam kode berikut dan perbaiki!
void prosesData() {
int* data = new int[100];
// ... proses data ...
if (error) {
return; // Early return
}
delete[] data;
}
Penyelesaian:
Masalah yang teridentifikasi:
error bernilai true (early return tanpa dealokasi)error tidak didefinisikanKode yang diperbaiki:
void prosesData() {
int* data = new int[100];
bool error = false;
// ... proses data ...
// Misalkan terjadi error
error = true;
if (error) {
delete[] data; // Dealokasi sebelum return
return;
}
// Proses normal
delete[] data;
}
Solusi lebih baik dengan RAII pattern:
#include <memory>
void prosesData() {
// unique_ptr otomatis dealokasi saat keluar scope
std::unique_ptr<int[]> data(new int[100]);
// ... proses data ...
if (error) {
return; // Aman, unique_ptr akan dealokasi
}
// Tidak perlu delete manual
}
Soal: Apa yang salah dengan kode berikut? Jelaskan dan perbaiki!
int* buatArray() {
int arr[5] = {1, 2, 3, 4, 5};
return arr;
}
int main() {
int* hasil = buatArray();
cout << hasil[0] << endl;
return 0;
}
Penyelesaian:
Masalah: Fungsi mengembalikan pointer ke array lokal (stack-allocated). Ketika fungsi berakhir, array arr dihancurkan, sehingga hasil menjadi dangling pointer.
Mengapa berbahaya:
hasil[0] adalah undefined behaviorPerbaikan menggunakan dynamic allocation:
int* buatArray() {
int* arr = new int[5]; // Alokasi di heap
for (int i = 0; i < 5; i++) {
arr[i] = i + 1;
}
return arr; // Aman, heap tidak dihancurkan saat return
}
int main() {
int* hasil = buatArray();
for (int i = 0; i < 5; i++) {
cout << hasil[i] << " ";
}
cout << endl;
delete[] hasil; // Jangan lupa dealokasi!
return 0;
}
Raw pointer (int*, char*, dll) memiliki beberapa masalah:
C++11 memperkenalkan smart pointer yang mengelola memori secara otomatis:
| Smart Pointer | Kepemilikan | Penggunaan |
|---|---|---|
unique_ptr |
Exclusive (satu pemilik) | Default choice, tidak bisa di-copy |
shared_ptr |
Shared (banyak pemilik) | Ketika perlu berbagi kepemilikan |
weak_ptr |
Non-owning reference | Menghindari circular reference |
unique_ptr#include <iostream>
#include <memory>
using namespace std;
int main() {
// Membuat unique_ptr
unique_ptr<int> ptr1(new int(42));
// Cara modern (C++14): make_unique
// unique_ptr<int> ptr1 = make_unique<int>(42);
cout << "Nilai: " << *ptr1 << endl;
// unique_ptr tidak bisa di-copy
// unique_ptr<int> ptr2 = ptr1; // ERROR!
// Tapi bisa di-move
unique_ptr<int> ptr2 = move(ptr1);
// Sekarang ptr1 adalah nullptr
if (ptr1 == nullptr) {
cout << "ptr1 sekarang null" << endl;
}
cout << "ptr2: " << *ptr2 << endl;
// Otomatis dealokasi saat keluar scope
return 0;
}
unique_ptr untuk Array#include <iostream>
#include <memory>
using namespace std;
int main() {
// unique_ptr untuk array
unique_ptr<int[]> arr(new int[5]);
// Mengisi array
for (int i = 0; i < 5; i++) {
arr[i] = i * 10;
}
// Menampilkan
for (int i = 0; i < 5; i++) {
cout << arr[i] << " ";
}
cout << endl;
// Tidak perlu delete[] - otomatis!
return 0;
}
Catatan: Smart pointer akan dibahas lebih detail pada mata kuliah Pemrograman Berorientasi Objek di Semester 3. Untuk saat ini, pahami konsep dasarnya sebagai solusi untuk masalah memory management.
Soal: Apa keuntungan utama menggunakan smart pointer dibandingkan raw pointer?
Penyelesaian:
Keuntungan Smart Pointer:
delete manualunique_ptr: satu pemilik, tidak ambigushared_ptr: kepemilikan bersama dengan reference countingContoh perbandingan:
// Raw pointer - rawan error
void fungsiRaw() {
int* ptr = new int(42);
// Jika exception di sini, memory leak!
riskyOperation();
delete ptr;
}
// Smart pointer - aman
void fungsiSmart() {
unique_ptr<int> ptr(new int(42));
// Jika exception, ptr tetap dealokasi otomatis
riskyOperation();
// Tidak perlu delete
}
Array statis di C++ memiliki keterbatasan:
int arrStatis[100]; // Selalu menggunakan memori untuk 100 int
// Tidak bisa diperbesar
Array dinamis dapat tumbuh sesuai kebutuhan:
#include <iostream>
#include <cstring> // untuk memcpy
using namespace std;
class ArrayDinamis {
private:
int* data;
int ukuran; // Jumlah elemen saat ini
int kapasitas; // Total kapasitas array
public:
// Constructor
ArrayDinamis(int kapasitasAwal = 10) {
kapasitas = kapasitasAwal;
ukuran = 0;
data = new int[kapasitas];
}
// Destructor
~ArrayDinamis() {
delete[] data;
}
// Tambah elemen
void tambah(int nilai) {
// Jika penuh, perbesar kapasitas
if (ukuran == kapasitas) {
perbesarKapasitas();
}
data[ukuran] = nilai;
ukuran++;
}
// Akses elemen
int ambil(int index) const {
if (index < 0 || index >= ukuran) {
throw out_of_range("Index di luar range!");
}
return data[index];
}
// Getter
int getUkuran() const { return ukuran; }
int getKapasitas() const { return kapasitas; }
private:
// Perbesar kapasitas (double)
void perbesarKapasitas() {
int kapasitasBaru = kapasitas * 2;
int* dataBaru = new int[kapasitasBaru];
// Copy data lama ke array baru
memcpy(dataBaru, data, ukuran * sizeof(int));
// Hapus array lama
delete[] data;
// Update pointer dan kapasitas
data = dataBaru;
kapasitas = kapasitasBaru;
cout << "[Info] Kapasitas diperbesar menjadi "
<< kapasitas << endl;
}
};
int main() {
ArrayDinamis arr(3); // Mulai dengan kapasitas 3
cout << "Menambahkan elemen..." << endl;
for (int i = 1; i <= 10; i++) {
arr.tambah(i * 10);
cout << "Tambah " << i * 10
<< " | Ukuran: " << arr.getUkuran()
<< " | Kapasitas: " << arr.getKapasitas() << endl;
}
cout << "\nIsi array: ";
for (int i = 0; i < arr.getUkuran(); i++) {
cout << arr.ambil(i) << " ";
}
cout << endl;
return 0;
}
Output:
Menambahkan elemen...
Tambah 10 | Ukuran: 1 | Kapasitas: 3
Tambah 20 | Ukuran: 2 | Kapasitas: 3
Tambah 30 | Ukuran: 3 | Kapasitas: 3
[Info] Kapasitas diperbesar menjadi 6
Tambah 40 | Ukuran: 4 | Kapasitas: 6
Tambah 50 | Ukuran: 5 | Kapasitas: 6
Tambah 60 | Ukuran: 6 | Kapasitas: 6
[Info] Kapasitas diperbesar menjadi 12
Tambah 70 | Ukuran: 7 | Kapasitas: 12
Tambah 80 | Ukuran: 8 | Kapasitas: 12
Tambah 90 | Ukuran: 9 | Kapasitas: 12
Tambah 100 | Ukuran: 10 | Kapasitas: 12
Isi array: 10 20 30 40 50 60 70 80 90 100
| Strategi | Deskripsi | Kelebihan | Kekurangan |
|---|---|---|---|
| Tambah tetap (+k) | newCap = oldCap + k |
Hemat memori | Banyak realokasi |
| Lipat dua (×2) | newCap = oldCap * 2 |
Realokasi jarang | Boros memori |
| Faktor 1.5 | newCap = oldCap * 1.5 |
Seimbang | Kompromi |
Strategi lipat dua memberikan amortized O(1) untuk operasi tambah.
Soal: Implementasikan method hapus(int index) untuk class ArrayDinamis!
Penyelesaian:
// Tambahkan method ini ke class ArrayDinamis
void hapus(int index) {
// Validasi index
if (index < 0 || index >= ukuran) {
throw out_of_range("Index di luar range!");
}
// Geser semua elemen setelah index ke kiri
for (int i = index; i < ukuran - 1; i++) {
data[i] = data[i + 1];
}
// Kurangi ukuran
ukuran--;
// Opsional: kurangi kapasitas jika terlalu banyak ruang kosong
// if (ukuran < kapasitas / 4 && kapasitas > 10) {
// kurangiKapasitas();
// }
}
Ilustrasi proses hapus di index 2:

Gambar 1.5: Ilustrasi proses penghapusan elemen pada array dinamis
Kompleksitas waktu: O(n) karena perlu menggeser elemen
Soal: Mengapa strategi memperbesar array dengan mengalikan 2 lebih baik daripada menambah dengan konstanta tetap?
Penyelesaian:
Analisis dengan menambahkan n elemen:
Strategi 1: Tambah tetap (+10)
Strategi 2: Lipat dua (×2)
Tabel perbandingan untuk n operasi:
| Strategi | Jumlah Realokasi | Total Copy | Amortized per Operasi |
|---|---|---|---|
| +k (konstanta) | O(n/k) | O(n²/k) | O(n) |
| ×2 (lipat dua) | O(log n) | O(n) | O(1) |
Kesimpulan: Strategi lipat dua memberikan performa amortized O(1) per operasi, jauh lebih efisien untuk jumlah operasi yang banyak.
Soal: Dalam konteks sistem pertahanan, jelaskan bagaimana array dinamis dapat digunakan untuk tracking objek radar dan implementasikan struktur dasarnya!
Penyelesaian:
Skenario: Sistem radar perlu melacak objek yang terdeteksi. Jumlah objek bervariasi dan tidak dapat diprediksi.
#include <iostream>
#include <cstring>
#include <cmath>
using namespace std;
// Struktur untuk objek yang terdeteksi radar
struct ObjekRadar {
int id;
double jarak; // km
double azimuth; // derajat
double kecepatan; // km/jam
char jenis[20]; // pesawat, kapal, dll
bool ancaman;
void tampilkan() const {
cout << "ID: " << id
<< " | Jenis: " << jenis
<< " | Jarak: " << jarak << " km"
<< " | Azimuth: " << azimuth << "°"
<< " | Kecepatan: " << kecepatan << " km/jam"
<< " | Ancaman: " << (ancaman ? "YA" : "Tidak")
<< endl;
}
};
class TrackerRadar {
private:
ObjekRadar* objek;
int jumlah;
int kapasitas;
int nextId;
void perbesarKapasitas() {
int kapasitasBaru = kapasitas * 2;
ObjekRadar* dataBaru = new ObjekRadar[kapasitasBaru];
memcpy(dataBaru, objek, jumlah * sizeof(ObjekRadar));
delete[] objek;
objek = dataBaru;
kapasitas = kapasitasBaru;
cout << "[SISTEM] Kapasitas tracking diperbesar: "
<< kapasitas << " objek" << endl;
}
public:
TrackerRadar(int kapasitasAwal = 50) {
kapasitas = kapasitasAwal;
jumlah = 0;
nextId = 1001;
objek = new ObjekRadar[kapasitas];
}
~TrackerRadar() {
delete[] objek;
}
// Deteksi objek baru
int deteksiObjek(double jarak, double azimuth,
double kecepatan, const char* jenis) {
if (jumlah == kapasitas) {
perbesarKapasitas();
}
ObjekRadar& obj = objek[jumlah];
obj.id = nextId++;
obj.jarak = jarak;
obj.azimuth = azimuth;
obj.kecepatan = kecepatan;
strncpy(obj.jenis, jenis, 19);
obj.jenis[19] = '\0';
// Analisis ancaman sederhana
obj.ancaman = (jarak < 100 && kecepatan > 500);
jumlah++;
if (obj.ancaman) {
cout << "[PERINGATAN] Objek ancaman terdeteksi! ID: "
<< obj.id << endl;
}
return obj.id;
}
// Hapus objek yang hilang dari radar
bool hapusObjek(int id) {
for (int i = 0; i < jumlah; i++) {
if (objek[i].id == id) {
// Geser elemen
for (int j = i; j < jumlah - 1; j++) {
objek[j] = objek[j + 1];
}
jumlah--;
return true;
}
}
return false;
}
// Update posisi objek
void updatePosisi(int id, double jarakBaru, double azimuthBaru) {
for (int i = 0; i < jumlah; i++) {
if (objek[i].id == id) {
objek[i].jarak = jarakBaru;
objek[i].azimuth = azimuthBaru;
objek[i].ancaman = (jarakBaru < 100 &&
objek[i].kecepatan > 500);
return;
}
}
}
// Tampilkan semua objek
void tampilkanSemua() const {
cout << "\n=== STATUS RADAR ===" << endl;
cout << "Total objek: " << jumlah << "/" << kapasitas << endl;
cout << "-------------------" << endl;
for (int i = 0; i < jumlah; i++) {
objek[i].tampilkan();
}
}
// Hitung jumlah ancaman
int hitungAncaman() const {
int count = 0;
for (int i = 0; i < jumlah; i++) {
if (objek[i].ancaman) count++;
}
return count;
}
};
int main() {
TrackerRadar radar(5); // Mulai dengan kapasitas kecil untuk demo
cout << "=== SIMULASI SISTEM RADAR ===" << endl << endl;
// Deteksi beberapa objek
radar.deteksiObjek(250, 45, 200, "Pesawat Komersial");
radar.deteksiObjek(80, 120, 600, "Jet Tempur");
radar.deteksiObjek(150, 200, 50, "Kapal Kargo");
radar.deteksiObjek(50, 90, 800, "Rudal");
radar.deteksiObjek(300, 270, 150, "Helikopter");
radar.deteksiObjek(75, 180, 650, "Drone");
radar.tampilkanSemua();
cout << "\n[INFO] Total ancaman terdeteksi: "
<< radar.hitungAncaman() << endl;
return 0;
}
Analisis Desain:
Soal: Apa yang terjadi jika kita tidak mengimplementasikan destructor pada class ArrayDinamis?
Penyelesaian:
Jika tidak ada destructor:
class ArrayDinamisTanpaDestructor {
private:
int* data;
int ukuran;
int kapasitas;
public:
ArrayDinamisTanpaDestructor(int kap = 10) {
kapasitas = kap;
ukuran = 0;
data = new int[kapasitas]; // Alokasi di heap
}
// TIDAK ADA DESTRUCTOR!
// ~ArrayDinamisTanpaDestructor() { delete[] data; }
};
void fungsiMasalah() {
ArrayDinamisTanpaDestructor arr(100);
// arr.data menunjuk ke 100 integer di heap
} // arr keluar scope, TAPI data di heap TIDAK didealokasi!
// Memory leak sebesar 100 * sizeof(int) = 400 bytes
Konsekuensi:
Memory Leak: Setiap kali objek ArrayDinamis dibuat dan dihancurkan, memori heap tidak dibebaskan
Akumulasi: Jika objek dibuat berkali-kali (misalnya dalam loop), memory leak terakumulasi
Crash: Program akhirnya kehabisan memori dan crash
Resource Exhaustion: Dalam sistem yang berjalan lama (seperti server), ini sangat berbahaya
Solusi wajib:
~ArrayDinamis() {
delete[] data; // WAJIB ada untuk mencegah memory leak
}
Soal: Implementasikan fungsi cariMaksimum yang menerima array dinamis dan ukurannya, kemudian mengembalikan nilai maksimum menggunakan pointer arithmetic!
Penyelesaian:
#include <iostream>
using namespace std;
int cariMaksimum(int* arr, int ukuran) {
if (ukuran <= 0) {
throw invalid_argument("Ukuran harus positif!");
}
int* ptr = arr; // Pointer ke elemen pertama
int* akhir = arr + ukuran; // Pointer melewati elemen terakhir
int maks = *ptr; // Inisialisasi dengan elemen pertama
// Traverse menggunakan pointer
while (ptr < akhir) {
if (*ptr > maks) {
maks = *ptr;
}
ptr++; // Pindah ke elemen berikutnya
}
return maks;
}
int main() {
// Buat array dinamis
int ukuran = 7;
int* data = new int[ukuran];
// Isi dengan nilai
data[0] = 23;
data[1] = 45;
data[2] = 12;
data[3] = 89;
data[4] = 34;
data[5] = 67;
data[6] = 56;
// Cari maksimum
int hasil = cariMaksimum(data, ukuran);
cout << "Array: ";
for (int i = 0; i < ukuran; i++) {
cout << data[i] << " ";
}
cout << endl;
cout << "Nilai maksimum: " << hasil << endl;
// Dealokasi
delete[] data;
return 0;
}
Output:
Array: 23 45 12 89 34 67 56
Nilai maksimum: 89
Penjelasan Pointer Arithmetic:
ptr++ memindahkan pointer ke elemen berikutnya (bukan +1 byte, tapi +sizeof(int))ptr < akhir membandingkan alamat untuk mengecek batas array*ptr mengakses nilai di alamat yang ditunjukSoal: Implementasikan fungsi yang menggabungkan dua array dinamis menjadi satu array baru yang terurut (merge)!
Penyelesaian:
#include <iostream>
using namespace std;
// Fungsi untuk menggabungkan dua array terurut
// Asumsi: arr1 dan arr2 sudah terurut ascending
int* gabungTerurut(int* arr1, int ukuran1,
int* arr2, int ukuran2,
int& ukuranHasil) {
ukuranHasil = ukuran1 + ukuran2;
int* hasil = new int[ukuranHasil];
int i = 0; // Index untuk arr1
int j = 0; // Index untuk arr2
int k = 0; // Index untuk hasil
// Merge selama kedua array masih punya elemen
while (i < ukuran1 && j < ukuran2) {
if (arr1[i] <= arr2[j]) {
hasil[k] = arr1[i];
i++;
} else {
hasil[k] = arr2[j];
j++;
}
k++;
}
// Salin sisa arr1 (jika ada)
while (i < ukuran1) {
hasil[k] = arr1[i];
i++;
k++;
}
// Salin sisa arr2 (jika ada)
while (j < ukuran2) {
hasil[k] = arr2[j];
j++;
k++;
}
return hasil;
}
int main() {
// Array pertama (terurut)
int ukuran1 = 5;
int* arr1 = new int[ukuran1];
arr1[0] = 1; arr1[1] = 3; arr1[2] = 5; arr1[3] = 7; arr1[4] = 9;
// Array kedua (terurut)
int ukuran2 = 4;
int* arr2 = new int[ukuran2];
arr2[0] = 2; arr2[1] = 4; arr2[2] = 6; arr2[3] = 8;
// Gabungkan
int ukuranHasil;
int* hasil = gabungTerurut(arr1, ukuran1, arr2, ukuran2, ukuranHasil);
// Tampilkan
cout << "Array 1: ";
for (int i = 0; i < ukuran1; i++) cout << arr1[i] << " ";
cout << endl;
cout << "Array 2: ";
for (int i = 0; i < ukuran2; i++) cout << arr2[i] << " ";
cout << endl;
cout << "Hasil merge: ";
for (int i = 0; i < ukuranHasil; i++) cout << hasil[i] << " ";
cout << endl;
// Dealokasi semua array
delete[] arr1;
delete[] arr2;
delete[] hasil;
return 0;
}
Output:
Array 1: 1 3 5 7 9
Array 2: 2 4 6 8
Hasil merge: 1 2 3 4 5 6 7 8 9
Kompleksitas:
Catatan: Algoritma ini adalah dasar dari Merge Sort yang akan dipelajari pada Pertemuan 10.
Soal: Jelaskan apa yang terjadi di memori saat kode berikut dieksekusi!
int* p1 = new int(10);
int* p2 = p1;
delete p1;
*p2 = 20; // ???
Penyelesaian:

Gambar 1.6: Proses terjadinya dangling pointer — langkah demi langkah
Penjelasan langkah:
| Langkah | Kode | Stack | Heap | Status |
|---|---|---|---|---|
| 1 | int* p1 = new int(10); |
p1 → 0x1000 | [0x1000]: 10 | ✅ Valid |
| 2 | int* p2 = p1; |
p1, p2 → 0x1000 | [0x1000]: 10 | ✅ Valid (shallow copy) |
| 3 | delete p1; |
p1, p2 → 0x1000 | [0x1000]: ??? | ⌠Dangling! |
| 4 | *p2 = 20; |
- | - | âš ï¸ UNDEFINED BEHAVIOR! |
Bahaya: Memori di 0x1000 didealokasi, tapi p1 dan p2 masih menyimpan alamat tersebut → dangling pointer.
Kemungkinan yang bisa terjadi:
Solusi yang benar:
int* p1 = new int(10);
int* p2 = p1;
*p2 = 20; // Ubah nilai SEBELUM delete
delete p1;
p1 = nullptr;
p2 = nullptr; // Penting: set semua pointer yang merujuk ke sini
Soal: Implementasikan class Matrix2D yang menggunakan dynamic memory allocation untuk matriks 2D dengan ukuran yang ditentukan saat runtime!
Penyelesaian:
#include <iostream>
#include <iomanip>
using namespace std;
class Matrix2D {
private:
double** data;
int baris;
int kolom;
public:
// Constructor
Matrix2D(int b, int k) : baris(b), kolom(k) {
// Alokasi array of pointers
data = new double*[baris];
// Alokasi setiap baris
for (int i = 0; i < baris; i++) {
data[i] = new double[kolom];
// Inisialisasi dengan 0
for (int j = 0; j < kolom; j++) {
data[i][j] = 0.0;
}
}
}
// Destructor
~Matrix2D() {
// Dealokasi setiap baris
for (int i = 0; i < baris; i++) {
delete[] data[i];
}
// Dealokasi array of pointers
delete[] data;
}
// Set nilai
void set(int i, int j, double nilai) {
if (i < 0 || i >= baris || j < 0 || j >= kolom) {
throw out_of_range("Index di luar range!");
}
data[i][j] = nilai;
}
// Get nilai
double get(int i, int j) const {
if (i < 0 || i >= baris || j < 0 || j >= kolom) {
throw out_of_range("Index di luar range!");
}
return data[i][j];
}
// Tampilkan matriks
void tampilkan() const {
for (int i = 0; i < baris; i++) {
for (int j = 0; j < kolom; j++) {
cout << setw(8) << fixed << setprecision(2)
<< data[i][j] << " ";
}
cout << endl;
}
}
// Penjumlahan matriks
Matrix2D operator+(const Matrix2D& other) const {
if (baris != other.baris || kolom != other.kolom) {
throw invalid_argument("Dimensi matriks tidak cocok!");
}
Matrix2D hasil(baris, kolom);
for (int i = 0; i < baris; i++) {
for (int j = 0; j < kolom; j++) {
hasil.data[i][j] = data[i][j] + other.data[i][j];
}
}
return hasil;
}
// Getter dimensi
int getBaris() const { return baris; }
int getKolom() const { return kolom; }
};
int main() {
cout << "=== Demo Matrix 2D Dinamis ===" << endl << endl;
// Buat matriks 3x3
Matrix2D A(3, 3);
Matrix2D B(3, 3);
// Isi matriks A
A.set(0, 0, 1); A.set(0, 1, 2); A.set(0, 2, 3);
A.set(1, 0, 4); A.set(1, 1, 5); A.set(1, 2, 6);
A.set(2, 0, 7); A.set(2, 1, 8); A.set(2, 2, 9);
// Isi matriks B
B.set(0, 0, 9); B.set(0, 1, 8); B.set(0, 2, 7);
B.set(1, 0, 6); B.set(1, 1, 5); B.set(1, 2, 4);
B.set(2, 0, 3); B.set(2, 1, 2); B.set(2, 2, 1);
cout << "Matriks A:" << endl;
A.tampilkan();
cout << "\nMatriks B:" << endl;
B.tampilkan();
// Penjumlahan
Matrix2D C = A + B;
cout << "\nA + B:" << endl;
C.tampilkan();
return 0;
}
Output:
=== Demo Matrix 2D Dinamis ===
Matriks A:
1.00 2.00 3.00
4.00 5.00 6.00
7.00 8.00 9.00
Matriks B:
9.00 8.00 7.00
6.00 5.00 4.00
3.00 2.00 1.00
A + B:
10.00 10.00 10.00
10.00 10.00 10.00
10.00 10.00 10.00
Catatan penting:
Soal: Apa output dari program berikut?
int main() {
int* arr = new int[5]{10, 20, 30, 40, 50};
int* p = arr + 2;
cout << *p << " " << *(p-1) << " " << *(p+1) << endl;
delete[] arr;
return 0;
}
Penyelesaian:
Output: 30 20 40
Penjelasan:
int* arr = new int[5]{10, 20, 30, 40, 50};
[10, 20, 30, 40, 50]int* p = arr + 2;
*p → nilai di index 2 = 30
*(p-1) → nilai di index 1 = 20
*(p+1) → nilai di index 3 = 40
Gambar 1.7: Visualisasi pointer arithmetic pada array
Soal: Implementasikan fungsi yang melakukan operasi resize pada array dinamis dengan mempertahankan data yang ada!
Penyelesaian:
#include <iostream>
#include <cstring>
using namespace std;
// Fungsi resize array dinamis
// Mengembalikan pointer ke array baru
// Parameter ukuranLama dan ukuranBaru di-pass by reference
// untuk melacak perubahan ukuran
int* resizeArray(int* arrLama, int ukuranLama, int ukuranBaru) {
// Alokasi array baru
int* arrBaru = new int[ukuranBaru];
// Tentukan berapa banyak elemen yang di-copy
int elemenCopy = (ukuranLama < ukuranBaru) ? ukuranLama : ukuranBaru;
// Copy data dari array lama ke array baru
for (int i = 0; i < elemenCopy; i++) {
arrBaru[i] = arrLama[i];
}
// Jika ukuran baru lebih besar, inisialisasi elemen baru dengan 0
for (int i = elemenCopy; i < ukuranBaru; i++) {
arrBaru[i] = 0;
}
// Dealokasi array lama
delete[] arrLama;
return arrBaru;
}
void tampilkanArray(int* arr, int ukuran, const char* label) {
cout << label << " (ukuran " << ukuran << "): [";
for (int i = 0; i < ukuran; i++) {
cout << arr[i];
if (i < ukuran - 1) cout << ", ";
}
cout << "]" << endl;
}
int main() {
// Buat array awal
int ukuran = 5;
int* data = new int[ukuran];
for (int i = 0; i < ukuran; i++) {
data[i] = (i + 1) * 10;
}
tampilkanArray(data, ukuran, "Array awal");
// Perbesar array
cout << "\n--- Memperbesar ke ukuran 8 ---" << endl;
ukuran = 8;
data = resizeArray(data, 5, ukuran);
tampilkanArray(data, ukuran, "Setelah resize");
// Isi elemen baru
data[5] = 60;
data[6] = 70;
data[7] = 80;
tampilkanArray(data, ukuran, "Setelah isi data");
// Perkecil array
cout << "\n--- Memperkecil ke ukuran 3 ---" << endl;
int ukuranLama = ukuran;
ukuran = 3;
data = resizeArray(data, ukuranLama, ukuran);
tampilkanArray(data, ukuran, "Setelah resize");
// Cleanup
delete[] data;
return 0;
}
Output:
Array awal (ukuran 5): [10, 20, 30, 40, 50]
--- Memperbesar ke ukuran 8 ---
Setelah resize (ukuran 8): [10, 20, 30, 40, 50, 0, 0, 0]
Setelah isi data (ukuran 8): [10, 20, 30, 40, 50, 60, 70, 80]
--- Memperkecil ke ukuran 3 ---
Setelah resize (ukuran 3): [10, 20, 30]
Poin penting:
Soal: Implementasikan class Stack sederhana menggunakan array dinamis yang dapat tumbuh otomatis!
Penyelesaian:
#include <iostream>
#include <stdexcept>
using namespace std;
class StackDinamis {
private:
int* data;
int top; // Index elemen teratas
int kapasitas;
void perbesarKapasitas() {
int kapasitasBaru = kapasitas * 2;
int* dataBaru = new int[kapasitasBaru];
// Copy data
for (int i = 0; i <= top; i++) {
dataBaru[i] = data[i];
}
delete[] data;
data = dataBaru;
kapasitas = kapasitasBaru;
cout << "[Stack] Kapasitas diperbesar: " << kapasitas << endl;
}
public:
// Constructor
StackDinamis(int kapasitasAwal = 10) {
kapasitas = kapasitasAwal;
top = -1; // Stack kosong
data = new int[kapasitas];
}
// Destructor
~StackDinamis() {
delete[] data;
}
// Push: tambah elemen ke puncak
void push(int nilai) {
if (top == kapasitas - 1) {
perbesarKapasitas();
}
data[++top] = nilai;
}
// Pop: hapus dan kembalikan elemen puncak
int pop() {
if (isEmpty()) {
throw underflow_error("Stack kosong!");
}
return data[top--];
}
// Peek: lihat elemen puncak tanpa menghapus
int peek() const {
if (isEmpty()) {
throw underflow_error("Stack kosong!");
}
return data[top];
}
// Cek apakah kosong
bool isEmpty() const {
return top == -1;
}
// Jumlah elemen
int size() const {
return top + 1;
}
// Tampilkan isi stack
void tampilkan() const {
cout << "Stack (bawah ke atas): [";
for (int i = 0; i <= top; i++) {
cout << data[i];
if (i < top) cout << ", ";
}
cout << "]" << endl;
cout << "Ukuran: " << size() << ", Kapasitas: " << kapasitas << endl;
}
};
int main() {
cout << "=== Demo Stack Dinamis ===" << endl << endl;
StackDinamis stack(3); // Kapasitas awal kecil untuk demo
// Push beberapa elemen
cout << "Push: 10, 20, 30, 40, 50" << endl;
stack.push(10);
stack.push(20);
stack.push(30);
stack.push(40); // Akan trigger resize
stack.push(50);
stack.tampilkan();
// Peek
cout << "\nPeek: " << stack.peek() << endl;
// Pop beberapa elemen
cout << "\nPop 3 elemen:" << endl;
for (int i = 0; i < 3; i++) {
cout << "Pop: " << stack.pop() << endl;
}
stack.tampilkan();
return 0;
}
Output:
=== Demo Stack Dinamis ===
Push: 10, 20, 30, 40, 50
[Stack] Kapasitas diperbesar: 6
Stack (bawah ke atas): [10, 20, 30, 40, 50]
Ukuran: 5, Kapasitas: 6
Peek: 50
Pop 3 elemen:
Pop: 50
Pop: 40
Pop: 30
Stack (bawah ke atas): [10, 20]
Ukuran: 2, Kapasitas: 6
Catatan: Stack akan dipelajari lebih detail pada Pertemuan 5.
Kerjakan soal-soal berikut untuk latihan tambahan. Jawaban singkat tersedia di bagian akhir.
Apa output dari kode berikut?
int a = 5;
int* p = &a;
int** pp = &p;
**pp = 10;
cout << a << endl;
Tuliskan fungsi void isiDescending(int* arr, int n) yang mengisi array dengan nilai n, n-1, n-2, …, 1 menggunakan pointer arithmetic!
Identifikasi semua potensi masalah dalam kode berikut:
int* buat() {
int x = 100;
return &x;
}
int main() {
int* p = buat();
cout << *p;
return 0;
}
Implementasikan fungsi yang membalik array secara in-place menggunakan two-pointer technique!
Jelaskan perbedaan antara shallow copy dan deep copy dalam konteks dynamic memory allocation. Berikan contoh kode yang menunjukkan masalah dengan shallow copy!
| Konsep | Deskripsi | Contoh/Catatan |
|---|---|---|
| Struktur Data | Cara mengorganisasi data dalam memori | Linear (array, list) dan non-linear (tree, graph) |
| ADT | Model matematis yang mendefinisikan operasi tanpa detail implementasi | Stack ADT: push, pop, peek, isEmpty |
| Pointer | Variabel yang menyimpan alamat memori | int* ptr = &var; |
| Referensi | Alias untuk variabel lain | int& ref = var; |
| new | Alokasi memori di heap | int* p = new int; |
| delete | Dealokasi memori heap | delete p; untuk single, delete[] arr; untuk array |
| Memory Leak | Memori yang dialokasi tidak pernah didealokasi | Penyebab: lupa delete, early return |
| Dangling Pointer | Pointer yang menunjuk ke memori tidak valid | Setelah delete, saat variabel lokal keluar scope |
| Smart Pointer | Pointer yang mengelola memori otomatis | unique_ptr, shared_ptr (C++11) |
| Array Dinamis | Array yang ukurannya dapat berubah saat runtime | Strategi resize: double capacity |
SP-1: 10
pp adalah pointer ke pointer**pp mengakses nilai yang ditunjuk oleh p, yaitu a**pp sama dengan mengubah aSP-2:
void isiDescending(int* arr, int n) {
int* ptr = arr;
for (int i = n; i >= 1; i--) {
*ptr++ = i; // Set nilai dan increment pointer
}
}
SP-3:
x dihancurkan saat fungsi berakhir*p adalah undefined behaviorSP-4:
void balikArray(int* arr, int n) {
int* kiri = arr;
int* kanan = arr + n - 1;
while (kiri < kanan) {
int temp = *kiri;
*kiri = *kanan;
*kanan = temp;
kiri++;
kanan--;
}
}
SP-5:
This repository is licensed under the Creative Commons Attribution 4.0 International (CC BY 4.0). Commercial use is permitted, provided attribution is given to the author.
© 2026 Anindito