Pada Chapter sebelumnya kita sudah berkenalan dengan variabel sebagai label untuk lokasi memori. Sekarang kita perlu mempelajari cara formal mendeklarasikan variabel dan cara memberikan nilai awal sejak variabel tersebut diciptakan. Deklarasi dan inisialisasi sering dianggap sepele, tetapi kesalahan di sini menjadi sumber bug paling klasik di C: variabel yang dipakai sebelum diberi nilai menghasilkan undefined behavior, dan variabel yang dideklarasikan jauh dari tempat dipakai membuat kode sulit dibaca. Pada Chapter ini kita akan menetapkan pola deklarasi dan inisialisasi yang aman dan konsisten.
Mekanisme Deklarasi #
Deklarasi adalah pernyataan yang memberitahu compiler dua hal: nama variabel dan tipe variabel. Sintaks umumnya adalah <tipe> <nama>;. Pada saat deklarasi tanpa inisialisasi, compiler hanya mengalokasikan ruang memori tetapi tidak mengisinya dengan nilai tertentu. Inilah mengapa variabel lokal yang dideklarasikan tanpa inisialisasi akan berisi garbage value—pola byte apa pun yang sebelumnya tertinggal di lokasi memori tersebut.
#include <stdio.h>
int main(void) {
/* Deklarasi tanpa inisialisasi */
int jumlah;
jumlah = 10;
printf("jumlah = %d\n", jumlah);
/* Deklarasi dengan inisialisasi */
double harga = 15000.75;
printf("harga = %.2f\n", harga);
/* Deklarasi beberapa variabel sekaligus */
int x = 1, y = 2, z = 3;
printf("x=%d, y=%d, z=%d\n", x, y, z);
return 0;
}Output yang Dihasilkan:
jumlah = 10
harga = 15000.75
x=1, y=2, z=3Mari kita telaah baris-baris kode di atas:
- Baris 5 (
int jumlah;): compiler mengalokasikan 4 byte untukjumlahtetapi tidak mengisinya—nilai variabel ini tidak terdefinisi sampai baris 6 memberi nilai10. - Baris 6 (
jumlah = 10;): penugasan pertama. Nilai10ditulis ke memori yang sudah dialokasikan pada baris sebelumnya. - Baris 10 (
double harga = 15000.75;): deklarasi sekaligus inisialisasi. Compiler mengalokasikan 8 byte dan langsung mengisinya dengan nilai15000.75bertipedouble. - Baris 14 (
int x = 1, y = 2, z = 3;): tiga variabel bertipeintdideklarasikan dan langsung diinisialisasi dalam satu pernyataan; setiap variabel tetap perlu inisialisasinya sendiri.
Inisialisasi Saat Deklarasi #
Inisialisasi adalah pemberian nilai pertama ke variabel. Pemberian nilai ini bisa dilakukan bersamaan dengan deklarasi (int a = 5;) atau terpisah setelahnya (int a; a = 5;). Meskipun hasil akhirnya sama, inisialisasi saat deklarasi lebih disarankan karena compiler bisa mengoptimalkan dan memperingatkan kita jika ada jalur kode yang lupa memberi nilai.
Pada C99 ke atas, kita juga bisa menggunakan designated initializer untuk array dan compound literal untuk struktur, tetapi untuk variabel skalar pola yang dipakai tetap <tipe> <nama> = <ekspresi>;. Ekspresi di sisi kanan boleh berupa konstanta, ekspresi aritmetika, atau pemanggilan fungsi.
#include <stdio.h>
int main(void) {
int total = 5 + 3 * 2; /* ekspresi aritmetika */
double rata = (10.0 + 20.0 + 30.0) / 3.0;
char kategori = 'A';
printf("total = %d\n", total);
printf("rata-rata = %.4f\n", rata);
printf("kategori = %c\n", kategori);
return 0;
}Output yang Dihasilkan:
total = 11
rata-rata = 20.0000
kategori = APada baris 4, ekspresi 5 + 3 * 2 dievaluasi sesuai prioritas operator: perkalian 3 * 2 = 6 dilakukan dulu, lalu dijumlahkan dengan 5 sehingga total bernilai 11. Pada baris 5, pembagian menggunakan literal bertipe double (10.0, bukan 10) supaya hasilnya bukan pembagian bilangan bulat melainkan pembagian pecahan.
Bahaya Variabel Tak Terinisialisasi #
Variabel lokal yang dideklarasikan tanpa inisialisasi tidak otomatis bernilai nol. Compiler hanya mengalokasikan ruang; nilai byte di ruang tersebut adalah apa pun yang sebelumnya tertinggal di memori. Memakai variabel dalam kondisi demikian adalah undefined behavior—hasilnya bisa benar secara kebetulan, bisa salah diam-diam, atau bisa membuat program crash.
#include <stdio.h>
int main(void) {
int a; /* tidak diinisialisasi: nilai tak terduga */
int b = 0; /* diinisialisasi eksplisit */
int c = 7; /* langsung diberi nilai awal */
printf("a (tak diinisialisasi) = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
return 0;
}Output yang Dihasilkan:
a (tak diinisialisasi) = 0
b = 0
c = 7Pada keluaran di atas, a kebetulan bernilai 0 karena lokasi memori yang dipilih compiler sedang bersih. Hasil ini tidak boleh diandalkan—program yang sama bisa mencetak nilai negatif acak, nilai positif besar, atau berperilaku aneh jika dijalankan di mesin lain atau setelah program diubah. Inilah alasan flag -Wextra akan memberi peringatan saat kompilasi dan menyarankan kita menginisialisasi variabel sebelum dipakai.
Lokasi Deklarasi: Dekat Tempat Dipakai #
Sejak C99, deklarasi variabel tidak harus berada di awal blok. Kita boleh mendeklarasikan variabel tepat sebelum variabel tersebut dipakai—bahkan di tengah blok if atau for. Pola ini membuat kode lebih mudah dibaca karena pembaca bisa melihat tipe dan nilai awal variabel tepat di tempat variabel itu relevan, bukan dipisah beberapa puluh baris.
#include <stdio.h>
int main(void) {
/* C99: deklarasi di tengah blok, dekat tempat dipakai */
int panjang = 10;
int lebar = 4;
int luas = panjang * lebar;
printf("panjang = %d, lebar = %d\n", panjang, lebar);
/* Deklarasi terlambat hanya jika diperlukan */
if (luas > 30) {
const char *status = "luas besar";
printf("status = %s\n", status);
}
return 0;
}Output yang Dihasilkan:
panjang = 10, lebar = 4
status = luas besarPada baris 9, variabel status dideklarasikan di dalam blok if dan hanya hidup selama blok tersebut dieksekusi. Setelah blok if selesai, memori untuk status dibebaskan. Pola ini mengurangi ruang lingkup variabel (minimize scope) sehingga pembaca tidak perlu melacak variabel yang hanya relevan di satu cabang.
Inisialisasi Agregat untuk Array dan Struct #
Untuk tipe gabungan seperti array dan struct, inisialisasi dilakukan dengan daftar nilai dalam kurung kurawal {...}. Sebagai contoh, int arr[5] = {1, 2, 3, 4, 5}; mengisi seluruh elemen array sekaligus. Topik ini akan dibahas mendalam pada Section array dan struct; yang penting kita catat di sini adalah pola <tipe> <nama> = {...}; berlaku konsisten untuk seluruh tipe agregat.
Dengan pola deklarasi-inisialisasi yang rapi ini, kita siap masuk ke pembahasan setiap tipe data secara spesifik, dimulai dari tipe paling dasar di C: char.