Ch6: Loops¶
TL;DR: Loop Paradigms: C++ รองรับคำสั่งลูป
for,while, และdo-whileโดยที่do-whileจะประเมินเงื่อนไขหลังจากทำโค้ดในบล็อกเสร็จแล้ว ทำให้รับประกันการทำงานอย่างน้อยหนึ่งครั้งเสมอ
⚡ Quick Reference¶
#include <iostream>
int main() {
// for (init; condition; increment) - ลูปสำหรับทำซ้ำแบบกำหนดจำนวนครั้ง
for (int i = 0; i < 5; ++i) {
// continue - ข้ามคำสั่งที่เหลือในรอบการรันปัจจุบันไปรอบถัดไป
if (i == 2) continue;
// break - สั่งหยุดและออกจากลูปการทำงานทันที
if (i == 4) break;
std::cout << i << " ";
}
std::cout << std::endl;
// while (condition) - ลูปตรวจสอบเงื่อนไขก่อนเข้ารอบการทำงาน
int count = 0;
while (count < 3) {
std::cout << count << " ";
++count;
}
std::cout << std::endl;
// do { ... } while (condition); - ลูปตรวจสอบเงื่อนไขหลังจากทำงานไปแล้วอย่างน้อยหนึ่งรอบ
int k = 0;
do {
std::cout << k << " ";
++k;
} while (k < 3);
std::cout << std::endl;
return 0;
}
🧠 Core Concepts¶
- Loop Paradigms: C++ รองรับคำสั่งลูป
for,while, และdo-whileโดยที่do-whileจะประเมินเงื่อนไขหลังจากทำโค้ดในบล็อกเสร็จแล้ว ทำให้รับประกันการทำงานอย่างน้อยหนึ่งครั้งเสมอ - Standard Iterator Types:
size_tเป็นชนิดข้อมูลจำนวนเต็มไม่มีเครื่องหมายมาตรฐานสำหรับการระบุขนาด ในระบบ 64-bit จะใช้ขนาด 8 Byte และจะเกิดการ Underflow หากมีค่าลดลงต่ำกว่าศูนย์ - Range-Based Iteration: คำสั่ง Range-based
forช่วยอำนวยความสะดวกในการวิ่งวนผ่าน Collection หรือ Initializer List โดยไม่ต้องคุม Index เอง แต่ลูปชนิดนี้ไม่รองรับการวนย้อนกลับแบบดั้งเดิม
⚠️ Pitfalls (Quick Scan)¶
| ข้อผิดพลาด | วิธีแก้ |
|---|---|
| การเรียกใช้ตัวนับลูปนอกสโคปของลูป | ประกาศตัวแปรนอกลูปหากจำเป็นต้องนำค่าสุดท้ายมาประมวลผลต่อ |
| การระบุขอบเขตลูปแบบ Hardcoded | ใช้ const size_t ในการระบุจำนวนรอบการวนซ้ำ |
ลืมใส่การอัปเดตค่า (Increment) ในลูป while |
ตรวจสอบให้มีคำสั่งอัปเดตตัวแปรควบคุมอยู่ในบล็อกลูปเสมอ |
เข้าใจผิดว่าลูป do-while จะไม่ทำงานหากเงื่อนไขเริ่มต้นเป็นเท็จ |
ใช้ลูป for หรือ while หากกรณีไม่วนลูปเลยเป็นสิ่งสำคัญ |
การลดค่าของข้อมูล unsigned size_t ให้ต่ำกว่าศูนย์ |
หลีกเลี่ยงการลดค่าลงต่ำกว่าศูนย์ เช่น เปลี่ยนเงื่อนไขเปรียบเทียบเป็น i > 0 (11.11) |
ใช้เงื่อนไขตรวจสอบ i >= 0 กับตัวแปรไม่มีเครื่องหมาย (unsigned) ในลูปลดค่า |
เปลี่ยนไปใช้ชนิดข้อมูลแบบมีเครื่องหมาย (signed) หรือปรับเงื่อนไขเป็น i > 0 (11.11) |
| พยายามใช้ Range-based for วนลูปย้อนกลับ | ใช้ลูปนับดั้งเดิมหรือใช้ std::reverse_iterator ในการวนย้อนกลับ (11.11) |
| ลืมรีเซ็ตค่าตัวนับภายในในลูปซ้อน (Nested Loops) | เขียนคำสั่งกำหนดค่าตัวแปรควบคุมภายในใหม่ทุกครั้งหลังเริ่มลูปชั้นนอก (11.12) |
เรียกใช้คำสั่ง continue โดยไม่ทำการอัปเดตตัวนับในลูป while |
อัปเดตตัวควบคุมการวนลูปทันทีก่อนเรียกสั่งงาน continue (11.13) |
| ความเข้าใจคลาดเคลื่อนเกี่ยวกับความสำคัญของตัวดำเนินการ Comma | ใช้วงเล็บครอบกลุ่มคำสั่งหรือแยกบรรทัดเขียนเพื่อป้องกันความสับสน (11.4) |
📖 Full Details¶
Cause → Effect → Fix พร้อม timestamp (คลิกเพื่อดู)
* **การเรียกใช้ตัวนับลูปนอกสโคปของลูป** -> **เกิด Compile-time error เนื่องจากตัวแปรถูกทำลายเมื่อหลุดจากลูป** -> **ประกาศตัวแปรนอกลูปหากจำเป็นต้องนำค่าสุดท้ายมาประมวลผลต่อ (12:20)** * **การระบุขอบเขตลูปแบบ Hardcoded** -> **โปรแกรมดูแลรักษายากขึ้นเมื่อขนาดของข้อมูลหรือ Array เปลี่ยนแปลง** -> **ใช้ `const size_t` ในการระบุจำนวนรอบการวนซ้ำ (15:48)** * **ลืมใส่การอัปเดตค่า (Increment) ในลูป `while`** -> **เกิด Infinite Loop ทำให้โปรแกรมทำงานไม่หยุด** -> **ตรวจสอบให้มีคำสั่งอัปเดตตัวแปรควบคุมอยู่ในบล็อกลูปเสมอ (13:00)** * **เข้าใจผิดว่าลูป `do-while` จะไม่ทำงานหากเงื่อนไขเริ่มต้นเป็นเท็จ** -> **บล็อกคำสั่งจะทำงานก่อนหนึ่งรอบเสมอโดยไม่สนใจเงื่อนไขเริ่มต้น** -> **ใช้ลูป `for` หรือ `while` หากกรณีไม่วนลูปเลยเป็นสิ่งสำคัญ (18:00)** * **การลดค่าของข้อมูล unsigned `size_t` ให้ต่ำกว่าศูนย์** -> **เกิดค่าเกิดขีดจำกัดล่าง (Underflow) วนกลับไปเป็นค่าบวกที่สูงที่สุด** -> **หลีกเลี่ยงการลดค่าลงต่ำกว่าศูนย์ เช่น เปลี่ยนเงื่อนไขเปรียบเทียบเป็น `i > 0` (11.11)** * **ใช้เงื่อนไขตรวจสอบ `i >= 0` กับตัวแปรไม่มีเครื่องหมาย (unsigned) ในลูปลดค่า** -> **เกิดลูปอนันต์ (Infinite loop) เนื่องจากตัวแปรไม่มีเครื่องหมายไม่มีทางติดลบ** -> **เปลี่ยนไปใช้ชนิดข้อมูลแบบมีเครื่องหมาย (signed) หรือปรับเงื่อนไขเป็น `i > 0` (11.11)** * **พยายามใช้ Range-based for วนลูปย้อนกลับ** -> **ไม่มีไวยากรณ์รองรับการวนย้อนกลับในตัวภาษาโดยตรง** -> **ใช้ลูปนับดั้งเดิมหรือใช้ `std::reverse_iterator` ในการวนย้อนกลับ (11.11)** * **ลืมรีเซ็ตค่าตัวนับภายในในลูปซ้อน (Nested Loops)** -> **ลูปชั้นในจะไม่ถูกเรียกทำงานในรอบถัดไปของลูปนอก** -> **เขียนคำสั่งกำหนดค่าตัวแปรควบคุมภายในใหม่ทุกครั้งหลังเริ่มลูปชั้นนอก (11.12)** * **เรียกใช้คำสั่ง `continue` โดยไม่ทำการอัปเดตตัวนับในลูป `while`** -> **คำสั่งข้ามทำให้ข้ามฟังก์ชันการอัปเดตตัวแปรจนเกิดลูปอนันต์** -> **อัปเดตตัวควบคุมการวนลูปทันทีก่อนเรียกสั่งงาน `continue` (11.13)** * **ความเข้าใจคลาดเคลื่อนเกี่ยวกับความสำคัญของตัวดำเนินการ Comma** -> **ตัวแปรจะได้รับการกำหนดค่าเฉพาะส่วนขวาสุดเท่านั้นไม่ใช่เป็น Tuple** -> **ใช้วงเล็บครอบกลุ่มคำสั่งหรือแยกบรรทัดเขียนเพื่อป้องกันความสับสน (11.4)**📎 Repo Files¶
11.Loops/11.2ForLoop/main.cpp11.Loops/11.3ForLoopMultipleDeclarations/main.cpp11.Loops/11.4CommaOperator/main.cpp11.Loops/11.5RangeBasedForLoop/main.cpp11.Loops/11.6WhileLoop/main.cpp11.Loops/11.7HugeLoopsWithOutput/main.cpp11.Loops/11.8DoWhileLoop/main.cpp11.Loops/11.9InfiniteLoops/main.cpp11.Loops/11.10InfiniteLoopPractice/main.cpp11.Loops/11.11DecrementingLoops/main.cpp11.Loops/11.12NestedLoops/main.cpp11.Loops/11.13BreakAndContinue/main.cpp11.Loops/11.14FixCalculator/main.cpp11.Loops/11.15ForLoopWithInitCondition/main.cpp