Setiap variabel di C memiliki scope—rentang program di mana nama variabel tersebut dapat dipakai. Memahami scope penting karena kesalahan scope menyebabkan kesalahpahaman umum: variabel yang terlihat di satu fungsi belum tentu terlihat di fungsi lain, dan dua variabel bernama sama di blok berbeda sebenarnya adalah dua entitas yang terpisah. C mengenal empat jenis scope: block scope, function scope, file scope, dan prototype scope. Pada chapter ini kita akan menelusuri keempatnya dengan contoh konkret, serta fenomena variable shadowing yang sering membingungkan pemula.

Block Scope #

Block scope berarti variabel hanya terlihat di dalam blok { } tempat variabel dideklarasikan, beserta semua blok bersarang di dalamnya. Saat blok selesai dieksekusi, variabel lokal di dalamnya dihancurkan. Deklarasi di dalam loop for (misalnya for (int i = 0; ...)) juga menciptakan variabel dengan block scope yang hanya hidup selama loop berjalan.

c
#include <stdio.h>

int counter = 100;            /* File scope: terlihat di seluruh file */

void naikkan_global(void) {
    counter++;                /* Mengakses file-scope variable */
}

void demo_block_scope(void) {
    int lokal = 5;
    printf("Luar blok: lokal = %d\n", lokal);

    /* Block scope dalam */
    {
        int lokal = 50;       /* Shadow: menyembunyikan lokal di blok luar */
        printf("Dalam blok: lokal = %d\n", lokal);
    }

    printf("Setelah blok: lokal = %d\n", lokal);
}

int main(void) {
    naikkan_global();
    printf("counter global = %d\n", counter);
    demo_block_scope();
    return 0;
}

Output yang Dihasilkan:

text
counter global = 101
Luar blok: lokal = 5
Dalam blok: lokal = 50
Setelah blok: lokal = 5

Mari kita telaah baris-baris kode di atas:

  1. Baris 3 (int counter = 100;): variabel counter dideklarasikan di luar fungsi apapun, sehingga memiliki file scope—terlihat di seluruh file source ini mulai dari titik deklarasi.
  2. Baris 6 (counter++;): di dalam fungsi naikkan_global, identifier counter menunjuk ke variabel file-scope di atas. Nilainya dinaikkan dari 100 menjadi 101.
  3. Baris 10 (int lokal = 5;): variabel lokal di dalam fungsi demo_block_scope memiliki block scope—terlihat dari titik deklarasi sampai akhir body fungsi.
  4. Baris 14 (int lokal = 50;): di dalam blok { }, deklarasi kedua int lokal = 50; ini menyembunyikan (shadow) variabel lokal di blok luar. Saat di dalam blok dalam, lokal menunjuk ke 50, bukan 5.
  5. Baris 18 (printf("Setelah blok: lokal = %d\n", lokal);): setelah blok dalam selesai, variabel lokal = 50 sudah dihancurkan. Identifier lokal kembali menunjuk ke lokal = 5 di blok luar fungsi.

File Scope #

Variabel atau fungsi yang dideklarasikan di luar blok fungsi apapun memiliki file scope—terlihat dari titik deklarasi sampai akhir translation unit (file source yang sedang dikompilasi, beserta file yang di-#include). Variabel file scope biasanya disebut global variable; kita akan membahas pro dan kontra penggunaannya pada chapter Local dan Global Variables.

Pada contoh di atas, variabel counter memiliki file scope dan dapat diakses dari fungsi naikkan_global, demo_block_scope, dan main—selama tidak di-shadow oleh variabel lokal dengan nama yang sama.

Function Scope #

Function scope hanya berlaku untuk label yang dipakai bersama statement goto. Label hanya terlihat di dalam fungsi tempat label dideklarasikan—tidak dapat dipanggil dari fungsi lain. Tidak ada variabel dengan function scope; ini adalah satu-satunya scope yang khusus untuk label.

c
#include <stdio.h>

/* Function scope: label hanya terlihat di dalam fungsi */
int cari_pertama_positif(const int arr[], int n) {
    int hasil = -1;
    for (int i = 0; i < n; i++) {
        if (arr[i] > 0) {
            hasil = i;
            goto selesai;        /* Lompat ke label selesai */
        }
    }
selesai:
    return hasil;
}

int main(void) {
    int data[] = {-3, -1, 0, 5, -2};
    int n = sizeof(data) / sizeof(data[0]);
    int pos = cari_pertama_positif(data, n);
    printf("Posisi pertama positif: %d\n", pos);
    return 0;
}

Output yang Dihasilkan:

text
Posisi pertama positif: 3

Pada contoh di atas, label selesai: hanya terlihat di dalam fungsi cari_pertama_positif. Statement goto selesai melompat ke label tersebut. Fungsi main atau fungsi lain tidak dapat menulis goto selesai ke label ini—label bersifat lokal untuk fungsi tempat ia dideklarasikan.

Prototype Scope #

Parameter pada function declaration (prototype) memiliki prototype scope—nama parameter hanya berlaku di dalam prototype itu sendiri. Akibatnya, nama parameter pada prototype dan pada definition boleh berbeda; compiler hanya peduli pada tipe dan urutan parameter.

c
#include <stdio.h>

/* Prototype scope: nama parameter hanya berlaku di dalam prototype */
int tambah(int a, int b);     /* a, b hanya ada di baris ini */

void loop_demo(void) {
    /* Loop scope: variabel i hanya hidup selama loop */
    for (int i = 0; i < 3; i++) {
        int kuadrat = i * i;   /* kuadrat dibuat ulang tiap iterasi */
        printf("iterasi %d: kuadrat = %d\n", i, kuadrat);
    }
    /* i dan kuadrat sudah tidak terlihat di sini */
}

int main(void) {
    loop_demo();
    return 0;
}

int tambah(int x, int y) {     /* Nama parameter boleh beda dengan prototype */
    return x + y;
}

Output yang Dihasilkan:

text
iterasi 0: kuadrat = 0
iterasi 1: kuadrat = 1
iterasi 2: kuadrat = 4

Pada contoh di atas, parameter a dan b pada prototype int tambah(int a, int b); hanya ada di baris prototype itu—di luar baris tersebut, nama a dan b tidak terlihat. Definisi int tambah(int x, int y) boleh memakai nama parameter yang berbeda (x, y) karena yang penting bagi compiler adalah tipe dan urutan. Loop for di dalam loop_demo juga menciptakan variabel i dengan loop scope (subset dari block scope) yang hanya hidup selama loop berjalan; variabel kuadrat di dalam loop dibuat ulang setiap iterasi.

Dengan pondasi scope yang jelas, kita siap melangkah ke chapter Local dan Global Variables untuk membahas pro dan kontra penggunaan variabel global versus variabel lokal.