Menu

For Loop di C: Sintaks, Contoh, dan Kesalahan Umum

Cara mengulang kode dengan for loop di C: header tiga bagian, menghitung naik dan turun, menelusuri array dengan trik sizeof, nested loop, loop tanpa akhir, serta bug off-by-one dan unsigned yang menjebak semua orang.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Kenapa for Loop

if dan switch memilih satu cabang lalu menjalankannya sekali. Program sungguhan perlu melakukan sesuatu berulang kali: mencetak setiap nilai, menjumlahkan sederet angka, menggambar sepuluh baris sebuah grid, mencoba setiap karakter dalam string. Loop for adalah andalan C untuk mengulang kode sebanyak jumlah yang diketahui, dengan counter yang kamu kendalikan.

Semua yang dibutuhkan loop for ada di satu header yang ringkas, jadi "berapa kali, dan bagaimana" terlihat dalam satu baris.

Header Tiga Bagian

Header for punya tiga bagian yang dipisahkan titik koma: inisialisasi, kondisi, dan update.

for (initializer; condition; update) {
    // body - runs while the condition is nonzero
}

Ketiganya dijalankan dalam urutan tertentu, dan memahaminya menjelaskan setiap loop for yang akan kamu baca:

  1. Inisialisasi dijalankan sekali, sebelum yang lain.
  2. Kondisi diuji. Kalau bernilai nol, loop langsung berakhir.
  3. Body dijalankan.
  4. Update dijalankan.
  5. Kembali ke langkah 2.

Telusuri loop di atas dengan daftar itu: int i = 0 dijalankan sekali. 0 < 5 terpenuhi, jadi body mencetak i = 0, lalu i++ membuat i bernilai 1. Kondisi diuji lagi, dan seterusnya. Saat i mencapai 5, pengujiannya gagal, body dilewati, dan done dicetak. Body berjalan tepat lima kali, dengan i bernilai 0 sampai 4.

Dua konsekuensi langsung mengikutinya. Kondisi diperiksa sebelum putaran pertama, jadi loop yang kondisinya bernilai false sejak awal berjalan nol kali: for (int i = 10; i < 5; i++) sama sekali tidak pernah masuk ke body. Lalu update dijalankan setelah body, jadi i masih menyimpan nilai lamanya di sepanjang body.

Mendeklarasikan counter di dalam header (int i = 0) sudah sah sejak C99 dan merupakan pilihan default yang tepat: i lalu hanya ada di dalam loop, sehingga tidak bisa bentrok dengan apa pun setelahnya, dan setiap loop di sebuah fungsi bebas memakai ulang nama itu.

Menghitung Naik, Turun, dan dengan Langkah Tertentu

Update tidak terbatas pada i++. Hitung mundur, melangkah sebanyak apa pun, atau gandakan di setiap putaran:

Sesuaikan kondisi dengan update-nya. Menghitung naik dipasangkan dengan < atau <=; menghitung turun dipasangkan dengan > atau >=. Salah memasangkannya adalah cara menulis loop yang tidak pernah berhenti.

Perhatikan bahwa loop kedua memakai <= 10 karena 10 adalah nilai yang ingin kita sertakan, sedangkan contoh pertama memakai < 5 karena 5 tidak termasuk. Pilihan itulah tempat lahirnya bug off-by-one, jadi putuskan dengan sadar: i < n berjalan n kali mulai dari 0; i <= n berjalan n + 1 kali.

Menelusuri Array dengan Loop

Pemakaian loop penghitung yang paling umum adalah menelusuri array berdasarkan indeks. Counter-nya sekaligus menjadi posisi yang kamu baca.

Ada dua hal yang bisa diambil dari contoh ini.

Trik sizeof. sizeof(scores) adalah ukuran seluruh array dalam byte, dan sizeof(scores[0]) adalah ukuran satu elemen, jadi hasil baginya adalah jumlah elemen. Hasilnya otomatis menyesuaikan saat kamu menambah elemen, sesuatu yang tidak bisa dilakukan 5 yang ditulis langsung. Masalahnya, dan ini masalah besar, trik itu hanya berfungsi di tempat array itu sendiri berada dalam scope. Kirim array ke sebuah fungsi dan ia berubah menjadi pointer, sehingga sizeof di sana memberikan ukuran pointer. Di dalam fungsi, selalu terima panjangnya sebagai parameter terpisah.

