Operator dereference (*) adalah pasangan kerja dari operator address-of (&). Jika & mengambil alamat sebuah variabel, operator * melakukan kebalikannya: diberikan sebuah pointer, operator * membaca atau menulis nilai pada alamat yang ditunjuk. Tanpa operator *, pointer hanya berisi angka alamat yang tidak berguna—kita tidak bisa membaca atau memodifikasi nilai di alamat tersebut. Pada chapter ini kita akan menelusuri dua peran operator *: sebagai read (di sisi kanan penugasan) dan sebagai write (di sisi kiri penugasan), serta bagaimana * berinteraksi dengan pointer arithmetic.
Peran Operator *: Baca dan Tulis #
Operator * adalah operator unary yang menghasilkan lvalue—ekspresi yang merujuk ke region memori yang ditunjuk pointer. Karena hasilnya lvalue, kita bisa memakainya di kedua sisi penugasan: di sisi kanan sebagai read (membaca nilai di alamat), atau di sisi kiri sebagai write (menulis nilai ke alamat). Tipe nilai yang dihasilkan *p ditentukan oleh tipe pointer p: jika p bertipe int *, maka *p bertipe int; jika p bertipe double *, maka *p bertipe double.
Mekanisme kerjanya: saat compiler melihat *p di sisi kanan, compiler membaca sizeof(*p) byte di alamat yang tersimpan pada variabel p, lalu menafsirkan byte-byte tersebut sebagai tipe yang ditunjuk. Saat compiler melihat *p = 99 di sisi kiri, compiler menulis 99 ke alamat yang sama, juga dengan jumlah byte yang sesuai dengan tipe. Inilah sebabnya tipe pointer penting: tipe menentukan berapa byte yang dibaca/ditulis dan bagaimana byte-byte tersebut ditafsirkan.
Visualisasi Konsep #
Diagram berikut memperlihatkan dua peran operator *: sebagai read di sisi kanan penugasan dan sebagai write di sisi kiri penugasan:
Pada diagram di atas, kedua peran operator * bertumpu pada alamat yang sama—alamat angka yang tersimpan di p. Pada peran read, operator *p mengikuti alamat di p, membaca 4 byte (untuk int), dan menghasilkan nilai yang kemudian disalin ke variabel salinan. Pada peran write, operator *p menjadi lvalue di sisi kiri, dan nilai 99 ditulis ke alamat yang sama sehingga variabel angka ikut berubah. Karena alamat yang dirujuk p adalah alamat angka, kedua peran operator * bekerja pada region memori yang sama.
#include <stdio.h>
int main(void) {
int angka = 25;
int *p = &angka;
/* Baca nilai melalui dereference */
int salinan = *p;
printf("angka = %d, *p = %d, salinan = %d\n", angka, *p, salinan);
/* Tulis nilai melalui dereference */
*p = 99;
printf("Setelah *p = 99 -> angka = %d, *p = %d\n", angka, *p);
return 0;
}Output yang Dihasilkan:
angka = 25, *p = 25, salinan = 25
Setelah *p = 99 -> angka = 99, *p = 99Pada baris int salinan = *p;, operator * membaca nilai int di alamat p (yaitu alamat angka) dan menyalinnya ke variabel salinan. Pada baris *p = 99;, operator * menulis nilai 99 ke alamat yang ditunjuk p. Karena alamat tersebut adalah alamat angka, perubahan langsung terlihat saat kita mencetak angka. Dengan kata lain, angka dan *p adalah dua cara berbeda untuk mengakses region memori yang sama.
Mari kita telaah baris-baris kode di atas:
- Baris 4 (
int angka = 25;): variabelangkabertipeintdengan nilai awal25. Compiler memesan 4 byte di stack untukangka. - Baris 5 (
int *p = &angka;): pointerpbertipeint *dan menyimpan alamatangka. Inisialisasi ini hanya menyalin alamat, tidak membaca atau menulis nilaiangka. - Baris 8 (
int salinan = *p;): operator*membaca nilaiintpada alamatp. Hasilnya disalin ke variabelsalinan. Sekarangsalinanbernilai25, terpisah dariangka. - Baris 11 (
*p = 99;): operator*menghasilkan lvalue yang menunjuk ke region memoriangka. Penugasan= 99menulis nilai99ke region tersebut. Setelah baris ini,angka == 99. - Baris 12 (
printf("... angka = %d, *p = %d", angka, *p);): dua ekspresi yang merujuk ke memori yang sama—angkasecara langsung,*pmelalui pointer—menghasilkan nilai yang sama:99.
Dereference pada Pointer yang Bergerak #
Operator * juga bisa diterapkan pada ekspresi pointer hasil pointer arithmetic. Ekspresi *(p + 1) artinya: ambil alamat p, geser maju satu elemen (sesuai tipe), lalu dereference alamat baru tersebut. Inilah dasar dari akses elemen array melalui pointer—ekspresi arr[i] setara dengan *(arr + i) (ISO/IEC 9899 §6.5.2.1).
#include <stdio.h>
int main(void) {
int data[3] = {5, 10, 15};
int *p = data; /* p menunjuk ke data[0] */
/* Dereference berbagai posisi pointer */
printf("*p = %d (data[0])\n", *p);
printf("*(p + 1) = %d (data[1])\n", *(p + 1));
printf("*(p + 2) = %d (data[2])\n", *(p + 2));
/* Modifikasi elemen via dereference */
*(p + 1) = 222;
printf("Setelah *(p+1) = 222 -> data[1] = %d\n", data[1]);
return 0;
}Output yang Dihasilkan:
*p = 5 (data[0])
*(p + 1) = 10 (data[1])
*(p + 2) = 15 (data[2])
Setelah *(p+1) = 222 -> data[1] = 222Ekspresi *(p + 1) di sisi kiri penugasan menulis ke elemen kedua array. Karena p + 1 adalah alamat data[1], dereference-nya menjadi lvalue yang menunjuk ke memori data[1]. Penugasan = 222 langsung mengubah array aslinya. Inilah mengapa arr[i] dan *(arr + i) dianggap ekuivalen secara semantik—keduanya menghasilkan lvalue yang menunjuk ke elemen ke-i dari array.