Setiap variabel di C dapat dikategorikan sebagai local variable (variabel lokal, hanya terlihat di dalam blok tempat ia dideklarasikan) atau global variable (variabel global, terlihat di seluruh file atau bahkan lintas file). Pilihan antara lokal dan global memengaruhi keterbacaan, modularitas, dan kemudahan pengujian kode. Variabel lokal mengisolasi state per-fungsi; variabel global membagi state lintas-fungsi dengan konsekuensi sulit dilacak. Pada chapter ini kita akan menelusuri perbedaan kedua jenis variabel, penggunaan keyword extern untuk akses lintas-file, serta kapan sebaiknya menghindari variabel global.
Karakteristik Local Variable #
Local variable dideklarasikan di dalam blok fungsi atau blok { }. Local variable disimpan di call stack dan dibuat saat blok dieksekusi, lalu dihancurkan saat blok selesai. Local variable tidak otomatis diinisialisasi—membaca nilai sebelum penugasan adalah undefined behavior. Setiap pemanggilan fungsi mendapatkan set lokal variabelnya sendiri.
#include <stdio.h>
/* Global variable: file scope, default init 0 */
int hitung_total = 0;
int max_panggilan = 3;
/* Local variable: hidup hanya selama pemanggilan fungsi */
void catat_panggilan(void) {
int lokal_panggilan = 0; /* Lokal, dibuat ulang tiap kali */
lokal_panggilan++;
hitung_total++; /* Global dapat diakses dari mana saja */
printf("lokal_panggilan = %d, hitung_total = %d\n",
lokal_panggilan, hitung_total);
}
int main(void) {
/* Global terlihat dari sini */
printf("Awal: hitung_total = %d, max_panggilan = %d\n",
hitung_total, max_panggilan);
for (int i = 0; i < max_panggilan; i++) {
catat_panggilan();
}
/* lokal_panggilan tidak terlihat di sini - compile error jika dipakai */
return 0;
}Output yang Dihasilkan:
Awal: hitung_total = 0, max_panggilan = 3
lokal_panggilan = 1, hitung_total = 1
lokal_panggilan = 1, hitung_total = 2
lokal_panggilan = 1, hitung_total = 3Mari kita telaah baris-baris kode di atas:
- Baris 4 (
int hitung_total = 0;): variabel global di file scope. Inisialisasi eksplisit= 0sebenarnya tidak diperlukan—variabel global selalu di-zero-initialize secara default. - Baris 9 (
int lokal_panggilan = 0;): variabel lokal di dalam fungsicatat_panggilan. Variabel ini dibuat ulang setiap kali fungsi dipanggil; nilai0adalah inisialisasi eksplisit—tanpa inisialisasi, isi variabel tidak terprediksi. - Baris 10 (
lokal_panggilan++;): inkremen lokal. Karena variabel lokal baru dibuat setiap pemanggilan, nilainya selalu1setelah inkremen—tidak pernah bertambah di antara pemanggilan. - Baris 11 (
hitung_total++;): inkremen global. Variabel global tetap hidup di antara pemanggilan fungsi, sehingga nilainya terus bertambah:0 → 1 → 2 → 3. - Baris 17-19 (loop
for): loop memanggilcatat_panggilantiga kali. Setiap pemanggilan mencetaklokal_panggilan = 1(selalu mulai dari0lalu dinaikkan ke1) danhitung_totalyang terus bertambah.
Karakteristik Global Variable #
Global variable dideklarasikan di luar fungsi apapun. Global variable memiliki file scope dan static storage duration—dialokasikan saat program dimulai dan tetap hidup sampai program selesai. Global variable selalu di-zero-initialize secara default (nilai 0 untuk int, 0.0 untuk double, NULL untuk pointer). Global variable dapat diakses dari fungsi manapun dalam file yang sama, atau bahkan dari file lain melalui keyword extern.
Akses Lintas-File dengan extern #
Untuk file besar yang terbagi ke beberapa .c, kita dapat membagi global variable lintas file. Variabel didefinisikan di satu file, dan dideklarasikan sebagai extern di file lain (biasanya lewat header). Keyword extern memberitahu compiler bahwa variabel ada di file lain—linker yang akan menyambungkannya.
konfigurasi.h:
#ifndef KONFIGURASI_H
#define KONFIGURASI_H
/* extern declaration - memberitahu compiler variabel ada di file lain */
extern int batas_maks;
extern int debug_mode;
void cetak_konfigurasi(void);
#endifkonfigurasi.c:
#include <stdio.h>
#include "konfigurasi.h"
/* Definisi variabel global di file ini */
int batas_maks = 100;
int debug_mode = 1;
void cetak_konfigurasi(void) {
printf("batas_maks = %d, debug_mode = %d\n", batas_maks, debug_mode);
}main.c:
#include <stdio.h>
#include "konfigurasi.h"
int main(void) {
/* Variabel global di file konfigurasi.c dapat diakses via extern */
printf("Dari main: batas_maks = %d, debug_mode = %d\n", batas_maks, debug_mode);
cetak_konfigurasi();
return 0;
}Compile dan jalankan:
gcc -std=c11 -Wall -Wextra konfigurasi.c main.c -o demo_extern
./demo_externOutput yang Dihasilkan:
Dari main: batas_maks = 100, debug_mode = 1
batas_maks = 100, debug_mode = 1File konfigurasi.c adalah satu-satunya tempat variabel batas_maks dan debug_mode didefinisikan (dialokasikan memori). File main.c hanya mendeklarasikan (memberitahu compiler bahwa variabel ini ada) lewat extern int batas_maks;. Linker kemudian menyambungkan kedua simbol tersebut. Pola ini memungkinkan konfigurasi global dibagi lintas file tanpa duplikasi definisi.
Jebakan Global Mutable State #
Walaupun variabel global tampak nyaman, global mutable state sering menjadi sumber bug yang sulit dilacak. Karena variabel global dapat dimodifikasi dari fungsi manapun, perubahan tak terduga dapat terjadi tanpa kita sadari.
#include <stdio.h>
/* Jebakan: global terlihat mudah berubah dari mana saja */
int saldo = 1000;
void tarik(int jumlah) {
saldo -= jumlah;
printf("Tarik %d, saldo = %d\n", jumlah, saldo);
}
void setorkan(int jumlah) {
saldo += jumlah;
printf("Setor %d, saldo = %d\n", jumlah, saldo);
}
int main(void) {
setorkan(500);
tarik(200);
tarik(100);
printf("Saldo akhir: %d\n", saldo);
return 0;
}Output yang Dihasilkan:
Setor 500, saldo = 1500
Tarik 200, saldo = 1300
Tarik 100, saldo = 1200
Saldo akhir: 1200Pada contoh di atas, saldo adalah variabel global yang diubah oleh fungsi tarik dan setorkan. Walaupun kode di atas bekerja dengan benar, masalah muncul saat program tumbuh: setiap fungsi baru yang mengakses saldo dapat menyebabkan perubahan tak terduga. Bila ada bug “saldo tiba-tiba menjadi nol”, debugging menjadi sulit karena setiap fungsi di file ini bisa jadi pelakunya. Dalam program paralel (multithreaded), variabel global tanpa proteksi mutex akan menyebabkan data race.
Dengan pemahaman trade-off lokal vs global, kita siap melangkah ke chapter Static Local Variables untuk membahas satu varian menarik: variabel lokal yang tetap hidup di antara pemanggilan fungsi.