Kata kunci const adalah qualifier yang menandai bahwa suatu nilai tidak boleh diubah setelah inisialisasi. Pemakaian const bukan sekadar dokumentasi—compiler akan menolak penugasan ulang dan mengoptimalkan kode berdasarkan jaminan tersebut. Pada Chapter ini kita akan memetakan empat bentuk pemakaian const: variabel lokal, parameter fungsi, pointer ke const, dan const pointer. Pemahaman kombinasi ini penting karena sintaks const di pointer sering membingungkan pemula bahkan yang sudah berpengalaman.

Variabel const Sederhana #

Bentuk paling dasar const adalah variabel lokal yang nilainya diatur saat deklarasi dan tidak boleh diubah kemudian. Compiler akan memberi error jika kita mencoba menugaskan nilai baru ke variabel tersebut.

c
#include <stdio.h>

int main(void) {
    const double PI = 3.14159;
    double r = 5.0;
    double luas = PI * r * r;

    printf("PI        = %.5f\n", PI);
    printf("r         = %.2f\n", r);
    printf("luas      = %.4f\n", luas);

    /* PI = 3.14;  // ERROR: assignment to const */
    return 0;
}

Output yang Dihasilkan:

text
PI        = 3.14159
r         = 5.00
luas      = 78.5397

Mari kita telaah baris-baris kode di atas:

  1. Baris 4 (const double PI = 3.14159;): variabel PI dideklarasikan sebagai const double; nilainya wajib diberikan saat deklarasi dan tidak bisa diubah setelahnya.
  2. Baris 5 (double r = 5.0;): variabel r biasa; nilainya bisa diubah kapan pun.
  3. Baris 6 (double luas = PI * r * r;): nilai PI dibaca untuk menghitung luas—membaca tidak melanggar const, yang dilarang hanya menulis.
  4. Baris 11 (/* PI = 3.14; */): baris ini dikomentari; jika diaktifkan, compiler akan menghasilkan error assignment of read-only variable 'PI'.

Pointer ke const (Data Konstan, Pointer Bisa Berubah) #

Bentuk const yang paling sering muncul pada API fungsi adalah pointer to const: const int *p atau int const *p (keduanya ekuivalen). Bentuk ini menyatakan bahwa data yang ditunjuk tidak boleh diubah lewat pointer tersebut, tetapi pointer itu sendiri bisa diarahkan ke lokasi lain.

c
#include <stdio.h>

/* Fungsi menerima pointer ke const int: tidak boleh mengubah isi */
void cetak_array(const int *arr, size_t n) {
    for (size_t i = 0; i < n; i++) {
        printf("arr[%zu] = %d\n", i, arr[i]);
    }
}

int main(void) {
    int data[3] = {10, 20, 30};
    cetak_array(data, 3);
    return 0;
}

Output yang Dihasilkan:

text
arr[0] = 10
arr[1] = 20
arr[2] = 30

Pada baris 4, parameter const int *arr menyatakan bahwa fungsi cetak_array berjanji tidak akan mengubah elemen array yang ditunjuk. Pemanggil yang melewatkan array tidak perlu khawatir datanya berubah. Pada baris 5, perulangan membaca elemen dengan aman; jika di dalam loop ada pernyataan arr[i] = 0, compiler akan menolak.

Const Pointer (Pointer Konstan, Data Bisa Berubah) #

Kebalikan dari sebelumnya, const pointer menyatakan bahwa pointer itu sendiri tidak bisa berubah—setelah diinisialisasi menunjuk ke satu alamat, ia akan selalu menunjuk ke sana. Data yang ditunjuk masih bisa diubah. Sintaksnya adalah int * const p = &x;.

c
#include <stdio.h>

int main(void) {
    int x = 10;

    /* Pointer ke const int: isi data tidak bisa diubah via pointer */
    const int *p1 = &x;
    printf("p1 menunjuk ke %d\n", *p1);
    /* *p1 = 20;  // ERROR: assignment to read-only location */

    /* Const pointer to int: pointer tidak bisa diubah, isi bisa */
    int * const p2 = &x;
    *p2 = 99;
    printf("x sekarang = %d\n", x);
    /* p2 = NULL;  // ERROR: assignment to const pointer */

    /* Const pointer to const int: keduanya tidak bisa diubah */
    const int * const p3 = &x;
    printf("p3 menunjuk ke %d\n", *p3);
    return 0;
}

Output yang Dihasilkan:

text
p1 menunjuk ke 10
x sekarang = 99
p3 menunjuk ke 99

Mari kita telaah baris-baris kode di atas:

  1. Baris 6 (const int *p1 = &x;): pointer p1 boleh menunjuk ke mana pun, tetapi data yang ditunjuk tidak bisa diubah lewat p1. Baca dari kiri: “p1 adalah pointer ke const int”.
  2. Baris 11 (int * const p2 = &x;): pointer p2 tidak bisa diubah—harus selalu menunjuk ke x. Tetapi data yang ditunjuk (x) bisa diubah. Baca dari kanan: “p2 adalah const pointer to int”.
  3. Baris 12 (*p2 = 99;): mengubah isi x lewat p2. Karena data tidak const, penugasan diperbolehkan.
  4. Baris 16 (const int * const p3 = &x;): kombinasi keduanya—pointer tidak bisa berubah dan data yang ditunjuk juga tidak bisa diubah lewat p3.

Konvensi const pada Parameter Fungsi #

Sebagai aturan praktis, gunakan const pada parameter pointer jika fungsi tidak boleh mengubah data yang ditunjuk. Hal ini memberi tahu pembaca dan compiler tentang intensi fungsi, sekaligus memungkinkan pemanggil melewatkan data const tanpa cast. Standar library C memakai pola ini secara konsisten—misalnya strlen(const char *s), printf(const char *fmt, ...).

Pemakaian const pada parameter fungsi juga membantu optimasi compiler. Karena compiler tahu data tidak akan diubah, ia bisa menyimpan nilai di register tanpa khawatir nilai tersebut diubah melalui alias pointer lain.

Dengan const qualifier, kita punya alat untuk menandai data yang tidak boleh diubah—baik variabel sederhana, parameter fungsi, maupun pointer dengan berbagai kombinasi. Selanjutnya, kita akan melihat berbagai jenis literal yang bisa dipakai untuk menginisialisasi variabel.