Control Flow: Conditional
Sejauh ini, program yang kita tulis berjalan secara sekuensial artinya komputer mengeksekusi kode instruksi baris per baris secara berurutan dari atas ke bawah tanpa ada instruksi yang dilewati. Namun dalam kehidupan nyata, kita sering kali dihadapkan pada situasi di mana suatu tindakan hanya boleh dilakukan jika suatu syarat tertentu terpenuhi.
Control flow adalah bagaimana kita mendefinisikan menggunakan bahasa untuk menentukan bagaimana urutan proses komputasi dilakukan.
Salah satu konsep paling fundamental dalam pemrograman adalah adanya operasi kondisional. Konsep ini memungkinkan program untuk melakukan operasi atau mengambil keputusan berdasarkan beberapa pilihan atau kondisi.
Pada pertemuan sebelumnya, kita telah mempelajari operator dan expression. Kita mengetahui bahwa operasi relational dan logical akan menghasilkan nilai kebenaran 1 untuk benar dan 0 untuk salah.
Statements and Blocks
Statement adalah berisi instruksi atau perintah yang menandakan suatu deklarasi, tindakan, atau tugas tertentu. Contoh statement yang pernah kita temui yaitu:
int x = 0;
i++;
printf(...);
Itu adalah statement. Selayaknya di kehidupan sehari-hari kita menggunakan tanda baca titik (.) untuk mengakhiri sebuah kalimat.
Di C, kita menggunakan semicolon (;) sebagai penanda end of statement (akhir dari statement).
Tanda kurung kurawal { dan } digunakan untuk mengelompokkan deklarasi dan statement bersama-sama menjadi sebuah statement majemuk, atau block, sehingga secara sintaksis setara dengan satu statement tunggal. Tanda kurung kurawal yang mengelilingi pernyataan-pernyataan dalam sebuah fungsi adalah salah satu contoh yang jelas; Tidak ada titik koma setelah tanda kurung kurawal kanan yang mengakhiri sebuah blok.
if-else
Statement if-else digunakan untuk menyatakan pilihan. Formally, syntaxnya ditulis seperti berikut:
if (expression)
statement1;
else
statement2;
Dimana bagian else bersifat opsional. Expression tersebut dievaluasi; jika bernilai true (yaitu, jika expression menghasilkan nilai bukan 0), statement1 akan dieksekusi. Jika bernilai false (expression menghasilkan nilai 0) dan jika ada bagian else, maka statement2 yang akan dieksekusi sebagai gantinya.
Dikarenakan if menguji nilai numerik dari sebuah expression, beberapa shortcut dalam penulisan diperbolehkan.
if (expression)
daripada
if (expression != 0)
Terkadang penulisan seperti ini terlihat lebih natural dan jelas, dan terkadang juga bisa jadi sulit dipahami.
Dikarenakan bagian else dari sebuah if-else bersifat opsional, maka akan terjadi ambiguitas ketika kita menulis nested if berturut-turut, tetapi hanya menyediakan 1 else. Sebagai contoh:
if (n > 0)
if (a > b)
z = a;
else
z = b;
Untuk menyelesaikan keambiguitasan tersebut, pencipta bahasa C menetapkan satu aturan baku: "Sebuah else akan selalu dipasangkan dengan if terdekat sebelumnya yang belum memiliki pasangan else."
Jadi walaupun kita mengubah indentasinya dalam contoh tersebut, else akan selalu jadi milik child if yang berada pada nested if tersebut. Lalu bagaimana jika kita menginginkan else-nya itu untuk if yang berada di luar bukan yang di dalam nested-nya? Solusinya yaitu dengan menambahkan else agar membentuk pasangan if-else yang padu.
if (n > 0)
if (a > b)
z = a;
else
// statement;
else
z = b;
Namun bagaimana jika kita tidak ingin menambahkan else untuk if yang berada di dalam nested tersebut?
Kita harus menggunakan block {} untuk memaksakan asosiasi if-else nya.
if (n > 0) {
if (a > b)
z = a;
}
else
z = b;
Best practice adalah kita selalu menggunakan block untuk if yang statementnya kompleks, seperti memiliki nested if atau logika statementnya yang panjang, agar kode lebih mudah dibaca dan mempermudah proses debugging. Contoh:
if (expression) {
statement;
if (expression) {
statement;
// ...
}
}
else {
statement;
}
Hanya gunakan if dalam bentuk statement biasa jika statement yang dijalankan di dalam if tersebut sederhana, seperti hanya 1 baris.
else-if
Lalu bagaimana jika kita tidak ingin hanya mengecek satu pilihan saja? Contohnya seperti pada nilai, kita tidak ingin kan kalo misalkan nilai di atas 85 dianggap A namun selain itu dianggap E. else-if adalah cara untuk membuat beberapa pilihan. Tiap expression dievaluasi dalam urutan, jika ekspresi bernilai benar maka statement yang berasosiasi akan dijalankan, dan akan mengabaikan pilihan lain.
Bentuknya:
if (expression)
statement;
else if (expression)
statement;
else if (expression)
statement;
else if (expression)
statement;
else
statement;
else di akhir mengatakan "jika tidak untuk semua kondisi di atas" atau kasus default di mana tidak ada kondisi lain yang terpenuhi, atau suatu pengaman ketika ada kondisi "impossible".
Switch
Pernyataan switch adalah bentuk keputusan multi-arah (multi-way decision) yang menguji apakah sebuah expression cocok dengan salah satu dari sekumpulan nilai konstanta integer (atau karakter), lalu melakukan percabangan sesuai dengan kecocokan tersebut.
Sintaks dari switch ditulis seperti berikut:
switch (expression) {
case const-expr:
statement;
break;
case const-expr:
statement;
break;
default:
statement;
break;
}
Tiap case dilabeli oleh satu atau lebih konstanta integer atau expression konstan (seperti angka atau karakter). Jika nilai dari expression pada switch cocok dengan salah satu nilai pada case, pengeksekusian program akan dimulai persis pada case tersebut. Perlu diingat bahwa semua nilai case dalam satu blok switch harus berbeda satu sama lain.
Bagian default akan dieksekusi jika tidak ada satu pun case yang kondisinya terpenuhi. Keberadaan default ini bersifat opsional; jika default tidak dituliskan dan tidak ada case yang cocok, maka program tidak akan melakukan tindakan apa pun dan langsung keluar dari blok switch. Penulisan urutan case dan default dapat diletakkan di mana saja, tidak harus berurutan.
Perhatikan contoh penggunaan switch berikut yang siap disalin dan diuji:
#include <stdio.h>
int main() {
char grade = 'B';
printf("Nilai Anda: %c\n", grade);
switch (grade) {
case 'A':
printf("Luar biasa! Pertahankan.\n");
break;
case 'B':
case 'C':
printf("Bagus, Anda lulus.\n");
break;
case 'D':
printf("Anda lulus dengan catatan.\n");
break;
case 'E':
case 'F':
printf("Maaf, Anda harus mengulang kelas ini.\n");
break;
default:
printf("Error: Format nilai tidak dikenali.\n");
break;
}
return 0;
}
Dalam contoh di atas, terdapat pernyataan break. Pernyataan break menyebabkan program langsung keluar (immediate exit) dari blok switch. Karena case pada dasarnya hanya berfungsi sebagai "label penanda lokasi", setelah kode untuk satu case selesai dikerjakan, pengeksekusian kode akan terus "jatuh" (fall-through) ke case di bawahnya kecuali Anda secara eksplisit mengambil tindakan untuk memutusnya. break dan return adalah cara paling umum untuk keluar dari sebuah switch.
Sifat fall-through pada switch ini ibarat pedang bermata dua:
- Keuntungan: Memungkinkan kita untuk menempelkan beberapa
casepada satu aksi yang sama. Seperti pada contoh kode di atas,case 'B'dancase 'C'akan menghasilkan output yang sama persis ("Bagus, Anda lulus.") karena tidak adabreakdi antara keduanya. - Kekurangan: Jika Anda lupa menuliskan
breakpada blok yang seharusnya berdiri sendiri, kode daricaseberikutnya akan ikut tereksekusi tanpa sengaja. Sifat fall-through dari satu aksi ke aksi lainnya berpotensi merusak logika program saat dilakukan modifikasi di masa depan.
Kecuali digunakan dengan sengaja untuk menggabungkan label seperti contoh di atas, fall-through harus digunakan seperlunya saja dan sebaiknya diberi komentar penjelas.
Sebagai praktik penulisan kode yang baik (good form), biasakan untuk selalu meletakkan break di akhir case paling bawah (dalam hal ini pada klausa default), meskipun secara logika tidak diperlukan karena blok switch toh akan segera berakhir. Suatu hari nanti, ketika Anda atau rekan Anda menambahkan case baru di bagian paling bawah, kebiasaan pemrograman defensif (defensive programming) ini akan menyelamatkan program Anda dari bug yang sulit dilacak.
Reference
Kernighan, B. W., & Ritchie, D. M. (1978). The C programming language. https://bvbr.bib-bvb.de:443/F?func=service&doc_library=BVB01&local_base=BVB01&doc_number=001351831&sequence=000002&line_number=0001&func_code=DB_RECORDS&service_type=MEDIA