Kondisinya i < n, tidak pernah i <= n. Array berisi lima elemen punya indeks valid 0 sampai 4. Membaca scores[5] adalah undefined behavior: program bisa mencetak nilai sampah, crash, atau terlihat berjalan normal padahal diam-diam merusak sesuatu yang lain. C sama sekali tidak memeriksa batas array, jadi ini sepenuhnya tanggung jawabmu.

Menelusuri array dari belakang adalah ide yang sama secara terbalik:

Mulai dari n - 1 (indeks valid terakhir), berhenti di 0 termasuk nol itu sendiri, karena itulah >=, bukan >. Biarkan i tetap int signed di sini; bagian berikutnya menjelaskan alasannya.

Nested Loop

Taruh satu for di dalam loop lain untuk bekerja dengan grid, tabel, atau setiap pasangan item. Loop dalam berjalan sampai selesai untuk setiap satu langkah loop luar.

Loop luar menetapkan sebuah row; loop dalam menyapu setiap col untuk baris itu; printf("\n") setelah loop dalam mengakhiri barisnya. Pindahkan baris baru itu ke dalam loop dalam dan seluruh tabel menjadi satu kolom. Ini layak dicoba, karena membuat struktur nesting-nya jadi konkret.

Beri nama counter yang berbeda. row/col atau i/j boleh; memakai i untuk keduanya menutupi counter luar dan menghasilkan hasil yang membingungkan. Perhatikan juga biayanya: loop n kali di dalam loop n kali menjalankan body sebanyak n * n kali, jadi sepasang loop dengan 1.000 iterasi berarti sejuta putaran.

Berikut nested loop yang mengerjakan sesuatu yang nyata, yaitu segitiga bintang, di mana batas loop dalam bergantung pada counter luar:

break dan continue

Dua kata kunci mengubah alur di tengah loop. break langsung keluar dari loop; continue melewati sisa putaran saat ini dan melompat ke update.

Loop pertama berhenti begitu menemukan 7 dan tidak pernah memeriksa 93 nilai sisanya. Loop kedua memakai continue untuk melewati print bagi bilangan genap; i++ di header tetap dijalankan, jadi loop terus maju. Ada penjelasan jauh lebih lengkap tentang keduanya di break dan continue, termasuk cara keluar dari loop bersarang, yang tidak bisa dilakukan dengan satu break.

Loop Tanpa Akhir dan Bagian yang Kosong

Ketiga bagian header bersifat opsional. Hilangkan kondisinya dan ia dianggap selalu true:

for (;;) {
    /* runs forever - exit with break or return */
}

for (;;) adalah loop tanpa akhir yang lazim di C, dan titik komanya tetap wajib. Ini bukan kesalahan selama ada sesuatu di dalamnya yang bisa break, return, atau exit: event loop dan loop "terus tanya sampai input valid" ditulis persis seperti ini.

Bagian lain juga boleh dihilangkan. Kalau counter-nya sudah ada, lewati inisialisasi; kalau body yang memajukannya, lewati update:

int i = 0;
for (; i < n; ) {
    /* ... */
    i += step;
}

Itu sah, tetapi lebih sulit dibaca daripada loop while yang sebenarnya. Pilih for kalau counter, batasnya, dan langkahnya memang sepatutnya berada bersama di header, dan loop while kalau tidak.

Operator Koma di Header

Inisialisasi dan update masing-masing bisa berisi beberapa ekspresi yang dipisahkan koma. Begitulah cara menjalankan dua counter sekaligus:

int i = 0, j = len - 1 mendeklarasikan kedua counter, dan i++, j-- memajukan keduanya. Inilah operator koma, yang mengevaluasi operand-operandnya secara berurutan. Gunakan untuk counter yang memang berjalan paralel; menjejalkan pekerjaan yang tidak berhubungan ke dalam header hanya menyembunyikannya.

