Pointer ke Memori
Latihan membuat instruksi pembelajaran tentang bagaimana mengenali konsep pointer ke memori yang biasanya ada di bahasa pemrograman tingkat rendah seperti bahasa pemrograman C, dari sudut pandang implementasi bahasa pemrograman Rust.
Pointer adalah konsep mendasar dalam pemrograman sistem. Artikel ini membantu pembaca pemula memahami pointer dari perspektif bahasa C, kemudian mempelajari bagaimana Rust menawarkan cara yang lebih aman untuk mengakses dan mengelola memori. Fokus pembelajaran bukan hanya mengetahui sintaks, tetapi juga memahami bagaimana memori bekerja, bagaimana data dipindahkan (move), dipinjam (borrow), dan dibebaskan (drop) dengan aman.
Tujuan Pembelajaran
Setelah mempelajari artikel ini, Anda diharapkan mampu:
Menjelaskan konsep pointer dan mengapa ia penting dalam pemrograman.
Menggambarkan perbedaan memori stack dan heap.
Menjelaskan konsep ownership, borrowing, dan lifetime di Rust.
Menulis kode menggunakan referensi (
&
,&mut
),Box<T>
, danOption<T>
untuk mengelola memori.Menjelaskan perbedaan passing by value dan passing by reference dalam Rust.
Mengidentifikasi edge case seperti dangling pointer, double free, dan null pointer, serta memahami bagaimana Rust mencegahnya.
Mengenali kapan menggunakan raw pointer (
*const T
,*mut T
) danunsafe
.
Prasyarat
Memahami variabel, tipe data, fungsi, dan array/Vec di Rust.
Mampu membaca dan mencoba contoh kode sederhana.
Tidak perlu pengalaman bahasa C, tetapi perbandingan akan membantu.
Penjelasan Konsep
Apa itu Pointer?
Pointer adalah variabel yang menyimpan alamat memori dari sebuah nilai. Dengan pointer, program dapat mengakses atau mengubah nilai di lokasi lain, tanpa menyalin data tersebut.
Di C:
int x = 5;
int *p = &x; // p menyimpan alamat x
Pointer memberikan fleksibilitas tinggi, tetapi juga rawan bug di antaranya:
Dangling pointer: menunjuk memori yang sudah dibebaskan.
Null pointer dereference: mengakses alamat null.
Double free: membebaskan memori dua kali.
Use-after-free: menggunakan data setelah dibebaskan.
Stack dan Heap
Untuk memahami pointer, penting memahami di mana data disimpan:
Stack: tempat menyimpan variabel lokal dan data kecil. Alokasi dan dealokasi otomatis, cepat, dan mengikuti urutan LIFO (Last In, First Out). Namun ukurannya terbatas.
Heap: digunakan untuk data yang ukurannya diketahui saat runtime atau berukuran besar. Alokasi lebih lambat karena perlu mencari blok memori yang sesuai. Di C, programmer harus memanggil
malloc
/free
sendiri.
Rust menggunakan RAII (Resource Acquisition Is Initialization): memori heap akan dibebaskan otomatis saat pemilik keluar scope, sehingga risiko kebocoran memori berkurang drastis.
Ownership dan Borrowing di Rust
Rust memperkenalkan sistem ownership untuk memastikan memori dikelola dengan aman:
Setiap nilai hanya memiliki satu owner.
Saat owner keluar scope, nilai otomatis di-drop.
Untuk berbagi data tanpa mengambil kepemilikan, gunakan borrowing:
&T
: referensi immutable (bisa banyak sekaligus).&mut T
: referensi mutable (hanya satu yang aktif pada saat yang sama).
Borrow checker memastikan aturan ini dipatuhi, sehingga mencegah bug seperti data race dan dangling pointer bahkan sebelum program di-run.
Passing by Value vs Passing by Reference
Rust membedakan antara:
Passing by value (move): kepemilikan data dipindahkan ke fungsi, sehingga variabel asli tidak bisa digunakan lagi kecuali tipe data mendukung
Copy
.Passing by reference (borrow): fungsi hanya meminjam akses, variabel asli tetap bisa digunakan setelah fungsi selesai (selama aturannya dipatuhi).
Contoh Passing by Value
fn tambah(mut v: Vec<i32>) { // ownership berpindah ke v
v.push(100);
println!("v di dalam fungsi: {:?}", v);
}
fn main() {
let data = vec![1, 2, 3];
tambah(data);
// println!("{:?}", data); // ERROR: data sudah pindah ownership
}
Contoh Passing by Reference
fn tambah_borrow(v: &mut Vec<i32>) { // meminjam akses secara mutable
v.push(200);
}
fn main() {
let mut data = vec![1, 2, 3];
tambah_borrow(&mut data); // ownership tetap di main
println!("data setelah borrow: {:?}", data); // bisa dipakai lagi
}
Contoh Kode Rust Lainnya
Referensi Immutable dan Mutable
fn main() {
let x = 10;
let r = &x; // borrow immutable
println!("x = {}, r = {}", x, r);
let mut y = 20;
let m = &mut y; // borrow mutable
*m += 5;
println!("y setelah diubah = {}", y);
}
Box: Menyimpan di Heap
fn main() {
let b = Box::new(100); // nilai 100 disimpan di heap
println!("Nilai box = {}", *b);
} // b keluar scope → memori heap dibebaskan otomatis
Option: Pengganti Null
fn main() {
let angka: Option<i32> = Some(42);
if let Some(x) = angka {
println!("Ada nilai: {}", x);
}
let kosong: Option<i32> = None;
println!("None berarti tidak ada nilai");
}
Pencegahan Dangling Reference
fn contoh() -> &i32 {
let x = 5;
&x // ERROR: x di-drop saat fungsi selesai → Rust menolak compile
}
Solusi dengan memindahkan ownership:
fn contoh_ok() -> Box<i32> {
Box::new(5) // mengembalikan nilai dengan ownership
}
Raw Pointer dan Unsafe: hati-hati dalam menggunakannya
fn main() {
let mut num = 5;
let r1 = &num as *const i32;
let r2 = &mut num as *mut i32;
unsafe {
println!("r1: {}", *r1);
*r2 = 10;
println!("r2: {}", *r2);
}
}
Edge Cases
Dua mutable borrow dalam satu scope → compile error.
Akses Option tanpa pengecekan → panic jika
None
.Raw pointer salah dereference → undefined behavior (tidak disarankan kecuali perlu).
Aktivitas Praktik Dilengkapi Petunjuk
Latihan Borrowing
Buat fungsi yang menerima
&mut Vec<i32>
dan menghapus elemen pertama.Petunjuk: gunakan
v.remove(0)
.
Latihan Box
Buat fungsi yang mengembalikan
Box<String>
berisi"Halo"
.Petunjuk: gunakan
Box::new(String::from("Halo"))
.
Latihan Option
Buat array
[Option<i32>; 3]
dengan isi[Some(1), Some(2), None]
, cetak hanya nilai yang ada.Petunjuk: gunakan
if let Some(x) = ...
.
Latihan Passing by Value vs Reference
Buat dua fungsi: satu menerima
Vec<i32>
(ownership pindah), satu menerima&mut Vec<i32>
(borrow).Petunjuk: coba cetak variabel setelah dipanggil untuk melihat perbedaannya.
Refleksi
Bagaimana Rust mencegah dangling pointer bahkan sebelum program dijalankan?
Mengapa ownership membantu mengurangi bug memori?
Apa manfaat
Option<T>
dibanding null pointer tradisional?Kapan Anda memilih passing by reference daripada passing by value?
Bagaimana perasaan Anda saat melihat borrow checker error — apakah membantu atau terasa membatasi?
Referensi
Nick Parlante. Pointers and Memory. Materi klasik yang menjelaskan pointer, stack, heap, dan ilustrasi visual.
Sekolah Teknik Elektro dan Informatika, Institut Teknologi Bandung. Pointer dan Manajemen Memori.
The Rust Programming Language (The Rust Book). Bab Ownership, Borrowing, dan Smart Pointers.