User Tools

Site Tools


comp:cpp_selection

บทที่ 3 การเลือกทำ Selection

ตัวอย่างโปรแกรมที่นำเสนอในบทที่ผ่านมาแสดงถึงการทำงานของโปรแกรมที่มีการประมวลผลแบบตามลำดับ (sequential execution) โดยที่แต่ละคำสั่งจะถูกประมวลผลหนึ่งครั้ง ตามลำดับแน่นอนที่ผู้เขียนโปรแกรมได้เขียนไว้ อย่างไรก็ดี แนวทางแก้ไขปัญหาในบางกรณีอาจต้องมีการตัดสินใจเข้ามาเกี่ยวข้องในการเลือกที่จะทำ หรือไม่ทำในบางสิ่ง ดังนั้น ในบทนี้จะขอนำเสนอคำสั่งในการเลือกกระทำ ซึ่งจะช่วยเพิ่มความยืดหยุ่นการพัฒนาโปรแกรมให้เป็นไปตามวัตถุประสงค์ของงานยิ่งขึ้น

3.1 คำสั่ง if

คำสั่ง if เป็นคำสั่งที่มีการประมวลผลแบบกระทำตามเงื่อนไข โดยมีรูปแบบคำสั่ง ดังนี้

	if  (condition)  statement ; 

โดยที่ condition หมายถึง นิพจน์จำนวนเต็ม (integral expression) และ statement หมายถึง คำสั่งที่ต้องการให้เกิดการประมวลผลตามผลของเงื่อนไขที่กำหนด โดยที่ คำสั่งดังกล่าวจะถูกกระทำเมื่อค่าของนิพจน์จำนวนเต็มมีค่าไม่เป็นศูนย์ (ค่าเป็นจริง) ให้สังเกตว่า เงื่อนไขที่ระบุในคำสั่งต้องเขียนภายในเครื่องหมายวงเล็บเสมอ ผังงานการทำงานของคำสั่ง if แสดงดังรูป 3-1

รูป 3-1 ผังงานคำสั่ง if

ตัวอย่าง 3.1 การทดสอบการหารลงตัว