Jebakan Umum

Segelintir jebakan menjadi penyebab sebagian besar bug for loop di C.

Off-by-one. i <= n pada array yang indeksnya mulai dari nol membaca satu elemen melewati ujungnya. Gunakan i < n untuk "n kali mulai dari 0".

Titik koma setelah header. Kode ini bisa dikompilasi dan hampir tidak pernah sesuai maksudmu:

/* BUG: the loop body is the empty statement; the printf runs once */
for (int i = 0; i < 5; i++);
{
    printf("%d\n", i);
}

; itu menjadi body, jadi loop berputar lima kali tanpa melakukan apa-apa dan kurung kurawal di bawahnya berjalan sekali sebagai blok biasa. gcc -Wall memberi peringatan untuk ini.

Counter unsigned yang menghitung turun. Ini loop tanpa akhir:

/* BUG: an unsigned value is never < 0 */
for (size_t i = n - 1; i >= 0; i--) {
    process(a[i]);
}

i >= 0 selalu bernilai true untuk tipe unsigned. Saat i mencapai 0, i-- melingkar menjadi bilangan positif yang sangat besar dan loop terus berjalan ke memori yang bukan miliknya. Gunakan int signed untuk hitungan mundur, atau tulis kondisinya sebagai for (size_t i = n; i-- > 0; ), yang mengurangi dan menguji dalam satu langkah dan berhenti dengan benar di nol.

Mengubah counter di dua tempat. Mengubah i di dalam body sekaligus di header membuat jumlah iterasinya tidak bisa diprediksi. Pilih satu tempat.

Counter floating-point. for (double x = 0.0; x != 1.0; x += 0.1) mungkin tidak pernah berhenti, karena 0.1 tidak punya representasi biner yang pasti dan jumlahnya melangkahi 1.0 tanpa pernah tepat mengenainya. Lakukan loop dengan hitungan integer dan hitung nilainya di dalam:

for (int i = 0; i <= 10; i++) {
    double x = i / 10.0;
    /* ... */
}

Mengubah panjang array saat sedang menelusurinya. Kondisi i < n membaca ulang n di setiap putaran, jadi kalau body memperkecil kumpulan datanya, sesuaikan indeksnya dengan sengaja, jangan biarkan keduanya tidak lagi selaras.

Pertanyaan yang sering diajukan

Bagaimana cara menulis for loop di C?

Taruh tiga bagian di header, dipisahkan titik koma, yaitu inisialisasi, kondisi, dan update: for (int i = 0; i < 5; i++) { printf("%d\n", i); }. Kode itu menjalankan body lima kali dengan i bernilai 0 sampai 4, dan berhenti begitu kondisinya bernilai false.

Bagaimana cara menelusuri array dengan loop di C?

Hitung indeks dari 0 sampai (tidak termasuk) panjang array: for (int i = 0; i < n; i++) { sum += a[i]; }. Untuk array yang dideklarasikan di fungsi yang sama, kamu bisa menghitung panjangnya dengan sizeof(a) / sizeof(a[0]); begitu array dikirim ke fungsi, trik itu tidak lagi berfungsi, jadi kirim panjangnya sebagai parameter.

Kenapa for loop C saya berjalan satu kali kebanyakan?

Itulah bug off-by-one. Pada array berukuran n yang indeksnya mulai dari nol, indeks yang valid adalah 0 sampai n - 1, jadi i <= n menjalankan satu iterasi ekstra dan membaca melewati ujung array, yang merupakan undefined behavior. Pilihan default yang aman adalah i < n.

Apakah variabel loop bisa dideklarasikan di dalam for loop C?

Bisa, sejak C99: for (int i = 0; i < n; i++). Variabel itu lalu hanya ada di dalam loop, persis yang kamu inginkan. Kompilasi dengan gcc -std=c99 atau yang lebih baru (GCC dan clang modern memakai C17 secara default, jadi langsung berfungsi); gaya C89 lama mendeklarasikan i sebelum loop.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai