Perulangan

for, while, do-while, dan range-based for atas array dan string.

Daftar isi

Perulangan mengeksekusi blok pernyataan yang sama berkali-kali selama kondisinya terpenuhi, sehingga pekerjaan berulang tidak perlu ditulis berulang. Topik ini membahas perulangan for dengan pencacahnya, pasangan while dan do-while, serta range-based for yang mengunjungi setiap elemen array dan string. Setiap bentuk disertai program utuh dan keluaran aslinya, dan topik ditutup dengan panduan memilih bentuk yang tepat untuk setiap kebutuhan.

Perulangan for#

Perulangan for menggabungkan tiga bagian dalam satu kepala, yaitu inisialisasi, kondisi, dan pembaruan, ditulis for (inisialisasi; kondisi; pembaruan). Inisialisasi dijalankan sekali di awal, kondisi diuji sebelum setiap putaran, dan pembaruan dieksekusi setelah badan perulangan selesai. Variabel pencacah yang dideklarasikan pada bagian inisialisasi hidup hanya di dalam perulangan itu, sehingga nama yang sama bebas digunakan lagi oleh perulangan lain. Susunan satu baris ini membuat keseluruhan mekanisme putaran terlihat pada satu tempat. Bentuk for paling tepat ketika banyaknya putaran diketahui atau berpola tetap.

Program berikut mencetak tabel perkalian tujuh dari satu sampai sepuluh. Kepala perulangannya memuat seluruh aturan putarannya, dan badannya hanya berisi satu pernyataan cetak.

cpp tabel-perkalian.cpp
#include <iostream>

int main() {
    for (int i = 1; i <= 10; ++i) {
        std::cout << i << " x 7 = " << i * 7 << '\n';
    }
    return 0;
}
text Keluaran
1 x 7 = 7
2 x 7 = 14
3 x 7 = 21
4 x 7 = 28
5 x 7 = 35
6 x 7 = 42
7 x 7 = 49
8 x 7 = 56
9 x 7 = 63
10 x 7 = 70

Pembaruan ditulis dengan bentuk awalan ++i karena nilai lama i tidak diperlukan pada baris tersebut, sedangkan kondisi i <= 10 menjaga putaran terakhir tetap terjadi. Bentuk awalan menjadi kebiasaan yang dianjurkan karena tidak perlu menyimpan nilai lama untuk dibaca kembali. Mengubah batas menjadi i < 10 membuang putaran kesepuluh, dan perbedaan sekecil ini merupakan sumber kesalahan off-by-one yang paling lazim. Menetapkan batas secara sadar sejak awal, kemudian mengujinya dengan kasus tepi, mencegah kesalahan semacam itu.

while dan do-while#

Perulangan while hanya menetapkan kondisinya, sehingga bentuknya tepat ketika banyaknya putaran tidak diketahui di awal. Kondisi diuji sebelum badan dijalankan, sehingga badan mungkin tidak pernah berjalan apabila kondisi sejak awal bernilai false. Bentuk do-while membalik urutan tersebut, yaitu badan dieksekusi terlebih dahulu dan kondisi diuji sesudahnya, sehingga badan dijamin berjalan sekali. Kepala do-while diakhiri tanda titik koma setelah kondisi, dan kelalaian menuliskannya menjadi error kompilasi yang sering terjadi. Pada kedua bentuk ini, badan perulangan harus mengubah nilai yang diuji kondisinya agar perulangan tidak berjalan tanpa akhir.

Program berikut menjumlahkan digit sebuah bilangan menggunakan while, kemudian menunjukkan perilaku do-while pada bilangan 0. Sisa pembagian nilai % 10 mengambil digit terakhir, sedangkan pembagian bulat nilai /= 10 membuang digit itu, dan pengulangan keduanya berhenti ketika nilai mencapai 0. Percobaan kedua pada bilangan 0 memperlihatkan perbedaan urutan pengujian antara kedua bentuk.

cpp jumlah-digit.cpp
#include <iostream>

int main() {
    int nilai = 4092;
    int jumlah = 0;

    while (nilai > 0) {
        jumlah += nilai % 10;
        nilai /= 10;
    }
    std::cout << "Jumlah digit 4092: " << jumlah << '\n';

    int kosong = 0;
    int jumlahKosong = 0;
    do {
        jumlahKosong += kosong % 10;
        kosong /= 10;
    } while (kosong > 0);
    std::cout << "Jumlah digit 0: " << jumlahKosong << '\n';

    return 0;
}
text Keluaran
Jumlah digit 4092: 15
Jumlah digit 0: 0

Empat putaran while mengambil digit 4, 0, 9, dan 2, sehingga jumlahnya 15. Badan do-while tetap berjalan sekali meskipun kosong bernilai 0 sejak awal, tetapi hasilnya tetap 0 karena satu-satunya putaran itu tidak menambahkan apa pun. Pada kasus lain yang badannya berbahaya apabila dijalankan dengan data kosong, while menjadi pilihan yang lebih aman.

Range-based for atas array dan string#

Bentuk range-based for yang diperkenalkan pada C++11 mengunjungi setiap elemen sebuah rentang tanpa pencacah dan tanpa indeks, ditulis for (deklarasi : rentang). Rentangnya dapat berupa array, std::string, atau container pustaka standar lainnya. Satu putaran berlangsung untuk setiap elemen, dan elemennya dibaca melalui variabel pada bagian deklarasi. Tidak ada indeks yang dirawat, sehingga kesalahan batas yang biasa menimpa for klasik tidak mungkin muncul pada bentuk ini. Bentuknya juga lebih pendek karena tiga bagian mekanis for klasik tidak ditulis sama sekali.

Program berikut menjumlahkan daftar harga belanja, kemudian menghitung huruf vokal pada sebuah kata. Perulangan pertamanya membaca array, sedangkan perulangan keduanya membaca string karakter demi karakter.

cpp daftar-belanja.cpp
#include <iostream>
#include <string>

int main() {
    int harga[] = {3500, 12000, 7800, 4400};
    int total = 0;

    for (int h : harga) {
        total += h;
    }
    std::cout << "Total belanja: " << total << '\n';

    std::string kata = "kembang";
    int jumlahVokal = 0;

    for (char c : kata) {
        if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') {
            ++jumlahVokal;
        }
    }
    std::cout << "Jumlah huruf vokal: " << jumlahVokal << '\n';
    return 0;
}
text Keluaran
Total belanja: 27700
Jumlah huruf vokal: 2

Perulangan pertama membaca setiap elemen array harga sebagai int, sedangkan perulangan kedua membaca kata sebagai deretan char. Apabila elemen perlu diubah di dalam badan perulangan, deklarasinya ditulis sebagai referensi (reference), yaitu nama yang merujuk elemen yang sama, misalnya for (int& h : harga). Apabila elemen hanya dibaca dan ukurannya besar, bentuk for (const auto& x : ...) menghindari penyalinan yang tidak perlu.

Memilih bentuk perulangan#

Keempat bentuk perulangan saling melengkapi, dan pilihan yang tepat membuat maksud kode terbaca tanpa penjelasan tambahan. Tabel berikut meringkas ciri setiap bentuk beserta waktu pengujian kondisinya.

BentukCocok untukPengujian kondisi
forBanyaknya putaran diketahui atau berpola tetapSebelum setiap putaran
whilePutaran bergantung pada kondisi yang berubah di badanSebelum setiap putaran
do-whileBadan yang wajib berjalan sekali, misalnya menu pilihanSesudah badan
Range-based forMengunjungi seluruh elemen array, string, atau containerTanpa kondisi eksplisit

Rentang yang dikunjungi range-based for ditentukan ketika perulangan dimulai, sehingga perubahan ukuran container di tengah jalan tidak ikut dihitung dan justru berisiko. Ketika putaran bergantung pada masukan pengguna atau kegagalan proses, while menggambarkan maksud itu dengan lebih tepat. Perulangan for klasik tetap unggul ketika langkahnya tidak satu demi satu, misalnya mengunjungi elemen bernomor genap saja. Selebihnya, pilihlah bentuk yang paling sederhana yang memenuhi kebutuhan, karena kebiasaan itu menjaga kode tetap mudah ditelusuri.

Kesalahan umum#

Tiga kesalahan berikut paling sering muncul ketika perulangan ditulis. Semuanya berakibat putaran yang salah atau perulangan yang tidak berhenti.

  1. Batas putaran yang meleset satu. Kondisi i < 10 dan i <= 10 berbeda satu putaran, sehingga elemen terakhir dapat terbuang atau satu putaran ekstra terjadi. Tetapkan batasnya secara sadar, kemudian uji dengan kasus tepi seperti nol dan satu elemen.
  2. Pembaruan yang terlupakan pada while. Tanpa pernyataan yang menggerakkan kondisi menuju berhenti, perulangan berjalan tanpa akhir dan program harus dihentikan paksa. Periksa bahwa badan perulangan selalu mengubah sesuatu yang diuji oleh kondisinya.
  3. Rentang yang diubah di tengah range-based for. Menambahkan elemen ke container selama perulangan berlangsung dapat menggugurkan iterator internalnya, dan perilakunya tidak terdefinisi. Tangguhkan perubahan struktur sampai perulangan selesai, atau gunakan indeks dengan kehati-hatian.

Ketiganya sama-sama sulit terlihat pada sekilas pandang karena sintaksnya sah. Menjalankan program dengan data kecil yang batasnya mudah dihitung manual menjadi pemeriksaan paling murah sebelum kode yang lebih besar ditulis.

Ringkasan#

  • for menggabungkan inisialisasi, kondisi, dan pembaruan dalam satu kepala, dengan pencacah yang berlingkup pada perulangannya.
  • while menguji kondisi sebelum badan, sedangkan do-while menjamin badan berjalan sekali sebelum kondisi diuji.
  • Range-based for mengunjungi setiap elemen array, string, atau container tanpa indeks, sehingga kesalahan batas tidak mungkin terjadi pada bentuknya.

Referensi#