Variabel kontrol loop (counter) adalah jantung dari setiap loop. Walau terlihat sepele, pemilihan tipe data, scope, dan pola update counter yang tepat berpengaruh besar pada kebenaran, keterbacaan, dan keamanan kode. Salah pilih tipe dapat memicu bug off-by-one, warning compiler, atau bahkan undefined behavior seperti integer overflow. Pada chapter ini kita akan menelaah scope variabel yang dideklarasikan di dalam for, pemilihan tipe data untuk counter, serta idiom size_t untuk indeks array yang menjadi standar industri di kode C modern.

Scope Variabel di dalam for #

Sejak C99, kita diperbolehkan mendeklarasikan variabel langsung di dalam init clause for. Variabel seperti ini hanya hidup di dalam blok for—tidak dapat diakses setelah loop selesai. Pembatasan scope ini mengurangi risiko salah pakai variabel di luar loop dan membuat compiler dapat melakukan optimasi lebih agresif:

c
#include <stdio.h>

int main(void) {
    for (int i = 0; i < 3; i = i + 1) {
        int kuadrat = i * i;
        printf("i=%d, kuadrat=%d\n", i, kuadrat);
    }

    /* Baris berikut akan compile error jika di-uncomment karena i dan kuadrat
       sudah keluar dari scope: */
    /* printf("i setelah loop: %d\n", i); */

    printf("Loop selesai, i tidak dapat diakses lagi di sini\n");
    return 0;
}

Output yang Dihasilkan:

text
i=0, kuadrat=0
i=1, kuadrat=1
i=2, kuadrat=4
Loop selesai, i tidak dapat diakses lagi di sini

Mari kita telaah baris-baris kode di atas:

  1. Baris 4 (for (int i = 0; i < 3; i = i + 1)): variabel i dideklarasikan dan diinisialisasi langsung di dalam for. Scope i terbatas pada blok for saja.
  2. Baris 5 (int kuadrat = i * i;): variabel kuadrat dideklarasikan di dalam body loop. kuadrat dihidupkan dan dimatikan pada setiap iterasi—setiap iterasi mendapat salinan kuadrat yang segar.
  3. Baris 6 (printf(...)): mencetak nilai i dan kuadrat pada iterasi saat ini.
  4. Baris 11 (komentar tentang i setelah loop): baris ini dikomentari karena akan memicu compile error. Setelah loop selesai, i dan kuadrat sudah keluar dari scope dan tidak dapat dipakai.

Pemilihan Tipe untuk Counter #

Pilihan tipe data counter bergantung pada rentang nilai dan konteks pemakaian:

KonteksTipe yang DisarankanAlasan
Iterasi array berukuran kecil hingga besarsize_tTipe standar untuk ukuran dan indeks; tidak mungkin negatif.
Counter umum dengan rentang kecil (0..1000)intSederhana, kompatibel dengan kebanyakan API.
Counter dengan rentang sangat besarlong atau long longMenghindari overflow pada iterasi panjang.
Loop hitung mundur dari nilai positifintMemungkinkan counter mencapai -1 sebagai sentinel keluar.

Untuk indeks array, size_t adalah pilihan terbaik karena tipe ini didefinisikan sebagai unsigned integer yang cukup besar untuk menampung indeks array terbesar yang dapat dialokasikan sistem. Operator sizeof juga menghasilkan size_t, sehingga idiom sizeof(arr)/sizeof(arr[0]) cocok secara tipe dengan counter size_t:

c
#include <stdio.h>

int main(void) {
    int data[] = {10, 20, 30, 40, 50};
    size_t n = sizeof(data) / sizeof(data[0]);
    long total = 0;

    for (size_t i = 0; i < n; i = i + 1) {
        total = total + data[i];
    }

    printf("Jumlah elemen: %zu\n", n);
    printf("Total: %ld\n", total);
    return 0;
}

Output yang Dihasilkan:

text
Jumlah elemen: 5
Total: 150

Pada contoh di atas, n bertipe size_t karena hasil sizeof adalah size_t. Counter i juga bertipe size_t agar perbandingan i < n tidak memicu warning -Wsign-compare (membandingkan signed dengan unsigned). Format specifier %zu adalah specifier khusus untuk size_t di printf.

Jebakan Counter Unsigned saat Hitung Mundur #

Salah satu jebakan klasik dengan counter unsigned adalah loop hitung mundur. Banyak pemula menulis for (unsigned i = n - 1; i >= 0; i = i - 1) dengan asumsi loop akan berhenti saat i menjadi -1. Asumsi ini salah—unsigned tidak pernah negatif, sehingga i >= 0 selalu true, dan loop berjalan tanpa henti:

c
#include <stdio.h>

int main(void) {
    unsigned int n = 5;

    /* Loop berjalan mundur dari 4 sampai 0 */
    for (unsigned int i = n - 1; i < n; i = i - 1) {
        printf("i = %u\n", i);
    }

    printf("Setelah loop\n");
    return 0;
}

Output yang Dihasilkan:

text
i = 4
i = 3
i = 2
i = 1
i = 0
Setelah loop

Pada contoh di atas, kita tidak memakai i >= 0 sebagai kondisi (yang akan menjadi infinite loop), melainkan memakai idiom i < n. Saat i = 0 dan dikurangi satu, nilai i wrap-around menjadi UINT_MAX (sekitar 4 miliar), yang mana UINT_MAX < 5 adalah false—loop berhenti. Idiom ini adalah trik standar untuk hitung mundur dengan unsigned.

Konvensi Penamaan Counter #

Meskipun C tidak memaksakan aturan penamaan, beberapa konvensi telah menjadi standar industri:

  • i, j, k untuk counter loop biasa (terutama di nested loops).
  • idx atau index untuk indeks array yang bermakna.
  • row, col untuk iterasi matriks.
  • n untuk jumlah elemen (sering size_t).
  • count untuk penghitung jumlah iterasi atau jumlah item yang diproses.

Pilih nama yang mencerminkan peran variabel dalam konteks kode. Nama i cocok untuk loop pendek dan jelas konteksnya; nama seperti baris_produk lebih cocok saat loop mengiterasi baris tabel produk di mana makna indeks penting.