int main ( )
{ 	int n, d;
	cout << "Enter two positive integers: ";
	cin >> n >> d;
	if (n%d) cout << n << " is not divisible by " << d << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า n = 66 และ d = 7

Enter two positive integers: 66 7
66 is not divisible by 7

จากการคำนวณ ค่า 66%7 ได้ผลลัพธ์เป็น 3 ซึ่งเป็นค่าจำนวนเต็มที่ไม่เป็นศูนย์ ซึ่งนิพจน์ดังกล่าวสำหรับภาษา C++ จะถือว่าเป็นเงื่อนไขจริง ผลที่ตามมา ข้อความ “66 is not divisible by 7” ถูกแสดงผลทางจอภาพ

ทดสอบโปรแกรมอีกครั้ง โดยป้อนค่า n = 56 และ d = 7

Enter two positive integers: 56 7

ค่าที่ได้จาก 56%7 มีค่าเป็น 0 ซึ่งจะถูกประเมินว่ามีค่าเป็นเท็จ ในภาษา C++ ดังนั้น จึงไม่มีการแสดงผลใดๆ ทางจอภาพ

โปรแกรม 3.1 จัดว่าเป็นโปรแกรมที่ขาดความสมบูรณ์ในตัวเอง ในเรื่องของการพัฒนาโปรแกรมให้เป็นโปรแกรมที่เป็นมิตรกับผู้ใช้ (user-friendly program) เนื่องจาก โปรแกรมไม่มีการแสดงข้อมูลยืนยันการหารลงตัวของค่า n ด้วยค่า d ข้อบกพร่องนี้สามารถแก้ไขได้ด้วยคำสั่ง if..else

ก่อนที่จะไปยังคำสั่งถัดไป ขอย้ำอีกครั้งว่า เมื่อใดก็ตามที่นิพจน์จำนวนเต็มถูกใช้เป็นเงื่อนไขในการตรวจสอบ ค่า 0 จะหมายถึง เงื่อนไขเท็จ และค่าอื่นใดที่ไม่เป็น 0 จะหมายถึงเงื่อนไขจริง

3.2 คำสั่ง if..else

คำสั่ง if..else เป็นคำสั่งที่จะเลือกประมวลผลคำสั่งจาก 2 ทางเลือก ขึ้นกับค่าของเงื่อนไขว่าเป็นจริงหรือไม่ โดยมีรูปแบบคำสั่ง ดังนี้

	if  (condition)  statement1 ;
		else  statement2 ;

โดยที่ condition หมายถึง นิพจน์จำนวนเต็ม และ statement1 และ statement 2 เป็นคำสั่งที่ต้องการให้เกิดการประมวลผลตามผลของเงื่อนไขที่กำหนด ถ้าค่าของเงื่อนไขไม่เป็นศูนย์ (จริง) statement1 จะถูกประมวลผล มิฉะนั้น statement2 จะถูกประมวลผล ให้สังเกตว่า คำสั่ง if..else ถือว่าเป็นคำสั่ง 1 คำสั่ง แม้ว่า จะต้องใช้เครื่องหมาย ; ถึง 2 ตัว คือ วางไว้หลังstatement1 และ statement2 ผังงานการทำงานของคำสั่ง if..else แสดงดังรูป 3-2

รูป 3-2 ผังงานคำสั่ง if..else

ตัวอย่าง 3.2 การทดสอบการหารลงตัวอีกครั้ง

int main ( )
{	int n, d;
	cout << "Enter two positive integers: ";
	cin >> n >> d;
	if (n%d) cout << n << " is not divisable by " << d << endl;
	else cout << n << " is divisible by " << d << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า n = 56 และ d = 7

Enter two positive integers: 56 7
56 is divisible by 7

เนื่องจาก ค่า 56%7 ได้ผลลัพธ์เป็นศูนย์ ซึ่งจะถูกตีความว่าเป็นเงื่อนไขเท็จ ผลที่ตามมา คำสั่งหลัง else จะถูกประมวลผล ข้อความ “56 is divisible by 7” ถูกแสดงทางจอภาพ

ตัวอย่าง 3.3 ค่าน้อยสุดระหว่างจำนวนเต็มสองจำนวน

int main ( )
{ 	int m, n;
	cout << "Enter two integers: ";
	cin >> m >> n;
	if (m < n) cout << m << " is the minimum." << endl;
	else cout << n << " is the minimum." << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า m = 77 และ n = 55

Enter two integers: 77 55
55 is the minimum.

เนื่องจาก ค่าของตัวแปร m และ n มีค่าเป็น 77 และ 55 ตามลำดับ ทำให้นิพจน์เงื่อนไข m < n มีค่าเป็นเท็จ ดังนั้น คำสั่งหลัง else จึงถูกประมวลผล ให้แสดงค่าของตัวแปร n เป็นค่าที่น้อยที่สุด

ตัวอย่าง 3.4 ค่าน้อยที่สุดของจำนวนเต็ม 3 จำนวน

int main ( )
{ 	int n1, n2, n3;
	cout << "Enter three integers: ";
	cin >> n1 >> n2 >> n3;
	int min = n1;    			// now min = n1
	if (n2 < min) min = n2;  	// now min <= n1 and <= n2
	if (n3 < min) min = n3;  	// now min <= n1, <= n2 and <= n3
	cout << "Their minimum is " << min << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า n1 = 77 , n2 = 33 และ n3 = 55

 Enter three integers: 77 33 55
Their minimum is 33

จากตัวอย่าง ตัวแปร min ถูกกำหนดให้มีค่าเริ่มต้นเท่ากับตัวแปร n1 ดังนั้น ค่าของ min จึงเป็นค่าที่น้อยที่สุดในเซต {n1} หลังจากคำสั่ง if คำสั่งแรกถูกประมวลผล min จะเก็บค่าที่น้อยกว่าระหว่างค่าของตัวแปร n1 กับ n2 ทำให้ min เก็บค่าที่น้อยสุดในเซต {n1, n2} คำสั่ง if สุดท้ายจะเปลี่ยนค่าในตัวแปร min เป็นค่าของตัวแปร n3 ก็ต่อเมื่อ ค่าของ n3 น้อยกว่าค่าปัจจุบันที่อยู่ใน min ซึ่งก็คือค่าที่น้อยที่สุดในเซต {n1, n2} ดังนั้น ไม่ว่าค่าของ min จะมีการเปลี่ยนแปลงหรือไม่ ค่าของ min ก็จะเป็นค่าที่น้อยที่สุดในเซต {n1, n2, n3}

ตัวอย่าง 3.5 การใช้เงื่อนไขเชิงซ้อนเพื่อหาค่าน้อยที่สุดของจำนวนเต็ม 3 จำนวน

int main ( )
{ 	int n1, n2, n3;
	cout << "Enter three integers: ";
	cin >> n1 >> n2 >> n3;
	if (n1 <= n2 && n1 <= n3) 
		cout << "Their minimum is " << n1 << endl;
	if (n2 <= n1 && n2 <= n3) 
		cout << "Their minimum is " << n2 << endl;
	if (n3 <= n1 && n3 <= n2) 
		cout << "Their minimum is " << n3 << endl;
}

หมายเหตุ ตัวอย่างนี้ไม่ได้เป็นการปรับปรุงโปรแกรมที่แสดงในตัวอย่าง 3.4 แต่มีวัตถุประสงค์เพียงเพื่อจะนำเสนอการเขียนคำสั่งโดยใช้เงื่อนไขเชิงซ้อนเท่านั้น

ทดสอบโปรแกรม โดยป้อนค่า n1 = 77 , n2 = 33 และ n3 = 55

Enter three integers: 77 33 55
Their minimum is 33

เงื่อนไขเชิงซ้อนทั้งสามในโปรแกรม มีเพียงเงื่อนไขที่สอง (n2 ⇐ n1 && n2 ⇐ n3) ที่ให้ผลลัพธ์เป็นจริง เนื่องจาก นิพจน์ n2 ⇐ n1 (33 ⇐ 77) และ นิพจน์ n2 ⇐ n3 (33 ⇐ 55) มีค่าเป็นจริงทั้งสองนิพจน์ ดังนั้น ค่าของ n2 จึงถูกพิจารณาว่าเป็นค่าที่น้อยที่สุด

ตัวอย่าง 3.6 การรับข้อมูลแบบเป็นมิตรกับผู้ใช้ (user-friendly input)

int main ( )
{ 	char ans;
	cout << "Are you enrolled (y/n): ";
	cin >> ans;
	if (ans =='Y' || ans == 'y') cout << "You are enrolled.\n";
	else cout << "You are not enrolled.\n";
}

ทดสอบโปรแกรม โดยป้อนค่า ans เป็น y

 Are you enrolled (y/n): y
You are enrolled.

ทดสอบโปรแกรม โดยป้อนค่า ans เป็น n

Are you enrolled (y/n): n
You are not enrolled.

โปรแกรมตัวอย่างจะแสดงข้อความตอบสนองการป้อนค่าของผู้ใช้ ถ้าผู้ใช้จะป้อนค่าเป็น ‘Y’ หรือ ‘y’ โปรแกรมจะแสดงข้อความ “You are enrolled.” ทางจอภาพ แต่ถ้าตัวอักขระดังกล่าวไม่ใช่อักขระ ‘Y’ หรือ ‘y’ (มีความหมายเดียวกับการป้อนอักขระ n) โปรแกรมจะแสดงข้อความ “You are not enrolled.” ทางจอภาพ การเขียนโปรแกรมเพื่อให้ผู้ใช้ทำการป้อนค่าจนกว่าจะได้ตัวอักขระที่ต้องการ สามารถทำได้เมื่อนักเรียนรู้คำสั่งในการกระทำซ้ำที่จะอธิบายในบทต่อไป

3.3 บล็อกคำสั่ง

บล็อกคำสั่ง (statement block) ในภาษา C++ หมายถึง กลุ่มของลำดับคำสั่งที่เขียนภายในเครื่องหมาย { } เช่น

{ int temp = x ;  x = y ; y = temp }

โดยที่ ในภาษา C++ จะพิจารณาบล็อกคำสั่งเหมือนกับเป็นคำสั่งเพียงคำสั่งเดียว เพราะฉะนั้น เราสามารถใช้บล็อกคำสั่งในทุกที่ของรูปแบบคำสั่งที่อนุญาตให้เขียนได้เพียง 1 คำสั่งเท่านั้น

ตัวอย่าง 3.7 การใช้บล็อกคำสั่งภายในคำสั่ง if ในการจัดลำดับเลขจำนวน 2 จำนวน

int main ( )
{	int x, y;
	cout << "Enter two integers: ";
	cin >> x >> y;
	if (x > y) { int temp = x; x = y; y = temp;}
	cout << x << " <= " << y << endl;
}

ข้อสังเกต หลังบล็อกคำสั่งจะไม่ปิดท้ายด้วยเครื่องหมาย ;

ทดสอบโปรแกรม โดยป้อนค่า x = 66 และ y = 44

Enter two integers: 66 44
44 <= 66

ในการสลับค่าระหว่างค่าในตัวแปร x และ y ต้องอาศัยการทำงานของคำสั่ง 3 คำสั่ง กล่าวคือ สำรองตัวแปร ชื่อ temp เพื่อใช้เก็บข้อมูลชั่วคราวของตัวแปร x เพราะว่า เมื่อเรานำค่าที่อยู่ในตัวแปร y มาใส่ใน x จะทำให้ค่าในตัวแปร x ถูกแทนที่ด้วยค่าของ y อย่างไรก็ดี ค่าของ x ที่เก็บอยู่ในตัวแปร temp สามารถนำมากำหนดให้กับตัวแปร y ทำให้เกิดการสลับค่าระหว่างตัวแปร x และ y คำสั่งทั้งสามจะถูกประมวลผลก็ต่อเมื่อค่าในตัวแปร x มีค่ามากกว่า y เพื่อให้ตัวแปร x เก็บค่าที่น้อยกว่าตัวแปร y เสมอ เนื่องจาก รูปแบบของคำสั่ง if จะทำการประมวลผลคำสั่งเพียงคำสั่งเดียวเมื่อพบว่าเป็นไปตามเงื่อนไขที่กำหนด ดังนั้น เราจึงต้องเขียนคำสั่งทั้งสามไว้ภายในบล็อกคำสั่ง เพื่อให้ถูกต้องตามรูปแบบของคำสั่ง if และ ได้ผลการทำงานตามวัตถุประสงค์ที่ต้องการ

ตัวแปร temp เป็นตัวแปรที่ประกาศภายในบล็อกซึ่งจัดว่าเป็นตัวแปรท้องถิ่น (local variable) โดยจะปรากฏและสามารถใช้งานได้ภายในบล็อกเท่านั้น จากตัวอย่าง ถ้าเงื่อนไข x > y มีค่าเป็นเท็จ บล็อกคำสั่งจะไม่ถูกประมวลผล และ ตัวแปร temp ก็จะไม่ถูกสร้างขึ้น การประกาศวัตถุเป็นแบบท้องถิ่นภายในบล็อกสามารถช่วยประหยัดทรัพยากรหน่วยความจำที่ใช้ในการประมวลผล โดยวัตถุจะถูกสร้างขึ้นเพื่อใช้งานก็ต่อเมื่อมีความจำเป็นต้องใช้งานเท่านั้น

3.4 วงจรลัด

ภาษา C++ รองรับการทำงานของวงจรลัด (short circuiting) โดยที่เงื่อนไขเชิงซ้อนที่เชื่อมด้วยตัวดำเนินการ && หรือ || จะไม่ทำการตรวจสอบเงื่อนไขที่สอง ถ้าสามารถสรุปผลของนิพจน์ได้จากเงื่อนไขแรก จากตารางความจริง จะเห็นว่าเงื่อนไข p && q จะถูกประเมินผลเป็นเท็จถ้าพบว่า p มีค่าเป็นเท็จ โดยไม่จำเป็นต้องพิจารณาค่าของ q เช่นเดียวกับ ถ้า p มีค่าเป็นจริง เราก็ไม่จำเป็นต้องพิจารณาค่าของ q เพื่อที่จะทราบว่าผลลัพธ์ของเงื่อนไข p || q มีค่าเป็นจริง ในทั้งสองกรณี ผลลัพธ์ของเงื่อนไขสามารถทราบได้ทันทีที่เราพิจารณาค่าของนิพจน์แรกในเงื่อนไขเชิงซ้อน

ตัวอย่าง 3.8 การทำงานของวงจรลัดในการทดสอบการหารลงตัว

int main ( )
{ 	int n, d;
	cout << "Enter two positive integers: ";
	cin >> n >> d;
	if (d != 0 && n%d == 0) cout << d << " divides " << n << endl;
	else cout << d << " does not divide " << n << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า n = 300 และ d = 6

Enter two positive integers: 300 6
6 divides 300

เนื่องจาก ค่าของ d มีค่าเป็น 6 ซึ่งไม่เท่ากับ 0 และ ผลการคำนวณ n%d มีค่าเป็น 0 ทำให้ผลลัพธ์ของเงื่อนไขเชิงซ้อนมีค่าเป็นจริง คำสั่งหลัง if จึงถูกประมวลผล

ทดสอบโปรแกรม โดยป้อนค่า n = 300 และ d = 7

Enter two positive integers: 300 7
7 does not divide 300

เนื่องจาก ค่าของ d มีค่าเป็น 7 ซึ่งไม่เท่ากับ 0 แต่ผลการคำนวณ n%d มีค่าเป็น 6 ซึ่งไม่เท่ากับ 0 ทำให้ผลลัพธ์ของเงื่อนไขเชิงซ้อนมีค่าเป็นเท็จ คำสั่งหลัง else จึงถูกประมวลผล

ทดสอบโปรแกรม โดยป้อนค่า n = 300 และ d = 0

Enter two positive integers: 300 0
0 does not divide 300

เนื่องจาก ค่าของ d มีค่าเท่ากับ 0 เงื่อนไขเชิงซ้อนจะถูกพิจารณาให้มีค่าเป็นเท็จทันที โดยไม่ทำการตรวจสอบนิพจน์ที่สอง (n%d == 0) ทำให้คำสั่งหลัง else ถูกประมวลผล จากผลการทดสอบจะเห็นว่า วงจรลัดได้ช่วยป้องกันไม่ให้เกิดข้อผิดพลาดในการประมวลผลโปรแกรม เพราะว่า ถ้าค่าของ d มีค่าเป็น 0 เราจะไม่สามารถคำนวณค่าของนิพจน์ n%d ได้

3.5 คำสั่งเลือกทำซ้อน

เช่นเดียวกับคำสั่งเชิงซ้อน คำสั่งเลือกทำสามารถใช้แทนที่คำสั่งเดี่ยวที่ปรากฏในรูปแบบของทุกคำสั่งในภาษา C++ ดังนั้น คำสั่งเลือกทำจึงสามารถเขียนซ้อนอยู่ภายในคำสั่งเลือกทำอื่น การเขียนคำสั่งในลักษณะนี้ เรียกว่า การเขียนคำสั่งซ้อน (nesting statement)

ตัวอย่าง 3.9 คำสั่งการเลือกทำซ้อนในการทดสอบการหารลงตัว

int main ( )
{	int n, d;
	cout << "Enter two positive integers: ";
	cin >> n >> d;
	if (d != 0)
		if (n%d == 0) cout << d << " divides " << n << endl;
		else cout << d << " does not divide " << n << endl;
	else cout << d << " does not divide " << n << endl;
}

จากโปรแกรม คำสั่งเลือกทำ if..else ที่สองปรากฏซ้อนอยู่เป็นคำสั่งเลือกทำเมื่อเงื่อนไขเป็นจริง ภายในคำสั่ง if..else แรก เพราะฉะนั้น คำสั่ง if..else ที่สองจะถูกกระทำ เมื่อ d มีค่าไม่เป็น 0 ให้สังเกตว่า ในโปรแกรมมีการเขียนคำสั่งแสดงข้อความ “ does not divide ” ไว้สองแห่ง โดยที่แรก ปรากฏภายในส่วนคำสั่ง if ของคำสั่ง if..else แรก ซึ่งจะถูกประมวลผลเมื่อ d มีค่าไม่เป็น 0 และ n%d มีค่าเป็น 0 ในขณะที่ ตำแหน่งที่สองจะถูกประมวลผลเมื่อ d มีค่าเป็น 0

ทดสอบโปรแกรม โดยป้อนค่า n = 300 และ d = 6

 
Enter two positive integers: 300 6
6 divides 300

เนื่องจาก ค่าของ d มีค่าเป็น 6 ซึ่งไม่เท่ากับ 0 คำสั่งหลัง if ของคำสั่ง if..else แรกจะถูกประมวลผล โปรแกรมจะทำการพิจารณาผลการคำนวณ n%d ซึ่งมีค่าเป็น 0 ทำให้คำสั่งหลัง if ของคำสั่ง if..else ที่สองถูกประมวลผล

ทดสอบโปรแกรม โดยป้อนค่า n = 300 และ d = 7

 
Enter two positive integers: 300 7
7 does not divide 300

เนื่องจาก ค่าของ d มีค่าเป็น 7 ซึ่งไม่เท่ากับ 0 คำสั่งหลัง if ของคำสั่ง if..else แรกจะถูกประมวลผล แต่เมื่อพิจารณาผลการคำนวณ n%d มีค่าเป็น 6 ซึ่งไม่เท่ากับ 0 ทำให้คำสั่งหลัง else ของคำสั่ง if..else ที่สองถูกประมวลผล

ทดสอบโปรแกรม โดยป้อนค่า n = 300 และ d = 0

Enter two positive integers: 300 0
0 does not divide 300

เนื่องจาก ค่าของ d มีค่าเท่ากับ 0 ทำให้คำสั่งหลัง else ของคำสั่ง if..else แรกถูกประมวลผล

เมื่อคำสั่ง if..else ถูกเขียนในลักษณะที่มีการซ้อนกัน โปรแกรมแปลโปรแกรมภาษา C++ จะแปลคำสั่งเลือกทำซ้อน โดยพิจารณากำหนดคู่ของคำสั่ง if..else ด้วยการจับคู่ else แต่ละตัวเข้ากับ if ตัวก่อนหน้าล่าสุดที่พบในคำสั่งนั้น

ลักษณะการเขียนคำสั่ง if..else แบบซ้อนสองชั้นโดยทั่วไปสามารถเขียนได้ ดังต่อไปนี้

	if  (condition1)
		if  (condition2)  statement1 ;
 
        else  statement2 ;
 
	else
 
		if  (condition3)  statement3 ;
 
        else  statement4 ;

รูปแบบข้างต้นมีการเขียนคำสั่ง if..else ซ้อนอยู่ภายใน ทั้งส่วน if และ ส่วน else ของคำสั่ง if..else แรก การทำงานจะเริ่มจากการตรวจสอบ condition1 ถ้า condition1 เป็นจริง จะทำการประมวลผลคำสั่ง if..else ในส่วน if โดยตรวจสอบ condition2 และ ถ้าพบว่า condition2 เป็นจริง ก็จะทำการประมวลผล statement1 มิฉะนั้น จะทำการประมวลผล statement2 แต่ถ้า condition1 เป็นเท็จ จะทำการประมวลผลคำสั่ง if..else ในส่วน else แทน โดยตรวจสอบ condition3 และ ถ้าพบว่า condition3 เป็นจริง จะทำการประมวลผล statement3 มิฉะนั้น จะทำการประมวลผล statement4 ผังงานการทำงานของคำสั่งเลือกทำซ้อน if..else แสดงดังรูป 3-3

รูป 3-3 ผังงานคำสั่งเลือกทำซ้อน if..else

	if  (condition1)
		if  (condition2)  statement1 ;
        else  statement2 ;
	else  statement3 ;

รูปแบบข้างต้นมีการเขียนคำสั่ง if..else ซ้อนอยู่ภายในส่วน if ของคำสั่ง if..else แรก การทำงานจะเริ่มจากการตรวจสอบ condition1 ถ้า condition1 เป็นจริง จะทำการประมวลผลคำสั่ง if..else ในส่วน if โดยตรวจสอบ condition2 และ ถ้าพบว่า condition2 เป็นจริง ก็จะทำการประมวลผล statement1 มิฉะนั้น จะทำการประมวลผล statement2 แต่ถ้า condition1 เป็นเท็จ จะทำการประมวลผล statement3

	if  (condition1)  statement1 ;
	else
		if  (condition2)  statement2 ;
		else  statement3 ;

รูปแบบข้างต้นมีการเขียนคำสั่ง if..else ซ้อนอยู่ภายในส่วน else ของคำสั่ง if..else แรก การทำงานจะเริ่มจากการตรวจสอบ condition1 ถ้า condition1 เป็นจริง จะทำการประมวลผล statement1 แต่ถ้า condition1 เป็นเท็จ จะทำการประมวลผลคำสั่ง if..else ในส่วน else โดยทำการตรวจสอบ condition2 และ ถ้าพบว่า condition2 เป็นจริง จะทำการประมวลผล statement2 มิฉะนั้น จะทำการประมวลผล statement3

	if  (condition1)
		if  (condition2)  statement1 ;
		else  statement2 ;

รูปแบบข้างต้นมีการเขียนคำสั่ง if..else ซ้อนอยู่ภายในคำสั่ง if การทำงานจะเริ่มจากการตรวจสอบ condition1 ถ้า condition1 เป็นจริง จะทำการประมวลผลคำสั่ง if..else โดยทำการตรวจสอบ condition2 และ ถ้าพบว่า condition2 เป็นจริง จะทำการประมวลผล statement1 มิฉะนั้น จะทำการประมวลผล statement2 ถ้า condition1 เป็นเท็จ จะไม่มีการประมวลผลคำสั่ง

อย่างไรก็ดี ถ้าพิจารณารูปแบบคำสั่งดังกล่าวอาจทำให้เกิดความสับสนได้ว่า เป็นการเขียนคำสั่ง if ซ้อนอยู่ภายในส่วน if ของคำสั่ง if..else แต่จากหลักเกณฑ์การประมวลคำสั่งซ้อนของโปรแกรมตัวแปลภาษา C++ ที่ได้อธิบายไปแล้วจะพบว่า เป็นคำสั่งในรูปแบบการเขียนคำสั่ง if..else ซ้อนอยู่ภายในคำสั่ง if คำถามที่เกิดขึ้น คือ ถ้าต้องการเขียนคำสั่ง if ซ้อนอยู่ภายในส่วน if ของคำสั่ง if..else จะต้องเขียนอย่างไร เราสามารถแก้ปัญหาดังกล่าวได้โดยอาศัยการเขียนคำสั่ง if ไว้ภายในบล็อกคำสั่ง ดังนี้

	if  (condition1)
		{ if  (condition2)  statement1 ; }
	else  statement2 ;

จะเห็นได้ชัดเจนว่า รูปแบบข้างต้นมีการเขียนคำสั่ง if ซ้อนอยู่ภายในส่วน if ของคำสั่ง if..else การทำงานจะเริ่มจากการตรวจสอบ condition1 ถ้า condition1 เป็นจริง จะทำการประมวลผลคำสั่ง if โดยทำการตรวจสอบ condition2 และถ้าพบว่า condition2 เป็นจริง จะทำการประมวลผล statement1 มิฉะนั้น จะไม่มีการประมวลผลคำสั่งใดเกิดขึ้น แต่ถ้า condition1 เป็นเท็จ จะทำการประมวลผล statement2

ตัวอย่าง 3.10 การใช้คำสั่งเลือกทำซ้อนในการหาค่าน้อยที่สุดของจำนวนเต็ม 3 จำนวน

int main ( )
{	int n1, n2, n3;
	cout << "Enter three integers: ";
	cin >> n1 >> n2 >> n3;
	if (n1 < n2)
		if (n1 < n3) cout << "Their minimum is " << n1 << endl;
		else cout << "Their minimum is " << n3 << endl;
	else  // n1 >= n2
		if (n2 < n3) cout << "Their minimum is " << n2 << endl;
		else cout << "Their minimum is " << n3 << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า n1 = 77, n2 = 33 และ n3 = 55

Enter three integers: 77 33 55
Their minimum is 33

เนื่องจาก ค่าของ n1 และ n2 มีค่าเป็น 77 และ 33 ทำให้เงื่อนไข n1 < n2 มีค่าเป็นเท็จ คำสั่ง if..else ในส่วน else ของคำสั่ง if..else แรกจะถูกประมวลผล โดยพิจารณาเงื่อนไข n2 < n3 ซึ่งได้ผลลัพธ์เป็นจริง เนื่องจาก n2 มีค่าเป็น 33 ในขณะที่ n3 มีค่าเป็น 55 โปรแกรมจึงทำการประมวลผลคำสั่งหลัง if และ แสดงค่าของ n2 เป็นค่าต่ำสุด

โปรแกรมนี้เป็นโปรแกรมที่มีประสิทธิภาพในการทำงานสูงกว่าโปรแกรมที่แสดงในตัวอย่าง 3.5 เนื่องจาก โปรแกรมนี้จะทำการประเมินนิพจน์เพียง 2 เงื่อนไขในแต่ละครั้งของการประมวลผล แทนที่จะประเมินผลเงื่อนไขเชิงซ้อน 3 คำสั่ง

ตัวอย่าง 3.11 เกมเดาตัวเลข

int main ( )
{ 	cout << "Pick a number from 1 to 8." << endl;
	char answer;
	cout << "Is it less than 5? (y|n): "; cin >> answer;
	if (answer == 'y')  // 1 <= n <= 4
	{  	cout << "Is it less than 3? (y|n): "; cin >> answer;
		if (answer == 'y')  // 1 <= n <= 2
		{  	cout << "Is it less than 2? (y|n): "; cin >> answer;
			if (answer == 'y') cout << "Your number is 1." << endl;
			else cout << "Your number is 2." << endl;
		}
		else  // 3 <= n <= 4
		{  	cout << "Is it less than 4? (y|n): "; cin >> answer;
			if (answer == 'y') cout << "Your number is 3." << endl;
			else cout << "Your number is 4." << endl;
		}
	}
	else  // 5 <= n <= 8
	{  	cout << "Is it less than 7? (y|n): "; cin >> answer;
		if (answer == 'y')  // 5 <= n <= 6
		{ 	cout << "Is it less than 6? (y|n): "; cin >> answer;
			if (answer == 'y') cout << "Your number is 5." << endl;
			else cout << "Your number is 6." << endl;
		}
		else  // 7 <= n <= 8
		{ 	cout << "Is it less than 8? (y|n): "; cin >> answer;
			if (answer == 'y') cout << "Your number is 7." << endl;
			else cout << "Your number is 8." << endl;
		}
	}
}

ทดสอบโปรแกรม เมื่อตัวเลขที่คิดไว้เป็น 6

 
Pick a number from 1 to 8.
Is it less than 5? (y|n): n
Is it less than 7? (y|n): y
Is it less than 6? (y|n): n
Your number is 6.

โปรแกรมทำการค้นหาตัวเลขระหว่างเลข 1 ถึง 8 โดยใช้วิธีการแบ่งปัญหาออกเป็นส่วนย่อย อาศัยการถามคำถามสามครั้ง อัลกอริทึมที่ใช้ในโปรแกรมนี้ เรียกว่า การสืบค้นแบบทวิภาค (binary search)

3.6 โครงสร้าง else if

คำสั่ง if..else ซ้อนเป็นคำสั่งที่มีการใช้งานเสมอในการทดสอบทางเลือกของปัญหา ในกรณีที่โครงสร้างเลือกทำซ้อนมีการเลือกทำในส่วนคำสั่งหลัง else อย่างต่อเนื่อง เรามักจะเขียนคำสั่งเชิงซ้อนดังกล่าวในรูปแบบของโครงสร้าง else if เพื่อเน้นให้เห็นตรรกะในการตรวจสอบเงื่อนไขที่เป็นลำดับ ตามรูปแบบคำสั่ง

	if ( condition 1)  statement 1 ;
	else if (condition 2) statement 2;
	. . .
	else if (condition n) statement n;
	else statement n+1;

โดยที่ condition i หมายถึง นิพจน์จำนวนเต็ม (integral expression) และ statement i เป็นคำสั่งที่จะประมวลผลตามค่าของเงื่อนไขที่ i ใดๆ ถ้าค่าของเงื่อนไขที่ i ไม่เป็นศูนย์ (จริง) คำสั่ง i จะถูกประมวลผล ส่วน statement n+1 เป็นคำสั่งที่ประมวลผล เมื่อค่านิพจน์ของทุกเงื่อนไขมีค่าเป็นศูนย์ (เท็จ) ผังงานการทำงานของคำสั่งเลือกทำซ้อน else if แสดงดังรูป 3-4

รูป 3-4 ผังงานคำสั่งเลือกทำซ้อน else if

ตัวอย่าง 3.12 การใช้โครงสร้าง else if ในการตรวจสอบทางเลือก

int main ( )
{ 	char language;
	cout << "Engl.,Fren.,Ger.,Ital., or Rus.? (e|f|g|i|r): ";
	cin >> language;
	if (language == 'e') 
		cout << "Welcome to Project Euclid." << endl;
	else if (language == 'f') 
		cout << "Bon jour, Project Euclid." << endl;
	else if (language == 'g') 
		cout << "Guten tag, Project Euclid." << endl;
	else if (language == 'i') 
		cout << "Bon giorno, Project Euclid." << endl;
	else if (language == 'r') 
		cout << "Dobre utre, Project Euclid." << endl;
	else cout << "Sorry; we don't speak your language." << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า language = i

Engl.,Fren.,Ger.,Ital., or Rus.? (e|f|g|i|r): i
Bon giorno, Project Euclid.

โปรแกรมใช้คำสั่ง if..else ซ้อนในส่วนของ else จำนวน 5 คำสั่ง เพื่อทดสอบเงื่อนไข 5 เงื่อนไขว่า เป็นไปตามเงื่อนไขใดเงื่อนไขหนึ่งหรือไม่ จากการประมวลผล ค่าของ language มีค่าเป็น i ซึ่งตรงกับการตรวจสอบเงื่อนไขในครั้งที่ 4 ทำให้คำสั่งหลัง if ของเงื่อนไขที่ 4 ถูกประมวลผล

ตัวอย่าง 3.13 การใช้โครงสร้าง else if ในการกำหนดเกรดตามช่วงคะแนน

int main ( )
{ 	int score;
	cout << "Enter your test score: "; cin >> score;
	if (score > 100) 
		cout << "Error: that score is out of range." << endl;
	else if (score >= 90) cout << "Your grade is an A." << endl;
	else if (score >= 80) cout << "Your grade is an B." << endl;
	else if (score >= 70) cout << "Your grade is an C." << endl;
	else if (score >= 60) cout << "Your grade is an D." << endl;
	else if (score >= 0) cout << "Your grade is an F." << endl;
	else cout << "Error: that score is out of range." << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า score = 83

Enter your test score: 83
Your grade is an B.

ตัวแปร score จะถูกทดสอบเงื่อนไขในคำสั่งตามลำดับอย่างต่อเนื่อง จนกระทั่งพบว่าเงื่อนไขเป็นจริง หรือ พบว่าไม่เป็นไปตามเงื่อนไขใดเลย จากการประมวลผล ค่าของ score จะถูกตรวจสอบจนถึงเงื่อนไขที่ 3 แล้วพบว่าเป็นจริง ทำให้คำสั่งตามเงื่อนไขดังกล่าวถูกประมวลผล

3.7 คำสั่ง switch

เราสามารถเขียนคำสั่ง switch แทนโครงสร้าง else if เพื่อใช้ในการตรวจสอบทางเลือกที่เป็นลำดับ โดยมีรูปแบบคำสั่ง ดังนี้

	switch (expression)
    { 	case  constant1  :  statementList1 ;
		case  constant2  :  statementList2 ;
             . . .
		case  constantn  :  statementListn ;
		default  :  statementList0 ;
 
	}

โดยที่ expression หมายถึง นิพจน์จำนวนเต็มที่ใช้ในการเปรียบเทียบกับค่าคงที่ในคำสั่ง constant 1 ถึง constant n หมายถึง ค่าคงที่จำนวนเต็มใดๆ ที่ใช้ตรวจสอบกับผลลัพธ์ของนิพจน์ เพื่อเลือกคำสั่งในการประมวลผล statementList 1 ถึง statementList n หมายถึง ชุดคำสั่งที่จะประมวลผลเมื่อพบว่า ค่าของนิพจน์มีค่าเท่ากันกับค่าคงที่นั้น ส่วน statementList 0 หมายถึง ชุดคำสั่งที่จะประมวลผลเมื่อค่านิพจน์ไม่ตรงกับค่าคงที่ที่กำหนด รูปแบบคำสั่ง switch อาจมี หรือไม่มีส่วนคำสั่ง default : statementList 0 ; ก็ได้

การทำงานของคำสั่ง switch เป็นการทำงานแบบตามลำดับ กล่าวคือ โปรแกรมจะประเมินผลค่าของนิพจน์ในคำสั่ง เพื่อนำไปตรวจสอบกับค่าคงที่ตามลำดับ เริ่มจากกรณีแรกไปถึงกรณีสุดท้าย ถ้าค่าของนิพจน์ที่ได้ตรงกับค่าคงที่ใด โปรแกรมก็จะทำการประมวลผลคำสั่ง ตั้งแต่ชุดคำสั่งในกรณีดังกล่าวเป็นต้นไปจนถึงชุดคำสั่งสุดท้ายในคำสั่ง switch ในกรณีที่ค่าของนิพจน์ไม่ตรงกับค่าคงที่ทุกตัว และมีส่วน default ในคำสั่ง ชุดคำสั่งของ default จะถูกประมวลผล มิฉะนั้น จะไม่มีคำสั่งใดถูกประมวลผล ผังงานการทำงานของคำสั่ง switch แสดงดังรูป 3-5

รูป 3-5 ผังงานคำสั่ง switch

ตัวอย่าง 3.14 แสดงการใช้คำสั่ง switch ในการแสดง * ตามค่าจำนวนเต็ม

int main ( )
{  	int star;
	cout << "Enter numbers of star: "; cin >> star;
	switch (star)
	{ 	case  5: cout << "* ";
		case  4: cout << "* ";
		case  3: cout << "* ";
		case  2: cout << "* ";
		case  1: cout << "* ";   
	}
	cout << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า star = 4

Enter numbers of star: 4
* * * *

เนื่องจาก ค่าของตัวแปร star มีค่าเป็น 4 ซึ่งตรงกับค่าคงที่ในกรณีที่สอง ดังนั้น โปรแกรมจะทำการประมวลผลคำสั่งตั้งแต่ case 4 เป็นต้นมา ทำให้มีการแสดงอักขระ * จำนวน 4 ตัว

ตัวอย่าง 3.15 การกำหนดเกรดตามช่วงคะแนน

int main ( )
{  	int score;
	cout << "Enter your test score: "; cin >> score;
	switch (score/10)
	{ 	case 10:
		case  9: cout << "Your grade is an A." << endl; 
		case  8: cout << "Your grade is an B." << endl; 
		case  7: cout << "Your grade is an C." << endl; 
		case  6: cout << "Your grade is an D." << endl; 
		case  5:
		case  4:
		case  3:
		case  2:
		case  1:
		case  0: cout << "Your grade is an F." << endl; 
		default: cout << "Error: that score is out of range." 
					<< endl;
    }
    cout << "Goodbye." << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า score = 83

Enter your test score: 83
Your grade is an B.
Your grade is an C.
Your grade is an D.
Your grade is an F.
Error: that score is out of range.
Goodbye.

เริ่มต้น โปรแกรมจะทำการหารค่าตัวแปร score ด้วย 10 เพื่อให้ได้ค่าจำนวนเต็มในช่วง 0 ถึง 10 เนื่องจาก ค่า score มีค่าเป็น 83 ทำให้ผลลัพธ์ของนิพจน์ได้ 8 โปรแกรมจะทำการเปรียบเทียบกับค่าคงที่จนถึง case 8 แล้วเริ่มทำการประมวลผลคำสั่งหลัง case 8 เป็นต้นมา รวมถึง คำสั่งหลัง default โปรแกรมดังกล่าวมีข้อผิดพลาดตรรกะจากการประมวลผล

ปัญหาที่พบสามารถแก้ไขได้โดยใช้คำสั่ง break คำสั่ง break จะมีผลให้หลุดออกจากการทำงานของคำสั่ง switch ดังนั้น ในกรณีที่เราไม่ต้องการให้โปรแกรมประมวลผลคำสั่งของกรณีอื่นที่ตามมา เราต้องปิดชุดคำสั่งในกรณีนั้นด้วยคำสั่ง break ผังงานการทำงานของคำสั่ง switch ที่ใช้คำสั่ง break แสดงดังรูป 3-6

รูป 3-6 ผังงานคำสั่ง switch ที่ใช้คำสั่ง break

ตัวอย่าง 3.16 การกำหนดเกรดตามช่วงคะแนนที่ใช้คำสั่ง break

int main ( )
{ 	int score;
	cout << "Enter your test score: "; cin >> score;
	switch (score/10)
	{ 	case 10:
		case  9: cout << "Your grade is an A." << endl; break;
		case  8: cout << "Your grade is an B." << endl; break;
		case  7: cout << "Your grade is an C." << endl; break;
		case  6: cout << "Your grade is an D." << endl; break;
		case  5:
		case  4:
		case  3:
		case  2:
		case  1:
		case  0: cout << "Your grade is an F." << endl; break;
		default: cout << "Error: that score is out of range." 
                  << endl;
    }
    cout << "Goodbye." << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า score = 83

Enter your test score: 83
Your grade is an B.
Goodbye.

จากตัวอย่าง หลังจากที่ทำการพิมพ์ข้อความตาม case 8 คำสั่ง break จะถูกประมวลผล และมีผลให้หลุดจากคำสั่ง switch เพื่อไปทำคำสั่งถัดไป คือ พิมพ์ข้อความ Goodbye.

3.8 ตัวดำเนินการนิพจน์เงื่อนไข

ในภาษา C++ มีตัวดำเนินการพิเศษที่สามารถใช้แทนที่การเขียนคำสั่ง if..else เรียกว่า ตัวดำเนินการนิพจน์เงื่อนไข (conditional expression operator) โดยใช้เครื่องหมาย ? และ : ดังรูปแบบ

condition  ? expression1 : expression2

โดยที่ condition หมายถึง เงื่อนไขที่ใช้ในการตัดสินใจเลือกผลลัพธ์ และ expression1 กับ expression2 เป็นนิพจน์ที่จะถูกกระทำเพื่อหาค่าผลลัพธ์ของตัวดำเนินการตามผลของเงื่อนไขที่กำหนด ตัวดำเนินการนิพจน์เงื่อนไข เป็นตัวดำเนินการที่จะกระทำกับตัวถูกกระทำ 3 ตัว เรียกว่า ternary operator ค่าผลลัพธ์ของตัวดำเนินการนิพจน์เงื่อนไขอาจเป็นค่าของ expression1 หรือ expression2 ขึ้นกับค่าตรรกะของเงื่อนไขที่กำหนด โดยจะเป็นค่าของ expression1 เมื่อเงื่อนไขเป็นจริง และ เป็นค่าของ expression2 เมื่อเงื่อนไขเป็นเท็จ ตัวอย่างคำสั่งการกำหนด เช่น

min = ( x < y ? x : y)

คำสั่งดังกล่าวจะกำหนดค่าต่ำสุดให้กับตัวแปร min เพราะว่า ถ้าเงื่อนไข x < y เป็นจริง จะได้ผลลัพธ์เป็นค่าของตัวแปร x มิฉะนั้น ผลลัพธ์จะเป็นค่าของตัวแปร y อย่างไรก็ดี คำสั่งนิพจน์เงื่อนไขควรใช้กับปัญหาที่มีเงื่อนไขและนิพจน์ที่ไม่ซับซ้อนเกินไป

ตัวอย่าง 3.17 ค่าน้อยที่สุดของเลขจำนวนเต็ม 2 จำนวน

int main ( )
{ 	int m, n;
	cout << "Enter two integers: ";
	cin >> m >> n;
	cout << ( m<n ? m :n ) << " is the minimum." << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า m = 22 และ n = 33

Enter two integers: 22 33
22 is the minimum.

เนื่องจาก ค่าของตัวแปร m และ n มีค่าเป็น 22 และ 33 ทำให้เงื่อนไข m < n มีค่าเป็นจริง ดังนั้น ค่าผลลัพธ์ของนิพจน์ได้ค่า m ซึ่งก็คือ 22

ทดสอบโปรแกรม โดยป้อนค่า m = 33 และ n = 22

Enter two integers: 33 22
22 is the minimum.

เนื่องจาก ค่าของตัวแปร m และ n มีค่าเป็น 33 และ 22 ทำให้เงื่อนไข m < n มีค่าเป็นเท็จ ดังนั้น ค่าผลลัพธ์ของนิพจน์ได้ค่า n ซึ่งก็คือ 22 เช่นกัน

3.9 ข้อผิดพลาดอันเนื่องจากนิพจน์ตรรกะ

นิพจน์ตรรกะ (boolean expression) คือ นิพจน์เงื่อนไขที่ให้ผลลัพธ์เป็นค่าจริงหรือค่าเท็จอย่างใดอย่างหนึ่ง ตัวอย่างเช่น d > 0 , n%d == 0 และ (d > 0 and n%d == 0) จากตัวอย่างที่ผ่านมาเราจะพบว่า ในภาษา C++ นิพจน์ตรรกะจะถูกประเมินเป็นค่าจำนวนเต็ม โดยที่ ค่าจำนวนเต็ม 0 หมายถึงค่าที่เป็นเท็จ และ ค่าจำนวนเต็มทุกค่าที่ไม่เป็น 0 หมายถึงค่าที่เป็นจริง ดังนั้น ในภาษา C++ เราจึงสามารถเขียนเงื่อนไขได้ในรูปแบบของค่าจำนวนเต็ม แทนการเขียนนิพจน์เงื่อนไขที่ใช้ตัวดำเนินการเปรียบเทียบ เช่น != 0 , > 0 หรือ < 0 ดังตัวอย่าง

if (n) cout << "n is not zero";

คำสั่งเบื้องต้นจะพิมพ์ข้อความ “n is not zero” เมื่อ n มีค่าไม่เท่ากับจำนวนเต็ม 0 เพราะว่า ถ้าค่าของนิพจน์ (n) มีค่าไม่เท่ากับ 0 จะทำให้เงื่อนไขมีค่าเป็นจริง

if (n%d) cout << "n is not a multiple of d. ";

จากคำสั่ง ข้อความ “n is not a multiple of d.” จะถูกแสดงทางจอภาพ เมื่อค่าของ n%d มีค่าไม่เท่ากับ 0 กล่าวคือ เมื่อค่าของ n ไม่สามารถหารด้วย d ลงตัว เพราะว่า นิพจน์ n%d คือ การหาค่าเศษเหลือที่ได้จากการหารเลขจำนวนเต็ม

การเขียนนิพจน์ตรรกะในรูปค่าจำนวนเต็ม อาจนำไปสู่ข้อผิดพลาดที่ไม่คาดคิดในการเขียนโปรแกรมด้วยภาษา C++

ตัวอย่าง 3.18 ข้อผิดพลาดตรรกะของนิพจน์บูลเลียน

int main ( )
{ 	int n1, n2, n3;
	cout << "Enter three integers: ";
	cin >> n1 >> n2 >> n3;
	if (n1 >= n2 >= n3) 
		cout << "max = " << n1 << endl; // Logical Error
}

ทดสอบโปรแกรม โดยป้อนค่า n1 = 0 , n2 = 0 และ n3 = 0

Enter three integers: 0 0 1
max = 0

ต้นเหตุของข้อผิดพลาดจากโปรแกรมตัวอย่างมาจาก การที่นิพจน์ตรรกะในภาษา C++ มีค่าเป็นจำนวนเต็ม เนื่องจาก นิพจน์ (n1 >= n2 >= n3) จะมีการประเมินผลจากซ้ายไปขวา โดยที่ n1 >= n2 จะได้ผลลัพธ์เป็นจริง เพราะว่า 0 >= 0 เป็นเงื่อนไขจริง ค่าจริงในภาษา C++ จะถูกเก็บเป็นค่าจำนวนเต็ม 1 ซึ่งค่าดังกล่าวจะถูกนำไปเปรียบเทียบกับค่าของตัวแปร n3 ซึ่งมีค่าเป็น 1 เช่นกัน ทำให้ผลลัพธ์ของนิพจน์โดยรวมมีค่าเป็นจริง เพราะฉะนั้น คำสั่งหลัง if จึงถูกประมวลผล ทำให้คำตอบผิดไปจากความจริง เพราะ ค่าจำนวนเต็ม 0 ไม่ใช่ค่าที่มากที่สุดในเซต {0, 0, 1}

คำสั่ง if ในตัวอย่าง 3.18 เขียนได้ถูกต้องตามรูปแบบคำสั่ง if ที่กำหนดในภาษา C++ และ ทำงานได้เรียบร้อยดังที่ได้อธิบาย ดังนั้น ข้อผิดพลาดดังกล่าวจึงไม่สามารถพบได้โดยโปรแกรมแปลโปรแกรมในช่วงของการแปลโปรแกรม และ ในช่วงของการประมวลผล ข้อผิดพลาดที่เกิดขึ้นจัดเป็นข้อผิดพลาดทางตรรกะ (logical errors)

ตัวอย่างข้อผิดพลาดทางตรรกะอีกตัวอย่างหนึ่งเกิดจากการใช้ตัวดำเนินการที่ผิด เนื่องจาก ในภาษา C++ เครื่องหมาย = หมายถึง ตัวดำเนินการกำหนดค่า ในขณะที่ เครื่องหมาย == หมายถึง ตัวดำเนินการเปรียบเทียบการเท่ากัน ความคล้ายคลึงของตัวดำเนินการทั้งสองมักก่อความสับสนให้กับผู้เขียนโปรแกรมมือใหม่ ที่ยังไม่คุ้นกับการเขียนโปรแกรมด้วยภาษา C++

ตัวอย่าง 3.19 ข้อผิดพลาดอันเนื่องจากการใช้ตัวดำเนินการที่ผิด

int main ( )
{ 	int n;
	cout << "Enter an integer: ";
	cin >> n;
	if (n = 22) cout << m << " = 22" << endl; // Logical Error
	else cout << n << " != 22" << endl;
}

ทดสอบโปรแกรม โดยป้อนค่า n = 77

Enter an integer: 77
22 = 22

เนื่องจาก นิพจน์ n = 22 จะทำการกำหนดค่า n ให้มีค่าเป็น 22 ผลที่ตามมา ค่าของ n จะถูกเปลี่ยนจาก 77 เป็น 22 อย่างไรก็ดี นิพจน์ n = 22 ถือว่าเป็นนิพจน์จำนวนเต็ม โดยค่า 22 เป็นค่าไม่เท่ากับศูนย์ ซึ่งในภาษา C++ จะถือว่าเป็นเงื่อนไขจริง ดังนั้น คำสั่งที่อยู่ก่อนหน้า else จะถูกประมวลผล ทำให้ได้ผลลัพธ์ดังที่แสดงในตัวอย่าง เพื่อให้เป็นไปตามวัตถุประสงค์ของโปรแกรม บรรทัดคำสั่งดังกล่าวควรแก้ไขเป็น

if (n == 22) cout << m << " = 22" << endl;

ข้อผิดพลาดทางตรรกะเป็นข้อผิดพลาดที่ร้ายแรงเมื่อเปรียบเทียบกับข้อผิดพลาดอื่น เช่น ข้อผิด พลาดในช่วงการแปลโปรแกรม (compile-time errors) ตัวอย่างเช่น ข้อผิดพลาดอันเนื่องจากการลืมเครื่องหมาย ; ในคำสั่ง ซึ่งสามารถตรวจพบได้โดยอาศัยโปรแกรมแปลโปรแกรมในช่วงเวลาของการแปลโปรแกรม หรือ แม้แต่ข้อผิดพลาดในช่วงการประมวลผล (run-time errors) ตัวอย่างเช่น การหารด้วยค่าที่เป็นศูนย์ ก็สามารถตรวจพบได้โดยระบบดำเนินการในช่วงเวลาการประมวลผล แต่ข้อผิดพลาดทางตรรกะจะไม่สามารถตรวจพบได้โดยอาศัยความช่วยเหลือของโปรแกรมระบบใดๆ เลย ผู้เขียนโปรแกรมจะต้องตรวจสอบความถูกต้องของผลลัพธ์ที่ได้จากการประมวลผลด้วยตัวเอง ดังนั้น ผู้เขียนโปรแกรมต้องระลึกไว้เสมอว่า ค่าของนิพจน์ตรรกะในภาษา C++ มีค่าเป็นจำนวนเต็ม ซึ่งทำให้การเขียนนิพจน์เงื่อนไข (โดยเฉพาะนิพจน์เงื่อนไขเชิงซ้อน) ในภาษา C++ ค่อนข้างยุ่งยาก ผู้เขียนโปรแกรมจึงควรตรวจสอบเงื่อนไขที่เขียนอย่างถี่ถ้วนก่อนใช้งาน

comp/cpp_selection.txt · Last modified: 2020/11/11 19:03 (external edit)

Page Tools