Pointer adalah variabel, dan variabel apa pun memiliki alamat — termasuk pointer itu sendiri. Lalu alamat pointer disimpan di mana? Di variabel lain yang bertipe pointer ke pointer, ditulis int** untuk pointer yang menunjuk pointer ke int. Dereference-nya pun bertingkat: satu * menghasilkan pointer, dua ** menghasilkan nilai akhirnya. Topik ini sering dianggap rumit, padahal mekanismenya persis pointer biasa — hanya dilakukan dua kali. Chapter ini membedah deklarasinya, dua kegunaan klasiknya, dan kapan kita memang butuh menyusunnya sampai dua lapis.

Deklarasi dan Dereference Bertingkat #

Kita bangun rantainya pelan-pelan: x adalah int, p adalah int* yang menunjuk x, dan pp adalah int** yang menunjuk p. Membaca nilai x dari pp butuh dua kali dereference: **pp.

cpp
#include <iostream>

// Mengubah pointer milik caller melalui pointer-to-pointer
void arahkan(int** pp, int* target) {
    *pp = target;
}

int main() {
    int a = 15;
    int b = 40;
    int* p = &a;
    int** pp = &p;  // pp menunjuk pointer p

    std::cout << "*p   : " << *p << "\n";
    std::cout << "**pp : " << **pp << "\n";

    **pp = 16;  // mengubah a lewat dua lapis dereference
    std::cout << "a setelah **pp = 16 : " << a << "\n";

    arahkan(&p, &b);
    std::cout << "p sekarang menunjuk b : " << *p << "\n";
    std::cout << "**pp setelah pindah   : " << **pp << "\n";

    // Array of pointers: kumpulan pointer dalam satu array
    int* daftar[3] = {&a, &b, &a};
    std::cout << "daftar: ";
    for (int i = 0; i < 3; ++i) {
        if (i > 0) std::cout << " ";
        std::cout << *daftar[i];
    }
    std::cout << "\n";

    return 0;
}

Output yang Dihasilkan:

text
*p   : 15
**pp : 15
a setelah **pp = 16 : 16
p sekarang menunjuk b : 40
**pp setelah pindah   : 40
daftar: 16 40 16

Mari kita telusuri:

  1. Baris 12 (int** pp = &p;): p adalah variabel (bertipe int*), jadi &p menghasilkan alamatnya, dan tipe yang cocok menampung alamat int* adalah int**. Rantainya: pp → p → a.
  2. Baris 15-16 (*p vs **pp): *p satu lapis dereference menghasilkan nilai a (15). **pp dua lapis: *pp dulu menghasilkan p, lalu *p-nya menghasilkan a. Keduanya sampai ke nilai yang sama lewat panjang rantai yang berbeda.
  3. Baris 18-19 (**pp = 16;): dua lapis dereference di sisi kiri menulis ke objek paling ujung rantai — a. Kita mengubah a tanpa menyebut a, p, maupun x apa pun selain pp.
  4. Baris 21-23 (arahkan(&p, &b);): kegunaan klasik pertama. Fungsi arahkan menerima int**, lalu *pp = target; mengganti isi pointer milik pemanggil. Ingat Chapter Pointer sebagai Parameter: mengirim p saja hanya menyalin alamat; untuk mengubah variabel p itu sendiri, kita wajib mengirim alamatnya — &p — yang bertipe int**.
  5. Baris 27-31 (daftar): kegunaan klasik kedua — array of pointers. Setiap elemen daftar adalah int* biasa, dan *daftar[i] membaca nilai yang ditunjuknya. Pemilihan &a, &b, &a sengaja menunjukkan bahwa elemen pointer boleh menunjuk objek yang sama.

Setelah arahkan dijalankan, output menegaskan efek gandanya: p menunjuk b sehingga *p bernilai 40, dan karena pp menunjuk p, ikutan **pp juga berubah menjadi 40 — rantai otomatis mengikuti.

Kapan Pointer to Pointer Dibutuhkan #

Meskipun mekanismenya penting dipahami, int** jarang muncul di kode C++ modern:

  • Mengubah pointer di dalam fungsi: pola arahkan(&p, ...) di atas adalah kasus klasiknya; C++ juga menyediakan reference ke pointer (int*&) — perluasan pass-by-reference pada Section Fungsi — untuk peran yang sama dengan tanda & yang lebih sedikit.
  • Array of pointers: kumpulan int* untuk tabel look-up atau array 2D dinamis gaya C; di C++ modern, std::vector<std::vector<int>> atau std::vector<int*> menyembunyikan hampir semua kebutuhan ini.
  • Interoperabilitas dengan API C: banyak fungsi C mengirim hasil lewat parameter T**, jadi kita tetap akan membacanya saat memakai library warisan.

Tiga lapis (int***) dan seterusnya sah secara sintaksis, tetapi kehadirannya hampir selalu sinyal desain yang perlu direvisi.

Rantai pointer bertingkat selesai. Selanjutnya kita periksa satu pointer yang justru sengaja tidak tahu tipenya: void*, pointer serbaguna warisan bahasa C yang masih kita temui di banyak API standar.

Referensi: cppreference — pointer declaration , cppreference — function declaration .