Pointer tanpa dereference hanya sekadar kertas berisi nomor rumah yang tidak pernah kita masuki. Dereference (menguraikan referensi) adalah operasi yang benar-benar “mengunjungi” alamat yang ditunjuk pointer: membaca nilai yang tersimpan di sana, atau bahkan menimpanya dengan nilai baru. Operatornya adalah * — tanda yang sama dengan deklarasi pointer, tetapi maknanya berbeda sesuai konteks. Pada Chapter ini kita melatih dereference untuk membaca dan menulis, membedah aturan precedence yang sering mengejutkan pemula, dan memahami satu aturan emas: dereference hanya boleh dilakukan pada pointer yang sah.

Membaca dan Menulis Melalui Pointer #

Satu operator *, dua arah kerja. Ketika dipakai di sisi kanan, *p membaca nilai di alamat yang ditunjuk p; ketika dipakai di sisi kiri assignment, *p = ... menulis ke alamat tersebut. Keduanya bekerja pada objek aslinya, bukan salinannya.

cpp
#include <iostream>

int main() {
    int x = 10;
    int* p = &x;

    // Membaca melalui pointer
    std::cout << "*p saat ini        : " << *p << "\n";

    // Menulis melalui pointer: mengubah x tanpa menyentuh variabelnya langsung
    *p = 42;
    std::cout << "x setelah *p = 42  : " << x << "\n";

    *p = *p + 8;
    std::cout << "x setelah *p + 8   : " << x << "\n";

    ++*p;  // parse: ++(*p) — menaikkan nilai yang ditunjuk, bukan pointernya
    std::cout << "x setelah ++*p     : " << x << "\n";

    // Precedence: *a + 1 berbeda dengan *(a + 1)
    int arr[3] = {5, 15, 25};
    int* a = arr;  // menunjuk arr[0]

    std::cout << "*a + 1 = " << *a + 1 << " (nilai arr[0] ditambah 1)\n";
    std::cout << "*(a+1) = " << *(a + 1) << " (nilai arr[1])\n";

    return 0;
}

Output yang Dihasilkan:

text
*p saat ini        : 10
x setelah *p = 42  : 42
x setelah *p + 8   : 50
x setelah ++*p     : 51
*a + 1 = 6 (nilai arr[0] ditambah 1)
*(a+1) = 15 (nilai arr[1])

Bedah baris-per-baris:

  1. Baris 9 (*p di sisi kanan): compiler melihat p berisi alamat x, pergi ke alamat itu, membaca 4 byte dengan tata letak int, dan hasilnya 10.
  2. Baris 13 (*p = 42;): * di sisi kiri membuat compiler menulis 42 ke alamat yang ditunjuk p. Karena p menunjuk x, nilai x ikut berubah — kita tidak pernah menulis x secara langsung, tetapi x berubah.
  3. Baris 15-17 (*p = *p + 8;): sisi kanan membaca nilai saat ini (42), menambahkannya 8, lalu hasilnya ditulis kembali ke alamat yang sama. Pola baca-ubah-tulis seperti ini sangat umum.
  4. Baris 18 (++*p;): karena operator unary dijalankan kanan-ke-kiri, ekspresi ini di-parse sebagai ++(*p) — menaikkan nilai yang ditunjuk, sehingga x menjadi 51. Pointer p sendiri tidak bergeser.
  5. Baris 21-27 (precedence): *a + 1 berarti (*a) + 1 karena * lebih kuat mengikat daripada +, hasilnya 5 + 1 = 6. Sebaliknya *(a+1) menghitung alamat a+1 dulu (satu elemen int ke kanan, menjelajah ke arr[1]), baru dereference: 15. Kurung menentukan segalanya.

Dereference pada Pointer yang Belum Siap #

Aturan emasnya sederhana: *p hanya boleh dieksekusi bila p berisi alamat objek yang masih hidup. Pointer yang baru dideklarasikan tanpa inisialisasi berisi nilai acak (alamat sampah), dan melakukan dereference padanya adalah undefined behavior — situasi di mana standar C++ tidak menjamin apa pun:

cpp Kode bermasalah — JANGAN dijalankan
int main() {
    int* p;          // berisi alamat sampah, bukan nullptr
    int v = *p;      // UNDEFINED BEHAVIOR: membaca alamat acak
    std::cout << v;
}

Program seperti ini bisa saja crash, bisa mencetak angka tidak masuk akal, bahkan tampak “berjalan normal” lalu merusak data di tempat lain — semuanya tanpa pesan error yang jelas dari compiler. Tidak ada cara yang bisa diandalkan untuk memeriksa apakah pointer tanpa inisialisasi berisi alamat sah; oleh karena itu pencegahannya ada di tangan kita: selalu inisialisasi pointer saat deklarasi, dengan alamat &variabel atau dengan nullptr bila memang belum ada sasarannya. nullptr sendiri adalah topik Chapter berikutnya, dan pointer yang menunjuk objek yang sudah tidak hidup (dangling pointer) dibahas pada bagian akhir Section ini.

Sekarang kita sudah bisa membaca dan menulis melalui pointer. Namun ada satu nilai spesial yang wajib dikuasai sebelum melangkah lebih jauh: cara menyatakan “pointer ini sedang tidak menunjuk apa-apa” dengan aman dan eksplisit.

Referensi: cppreference — operator precedence , cppreference — undefined behavior .