3.2 else if และ if ซ้อน
if else เลือกได้สองทาง แต่โจทย์จริงมักมีมากกว่านั้น เกรดมี 8 ระดับ ค่าไฟคิดหลายอัตรา ตั๋วเครื่องเล่นขึ้นกับทั้งส่วนสูงและอายุ หน้านี้ต่อ if เป็นสายยาวด้วย else if และวาง if ไว้ใน if อีกชั้น แล้วใช้สองอย่างนี้ทำโจทย์แนวที่ออกสอบบ่อย คือตัดเกรด คิดค่าบริการแบบขั้นบันได และหาค่ามากสุดของสามตัว
เลือกหนึ่งจากหลายทาง
บอกสภาพอากาศจากอุณหภูมิ ต่ำกว่า 20 องศาคือ cold ตั้งแต่ 20 แต่ต่ำกว่า 30 คือ warm ตั้งแต่ 30 ขึ้นไปคือ hot
#include <stdio.h>
int main()
{
int temp;
scanf("%d", &temp);
if (temp < 20) {
printf("cold\n");
} else if (temp < 30) {
printf("warm\n");
} else {
printf("hot\n");
}
return 0;
}
25
warm
โปรแกรมตรวจเงื่อนไข จากบนลงล่างทีละข้อ เจอข้อแรกที่จริงเมื่อไร ทำ block นั้น แล้วข้ามที่เหลือทั้งสายไปเลย ถ้าไม่มีข้อไหนจริง ทำ else ตัวสุดท้าย
| temp | temp < 20 | temp < 30 | พิมพ์ |
|---|---|---|---|
| 15 | จริง | ไม่ได้ตรวจ | cold |
| 25 | เท็จ | จริง | warm |
| 34 | เท็จ | เท็จ | hot |
สังเกตว่าเงื่อนไขที่สองเขียนแค่ temp < 30 ไม่ต้องเขียนว่า "ตั้งแต่ 20 ด้วย" เพราะการที่โปรแกรมมาถึงบรรทัดที่ 9 ได้ แปลว่าเงื่อนไขแรกเป็นเท็จไปแล้ว temp จึงไม่ต่ำกว่า 20 แน่นอน นี่คือข้อดีของ else if แต่ละข้อรู้ว่าข้อก่อนหน้าไม่จริง
else if ไม่ใช่คำสั่งใหม่ มันคือ else ที่ตามด้วย if อีกตัว จะต่อกี่ข้อก็ได้ ส่วน else ตัวท้ายจะมีหรือไม่มีก็ได้ ถ้าไม่มีแล้วไม่มีข้อไหนจริง ก็ไม่ทำอะไรเลย
ตัดเกรด
เกณฑ์ที่โรงเรียนส่วนใหญ่ใช้ คือ 80 ขึ้นไปได้ A ลดลงช่วงละ 5 คะแนน จนต่ำกว่า 50 ได้ F
#include <stdio.h>
int main()
{
int score;
scanf("%d", &score);
if (score >= 80) {
printf("A\n");
} else if (score >= 75) {
printf("B+\n");
} else if (score >= 70) {
printf("B\n");
} else if (score >= 65) {
printf("C+\n");
} else if (score >= 60) {
printf("C\n");
} else if (score >= 55) {
printf("D+\n");
} else if (score >= 50) {
printf("D\n");
} else {
printf("F\n");
}
return 0;
}
77
B+
หลักการคือ เรียงจากเกณฑ์สูงลงต่ำ แต่ละข้อเขียนแค่ขอบล่าง เพราะขอบบนถูกข้อก่อนหน้ากันไว้แล้ว 77 ไม่ผ่าน >= 80 แต่ผ่าน >= 75 จึงได้ B+ แล้วหยุด ไม่ไปถึง >= 70 ทั้งที่ 77 ก็มากกว่า 70
เวลาทดสอบโปรแกรมแบบนี้ ให้ป้อนค่าที่ขอบของทุกช่วง คือ 80 กับ 79 ได้ A กับ B+ และ 50 กับ 49 ได้ D กับ F เกรดผิดส่วนใหญ่เกิดตรงขอบ เช่นเผลอเขียน > แทน >= ซึ่งทำให้ 80 พอดีได้ B+
if ซ้อน
block ของ if ใส่คำสั่งอะไรก็ได้ รวมถึง if อีกตัว เรียกว่า if ซ้อน (nested if) ใช้เมื่อต้องตัดสินเป็นขั้นๆ เครื่องเล่นในสวนสนุกให้ขึ้นได้เมื่อสูงตั้งแต่ 120 เซนติเมตร คนที่ขึ้นได้ ถ้าอายุต่ำกว่า 12 ปี ต้องมีผู้ใหญ่นั่งด้วย
#include <stdio.h>
int main()
{
int age, height;
scanf("%d %d", &age, &height);
if (height >= 120) {
if (age >= 12) {
printf("ride alone\n");
} else {
printf("ride with adult\n");
}
} else {
printf("too short\n");
}
return 0;
}
10 135
ride with adult
ขั้นแรกดูส่วนสูง ผ่านแล้วค่อยดูอายุในขั้นที่สอง ถ้าไม่ผ่านขั้นแรก อายุเท่าไรก็ไม่มีความหมาย โปรแกรมไม่ได้ตรวจอายุเลย การเยื้องทำให้เห็นชั้นได้ชัด if ชั้นในเยื้องลึกกว่าชั้นนอก 4 ช่อง ถ้าการเยื้องผิด จะอ่านไม่ออกว่า else ตัวไหนเป็นของ if ตัวไหน
ทดสอบ if ซ้อนต้องให้ครบทุกกิ่ง ในที่นี้มีสามกิ่ง ป้อน 15 130 ได้ ride alone ป้อน 15 110 ได้ too short และตรงขอบ 12 120 ได้ ride alone
ค่าบริการแบบขั้นบันได
ค่าไฟ ค่าน้ำ และภาษีเงินได้ ไม่ได้คิดอัตราเดียวทั้งหมด แต่คิดเป็นขั้น สมมติการไฟฟ้าแห่งหนึ่งคิดแบบนี้
| หน่วยที่ | ราคาต่อหน่วย |
|---|---|
| 1 ถึง 100 | 3 บาท |
| 101 ถึง 200 | 4 บาท |
| 201 ขึ้นไป | 5 บาท |
ใช้ไป 250 หน่วย ไม่ได้ แปลว่าจ่ายหน่วยละ 5 บาททั้ง 250 หน่วย แต่ 100 หน่วยแรกจ่ายหน่วยละ 3 อีก 100 หน่วยถัดมาจ่ายหน่วยละ 4 และ 50 หน่วยที่เหลือจ่ายหน่วยละ 5
#include <stdio.h>
int main()
{
int units;
scanf("%d", &units);
int bill;
if (units <= 100) {
bill = units * 3;
} else if (units <= 200) {
bill = 100 * 3 + (units - 100) * 4;
} else {
bill = 100 * 3 + 100 * 4 + (units - 200) * 5;
}
printf("%d\n", bill);
return 0;
}
250
950
แต่ละกิ่งคิดสองส่วน ส่วนแรกคือขั้นที่ใช้เต็มแล้วทั้งขั้น ซึ่งเป็นค่าคงที่ ส่วนที่สองคือหน่วยที่เกินขอบล่างของขั้นปัจจุบัน คูณด้วยราคาของขั้นนั้น ถ้าคิดหน่วยละ 5 บาททั้งหมดจะได้ 1250 ซึ่งผิด
วิธีตรวจว่าเขียนถูก คือลองค่าสองฝั่งของทุกขอบ แล้วดูว่าค่าไฟเพิ่มขึ้นทีละเท่าราคาของขั้นนั้นพอดี ไม่กระโดด
| หน่วย | ค่าไฟที่โปรแกรมคิดได้ | เพิ่มจากแถวบน |
|---|---|---|
| 100 | 300 | |
| 101 | 304 | 4 ราคาขั้นที่สอง |
| 200 | 700 | |
| 201 | 705 | 5 ราคาขั้นที่สาม |
ถ้าเห็นค่าไฟที่ 101 หน่วยกระโดดไปเป็น 404 แปลว่าคิดทั้งหมดด้วยราคาขั้นที่สอง หรือถ้าน้อยกว่าที่ 100 หน่วย แปลว่าลืมบวกส่วนของขั้นก่อนหน้า
หาค่ามากสุดของสามตัว
หาค่ามากสุดของสองตัวใช้ if else ตรงๆ ได้ แต่พอเป็นสามตัว ถ้าเทียบทุกคู่จะต้องเขียน if ซ้อนหลายชั้น วิธีที่ง่ายกว่าคือ สมมติให้ตัวแรกเป็นค่ามากสุดไปก่อน แล้วเอาตัวที่เหลือมาท้าชิงทีละตัว ตัวไหนมากกว่าแชมป์ปัจจุบัน ก็ขึ้นเป็นแชมป์แทน
#include <stdio.h>
int main()
{
int a, b, c;
scanf("%d %d %d", &a, &b, &c);
int largest = a;
if (b > largest) {
largest = b;
}
if (c > largest) {
largest = c;
}
printf("%d\n", largest);
return 0;
}
72 95 88
95
ข้อนี้ต้องใช้ if สองตัวแยกกัน ไม่ใช่ else if เพราะทุกตัวต้องได้ท้าชิง ถึงตัวที่สองจะชนะไปแล้ว ตัวที่สามก็ยังอาจมากกว่าได้ ค่าเท่ากันก็ไม่มีปัญหา ถ้า b เท่ากับแชมป์ b > largest เป็นเท็จ แชมป์ก็เป็นค่าเดิมซึ่งเท่ากันอยู่แล้ว
หาค่าน้อยสุดใช้วิธีเดียวกัน แค่กลับเครื่องหมายเป็น < วิธีนี้ขยายเป็น 4 หรือ 5 ตัวได้โดยเพิ่ม if ทีละตัว และเป็นแบบเดียวกับที่จะใช้หาค่ามากสุดของข้อมูลเป็นแสนตัวด้วยวนซ้ำในบทที่ 4
ลองทำให้พัง
แบบที่ 1 เรียงเงื่อนไขผิดลำดับ
ตัดเกรดแบบย่อ 5 ระดับ แต่เรียงจากเกณฑ์ต่ำขึ้นสูง
#include <stdio.h>
int main()
{
int score;
scanf("%d", &score);
if (score >= 50) {
printf("D\n");
} else if (score >= 60) {
printf("C\n");
} else if (score >= 70) {
printf("B\n");
} else if (score >= 80) {
printf("A\n");
} else {
printf("F\n");
}
return 0;
}
92
D
92 คะแนนได้ D เพราะ 92 ผ่าน >= 50 ซึ่งเป็นข้อแรก แล้วสายทั้งหมดก็จบตรงนั้น สาม else if ข้างล่างไม่มีวันได้ทำงาน ไม่มีคำเตือน เพราะไม่ผิดไวยากรณ์ ถ้าใช้ >= ต้องเรียงจากมากไปน้อย ถ้าอยากเรียงจากน้อยไปมาก ต้องเปลี่ยนเป็น < ทุกตัว เช่น score < 50 ได้ F ก่อน
แบบที่ 2 ใช้ if แยกกันแทน else if
ในโปรแกรม weather ลบ else หน้า if ตัวที่สองออก
#include <stdio.h>
int main()
{
int temp;
scanf("%d", &temp);
if (temp < 20) {
printf("cold\n");
}
if (temp < 30) {
printf("warm\n");
} else {
printf("hot\n");
}
return 0;
}
15
cold
warm
ตอนนี้มีสองเรื่องแยกกัน เรื่องแรกคือ if เดี่ยวที่บรรทัด 7 เรื่องที่สองคือ if else ที่บรรทัด 10 15 องศาจริงทั้งสองเรื่อง จึงพิมพ์สองบรรทัด ส่วน 25 องศาจะได้ warm บรรทัดเดียวถูกต้องโดยบังเอิญ เวลาที่คำตอบต้องมี อย่างเดียว จากหลายแบบ ให้ใช้ else if แต่ถ้าแต่ละเรื่องเป็นอิสระต่อกันแบบหาค่ามากสุด ให้ใช้ if แยก
แบบที่ 3 else ห้อยผิดตัว
โปรแกรม ride ที่เขียนโดยไม่ใส่ปีกกา และตั้งใจให้ else เป็นของเงื่อนไขส่วนสูง
#include <stdio.h>
int main()
{
int age, height;
scanf("%d %d", &age, &height);
if (height >= 120)
if (age >= 12)
printf("ride alone\n");
else
printf("too short\n");
return 0;
}
ride.c:7:8: warning: suggest explicit braces to avoid ambiguous 'else' [-Wdangling-else]
7 | if (height >= 120)
| ^
10 135
too short
สูง 135 แต่โปรแกรมบอกว่าเตี้ยไป กฎของภาษา C คือ else จับคู่กับ if ที่ใกล้ที่สุดที่ยังไม่มีคู่ ไม่ได้ดูการเยื้อง else บรรทัด 10 จึงเป็นของ age >= 12 ไม่ใช่ของ height >= 120 เด็กสูงพออายุ 10 ปีเลยได้ too short และถ้าป้อน 10 110 โปรแกรมจะไม่พิมพ์อะไรเลย เพราะไม่มี else ของส่วนสูง แก้ด้วยการใส่ปีกกาแบบโปรแกรม ride ต้นฉบับ ปีกกาบอกชัดว่าอะไรอยู่ชั้นไหน
สรุป
if ... else if ... elseตรวจจากบนลงล่าง ทำแค่ block แรกที่จริง แล้วข้ามที่เหลือ- ตัดเกรดหรือแบ่งช่วง ให้เรียงเกณฑ์ตามลำดับ แต่ละข้อเขียนแค่ขอบเดียว อีกขอบถูกข้อก่อนหน้ากันไว้แล้ว
- if ซ้อนใช้ตัดสินเป็นขั้น ใส่ปีกกาทุกชั้น เพราะ
elseจับคู่กับifที่ใกล้ที่สุด - ค่าบริการขั้นบันไดคิดแต่ละขั้นด้วยราคาของขั้นนั้น ตรวจด้วยค่าสองฝั่งของทุกขอบ
- ค่ามากสุดของหลายตัว ตั้งตัวแรกเป็นแชมป์ แล้วใช้
ifแยกให้ตัวที่เหลือท้าชิงทีละตัว - ทดสอบให้ครบทุกกิ่ง และทุกค่าตรงขอบของแต่ละช่วง