Part of 10306103 หลักการเขียนโปรแกรมเบื้องต้น (Fundamentals of Programming)
บทที่ 1 บทนำ: ปัญหา การคิดเชิงอัลกอริทึม และกระบวนการพัฒนาโปรแกรม
แผนบริหารการสอนประจำบทที่ 1
บทนี้เป็นบทเปิดของรายวิชา 10306103 หลักการเขียนโปรแกรมเบื้องต้น มุ่งปูพื้นฐานวิธีคิดในการแก้ปัญหาด้วยคอมพิวเตอร์ ตั้งแต่การวิเคราะห์ปัญหา การคิดเชิงคำนวณ การออกแบบขั้นตอนวิธี ไปจนถึงการเขียน คอมไพล์ และรันโปรแกรมภาษา C โปรแกรมแรก พร้อมปลูกฝังมาตรฐานการเขียนโค้ดตั้งแต่เริ่มต้น
| ผลลัพธ์ | ข้อความ | หลักฐาน | CLO |
|---|---|---|---|
| LLO1.1 | อธิบายความหมายของปัญหา ขั้นตอนวิธี (algorithm) คุณสมบัติของขั้นตอนวิธี และกระบวนการพัฒนาโปรแกรม | งานข้อ 1 และแบบฝึกหัดท้ายบทกลุ่ม ก | CLO1 |
| LLO1.2 | วิเคราะห์ปัญหาอย่างง่าย และออกแบบขั้นตอนวิธีด้วยผังงาน (flowchart) และรหัสเทียม (pseudocode) | งานข้อ 2 (ปฏิบัติการที่ 1 Lab A) | CLO2 |
| LLO1.3 | เขียน คอมไพล์ และรันโปรแกรมภาษา C อย่างง่ายได้ถูกต้องตามไวยากรณ์ | งานข้อ 3 (ปฏิบัติการที่ 1 Lab B) | CLO3 |
| LLO1.4 | ปฏิบัติตามมาตรฐานการเขียนโค้ดเบื้องต้น (การจัดย่อหน้า การตั้งชื่อสื่อความหมาย การใส่คอมเมนต์) | งานข้อ 4 (ตรวจโค้ดใน Lab B) | CLO5 |
CLO ที่เกี่ยวข้อง (ข้อความจากหลักสูตร):
- CLO1 อธิบายและใช้ตัวแปร ชนิดข้อมูล การรับ-แสดงผล และโครงสร้างควบคุม (if/else, switch, loop) เพื่อแก้ปัญหาและได้ผลลัพธ์ที่ถูกต้อง
- CLO2 อธิบายขั้นตอนการทำงาน (Logic) ของภาษาโปรแกรมและเลือกใช้โครงสร้างควบคุม (Control Structure) ให้สอดคล้องกับโจทย์ที่กำหนดได้
- CLO3 สามารถเขียนโค้ดได้ถูกต้องตามหลักไวยากรณ์ (Syntax) และมีประสิทธิภาพ (Efficiency)
- CLO5 ปฏิบัติตามมาตรฐานการเขียนโค้ด (Indentation, Naming, Commenting, Git commits ที่มีข้อความที่สื่อความหมาย)
บทที่ 1 วางตำแหน่งเป็นจุดเริ่มต้นของการสะสมหลักฐานการเรียนรู้ตลอดภาคการศึกษา งานทั้งสี่ข้อในบทนี้เป็นงานตั้งต้นที่ส่งต่อทักษะไปยังบทถัดไป โดยเฉพาะการออกแบบขั้นตอนวิธีและการตั้งมาตรฐานโค้ด ตามแผนคะแนนรายวิชา (มติผู้สอน 30 ต.ค. 2569 ฉบับที่ 4) งานที่ต้องส่งของบทนี้นับรวมในหมวดใบงานบทที่ 1–13 15% โดยจุดตรวจ CLO5 (มาตรฐานโค้ด) ให้คะแนนและตรวจทุกบทตั้งแต่บทนี้เป็นต้นไป นอกจากนี้บทนี้ยังทำหน้าที่เป็น จุดตรวจความซื่อสัตย์ทางวิชาการ จุดที่ 1 (CLO4 Checkpoint 1: สัญญาจริยธรรมและการใช้ AI) เพื่อตกลงขอบเขตการพัฒนาโค้ดด้วยตนเองและการอ้างอิงอย่างโปร่งใส (เป็นจุดตรวจให้ข้อเสนอแนะ ไม่คิดสัดส่วนคะแนน) (ดูบันทึกสำหรับผู้สอนท้ายบท)
วิธีสอน
- ใช้สถานการณ์ปัญหาในชีวิตประจำวันนำเข้าสู่แนวคิดขั้นตอนวิธีและการคิดเชิงคำนวณ เพื่อเชื่อมโยงสิ่งที่คุ้นเคยกับการคิดเชิงคำนวณ
- สาธิตการวิเคราะห์ปัญหาแบบ input–process–output บนกระดาน แล้วแปลงเป็นผังงานและรหัสเทียมทีละขั้น พร้อมไล่ตรวจด้วยข้อมูลตัวอย่าง
- สาธิตการเขียน คอมไพล์ และรันโปรแกรมภาษา C โปรแกรมแรกบนเครื่องจริง พร้อมชี้ให้เห็นกระบวนการแปลสี่ขั้นตั้งแต่ซอร์สโค้ดจนเป็นไฟล์ปฏิบัติการ
- ให้ลงมือปฏิบัติตามใบงาน โดยกำหนดจุดตรวจระหว่างทางเพื่อให้ข้อมูลป้อนกลับทันที
- สรุปมาตรฐานการเขียนโค้ดเบื้องต้นและเหตุผลเชิงคุณภาพ เพื่อสร้างนิสัยที่ดีตั้งแต่บทแรก
สื่อการเรียนการสอน
- เครื่องคอมพิวเตอร์ที่เข้าถึงแพลตฟอร์มการเรียนของรายวิชาสำหรับเขียน คอมไพล์ และรันโปรแกรมภาษา C (มาตรฐาน C11) บนเว็บ
- เอกสารประกอบบทที่ 1 และสไลด์สรุปสัญลักษณ์ผังงาน
- ตัวอย่างโจทย์วิเคราะห์ปัญหาและไฟล์โปรแกรมตัวอย่าง
hello.cและwelcome.c
การวัดผลและการประเมินผล
กำหนดส่ง: งานข้อ 1–4 ภายใน 23:59 น. ของวันก่อนวันปฏิบัติการในสัปดาห์ที่ 2 ส่วนชุดฝึกท้ายบทและแบบฝึกหัดวัดความเข้าใจของบทนี้ ภายใน 23:59 น. ของวันก่อนวันบรรยายในสัปดาห์ที่ 2 ดูวันที่จริงของตอนเรียนได้ในห้องเรียนออนไลน์ (มติผู้สอน 28 ต.ค. 2569)
| ข้อ | งาน | หลักฐาน | ผลลัพธ์ | CLO |
|---|---|---|---|---|
| 1 | ตอบคำถามแนวคิด: นิยามขั้นตอนวิธี ระบุคุณสมบัติ และเรียงลำดับขั้นกระบวนการพัฒนาโปรแกรม | คำตอบเป็นข้อความ | LLO1.1 | CLO1 |
| 2 | ออกแบบผังงานและรหัสเทียมของปัญหาหาค่ามากที่สุดของจำนวน 3 จำนวน | ผังงาน + รหัสเทียม | LLO1.2 | CLO2 |
| 3 | เขียนและส่งไฟล์ .c ที่คอมไพล์ด้วย gcc -std=c11 -Wall ได้โดยไม่มีข้อผิดพลาดและรันได้ผลตามโจทย์ | ไฟล์ซอร์สโค้ด + ผลการรัน | LLO1.3 | CLO3 |
| 4 | ตรวจว่าโค้ดในข้อ 3 เป็นไปตามมาตรฐานเบื้องต้น | โค้ดที่มีการจัดย่อหน้า ตั้งชื่อ และคอมเมนต์ | LLO1.4 | CLO5 |
เงื่อนไขผ่าน: งานข้อ 4 ประเมินจากไฟล์เดียวกับงานข้อ 3 ดังนั้นงานข้อ 3 ต้องคอมไพล์ผ่านก่อนจึงจะประเมินข้อ 4 ได้
คะแนนใบงาน (10 คะแนน)
| ผลลัพธ์ | สิ่งที่ตรวจ | คะแนน |
|---|---|---|
| LLO1.1 | งานข้อที่ระบุผลลัพธ์นี้ | 3 |
| LLO1.2 | งานข้อที่ระบุผลลัพธ์นี้ | 3 |
| LLO1.3 | งานข้อที่ระบุผลลัพธ์นี้ | 3 |
| LLO1.4 | มาตรฐานโค้ด ตรวจจากโค้ดทุกข้อที่ส่ง | 1 |
ใบงานบทที่ 1–13 รวมกันคิดเป็น 15% ของคะแนนรายวิชา ชิ้นละเท่ากัน ส่งช้าหัก 10% ของคะแนนงานต่อสัปดาห์ที่ช้า สูงสุด 50% และรับงานถึงสิ้นสัปดาห์ที่ 15 งานที่ผู้สอนส่งกลับให้แก้นับเวลาจากการส่งครั้งแรก ดูคะแนนของตนเองได้ที่หน้า “คะแนนของฉัน” ในห้องเรียนออนไลน์ของรายวิชา
เกณฑ์ให้คะแนน
งานข้อ 1 และงานข้อ 3 ใช้เกณฑ์ผ่าน/ไม่ผ่าน:
| เกณฑ์ | ผ่าน | ยังไม่ผ่าน |
|---|---|---|
| งานข้อ 1 | ระบุนิยาม คุณสมบัติครบ และลำดับขั้นถูกต้อง | ขาดคุณสมบัติหรือเรียงลำดับผิด |
| งานข้อ 3 | คอมไพล์ผ่านไม่มีข้อผิดพลาด และผลลัพธ์ตรงโจทย์ | คอมไพล์ไม่ผ่านหรือผลลัพธ์ไม่ตรง |
งานข้อ 2 ใช้เกณฑ์แบบรูบริก 3 ระดับ:
| ระดับ | ผังงาน | รหัสเทียม |
|---|---|---|
| ดี | สัญลักษณ์ถูกต้อง ทุกเส้นทางไปถึงจุดจบ ครอบคลุมกรณีค่าเท่ากัน | สอดคล้องกับผังงานและอ่านเข้าใจง่าย |
| ผ่าน | โครงถูกต้องแต่ขาดบางกรณี | สื่อความได้แต่ไม่ครบขั้น |
| ยังไม่ผ่าน | สัญลักษณ์ผิดหรือเส้นทางไม่ครบ | ไม่สอดคล้องกับผังงาน |
งานข้อ 4 ใช้รายการตรวจ (checklist): จัดย่อหน้าสม่ำเสมอ 4 ช่องว่าง, ตั้งชื่อสื่อความหมายแบบ snake_case, มีคอมเมนต์ส่วนหัวอธิบายหน้าที่ของโปรแกรม
เฉลยจะเปิดในชั้นเรียนหลังทุกคนทำเสร็จ
บทนำ
การเขียนโปรแกรมเริ่มต้นที่วิธีคิด ไม่ใช่ที่ไวยากรณ์ของภาษา ก่อนจะสั่งให้คอมพิวเตอร์ทำงานได้อย่างถูกต้อง ผู้พัฒนาต้องเข้าใจปัญหา แยกแยะข้อมูลเข้าและผลลัพธ์ที่ต้องการ แล้วออกแบบลำดับขั้นตอนการแก้ปัญหาให้ชัดเจนเสียก่อน บทนี้จึงเริ่มจากแนวคิดการคิดเชิงอัลกอริทึมและการคิดเชิงคำนวณ การออกแบบด้วยผังงานและรหัสเทียม แล้วจึงนำไปสู่การเขียนโปรแกรมภาษา C โปรแกรมแรก ซึ่งเป็นเครื่องมือหลักที่ใช้ตลอดรายวิชา
ทักษะในบทนี้เป็นรากฐานของทุกบทที่ตามมา การวิเคราะห์ปัญหาและการออกแบบขั้นตอนวิธีจะถูกใช้ซ้ำเมื่อเรียนโครงสร้างควบคุมในบทที่ 4–5 ฟังก์ชันในบทที่ 6 และโครงงานบูรณาการในบทที่ 15 ส่วนมาตรฐานการเขียนโค้ดที่ปลูกฝังในบทนี้จะถูกตรวจต่อเนื่องไปจนจบรายวิชา
| สิ่งที่ได้จากบทนี้ | ใช้ต่อในบท |
|---|---|
| การวิเคราะห์ปัญหาและการออกแบบขั้นตอนวิธี | บท 4–5 (โครงสร้างควบคุม), บท 10 (เทคนิคการแก้ปัญหา) |
| โครงร่างโปรแกรมภาษา C ขั้นต่ำและการคอมไพล์ | บท 2 เป็นต้นไป (ทุกปฏิบัติการ) |
| มาตรฐานการเขียนโค้ดเบื้องต้น | ทุกบท (จุดตรวจ CLO5) |
ความรู้พื้นฐาน เครื่องมือ และรุ่นซอฟต์แวร์
บทนี้ต้องใช้สภาพแวดล้อมสำหรับเขียน คอมไพล์ และรันโปรแกรมภาษา C ตารางด้านล่างเป็นรุ่นเครื่องมือที่ใช้ทดสอบโค้ดตัวอย่างและคำสั่งในบทนี้จริง
| เครื่องมือ | รุ่นที่ทดสอบ | หน้าที่ |
|---|---|---|
| คอมไพเลอร์ gcc | 13.3.0 (Ubuntu) | แปลซอร์สโค้ด .c เป็นไฟล์ปฏิบัติการ |
| มาตรฐานภาษา | C11 (-std=c11) | กำหนดไวยากรณ์ภาษา C ที่ใช้อ้างอิง |
โค้ดตัวอย่าง คำสั่ง และขนาดไฟล์ในบทนี้ทดสอบด้วย gcc 13.3.0 บนระบบปฏิบัติการลินุกซ์ ขนาดไฟล์ที่แสดงเป็นค่าตัวอย่างซึ่งอาจต่างกันเล็กน้อยตามเครื่องและรุ่นคอมไพเลอร์ หากใช้คอมไพเลอร์หรือระบบปฏิบัติการอื่น เช่น MinGW บนวินโดวส์ คำสั่งคอมไพล์และชื่อไฟล์ปฏิบัติการอาจแตกต่างเล็กน้อย แต่ซอร์สโค้ดภาษา C มาตรฐานใช้ได้เหมือนกัน
วิธีใช้บทเรียนและใบงานในหน้านี้
ใช้เนื้อหาและใบงานบนหน้านี้ร่วมกันได้ทันที โดยเตรียมพื้นที่จดคำตอบและวาดผังงานของตนเอง ก่อนทดลองแต่ละครั้งให้เขียนผลที่คาด แล้วจึงเปรียบเทียบกับผลที่เกิดขึ้นจริง ตารางสำหรับบันทึกเป็นแบบให้คัดลงสมุดหรือไฟล์งาน ไม่ใช่ช่องรับคำตอบที่บันทึกอัตโนมัติบนเว็บไซต์
เริ่มจากการทำความหมายของโจทย์ในหัวข้อ 1.5 ต่อด้วยการทำนายลำดับคำสั่งในหัวข้อ 1.6 และการไล่ค่าผู้ชนะชั่วคราวในหัวข้อ 1.8 จากนั้นทำ Lab A และ Lab B ตามลำดับ ปิดท้ายด้วยคำถามตรวจความเข้าใจก่อนขึ้นบทที่ 2 งานส่งและเกณฑ์คะแนนยังให้ยึดแผนประเมินเดิมของบทนี้
1.1 ปัญหาและการคิดเชิงอัลกอริทึม
ระดับที่ 1: ปัญหา (problem) คือสถานการณ์ที่มีสิ่งที่ต้องการแต่ยังไปไม่ถึง การแก้ปัญหาด้วยคอมพิวเตอร์คือการกำหนดลำดับขั้นตอนที่ทำให้ได้ผลลัพธ์ที่ต้องการจากข้อมูลที่มี ลำดับขั้นตอนนั้นเรียกว่า ขั้นตอนวิธี หรือ อัลกอริทึม (algorithm) คำว่า algorithm มีที่มาจากชื่อของนักคณิตศาสตร์ชาวเปอร์เซีย อัล-ควาริซมี (al-Khwārizmī) ซึ่งมีผลงานด้านการคำนวณราวคริสต์ศักราช 825 เมื่อผลงานถูกแปลเป็นภาษาละติน ชื่อของเขาถูกถอดเป็น Algoritmi และกลายมาเป็นรากของคำว่า algorithm ในปัจจุบัน แนวคิดสำคัญที่สืบทอดมาคือการแก้ปัญหาด้วยลำดับขั้นตอนที่เป็นระบบและมีกฎเกณฑ์ชัดเจน
ระดับที่ 2: ขั้นตอนวิธีที่ดีมีคุณสมบัติสำคัญ 5 ประการตามที่ Knuth (1997) ระบุไว้ ดังตาราง
| คุณสมบัติ | ความหมาย | ตัวอย่างในขั้นตอนการชงเครื่องดื่มร้อน |
|---|---|---|
| มีข้อมูลเข้า (input) | รับข้อมูลเข้าได้ตั้งแต่ศูนย์ชุดขึ้นไป | ผงเครื่องดื่ม น้ำ และปริมาณที่ต้องการ |
| มีผลลัพธ์ (output) | ให้ผลลัพธ์อย่างน้อยหนึ่งอย่าง | เครื่องดื่มที่ชงเสร็จ |
| ความชัดเจน (definiteness) | แต่ละขั้นระบุชัดเจน ไม่กำกวม | "เทน้ำร้อน 200 มิลลิลิตร" ชัดกว่า "เทน้ำพอประมาณ" |
| มีจำนวนขั้นจำกัด (finiteness) | ทำครบแล้วต้องสิ้นสุดได้ | เมื่อคนจนเข้ากันแล้วถือว่าจบ ไม่คนไปเรื่อย ๆ |
| ทำได้จริง (effectiveness) | ทุกขั้นเป็นการกระทำพื้นฐานที่ทำได้จริง | "เทน้ำ" และ "คน" เป็นสิ่งที่ทำได้จริง |
จุดที่ควรเน้นคือ finiteness ถ้าลำดับขั้นตอนไม่มีวันสิ้นสุด เช่น สั่งให้ "คนไปเรื่อย ๆ ไม่หยุด" ลำดับนั้นจะไม่ถือเป็นขั้นตอนวิธี Knuth เรียกลำดับที่ไม่สิ้นสุดเช่นนี้ว่าเป็นเพียง วิธีการคำนวณ (computational method) ไม่ใช่อัลกอริทึม คุณสมบัติทั้งห้านี้จึงเป็นเกณฑ์ที่ใช้ตัดสินว่าแนวทางแก้ปัญหาหนึ่งเป็นขั้นตอนวิธีที่นำไปเขียนเป็นโปรแกรมได้หรือไม่
ระดับที่ 3: การแปลงปัญหาจริงให้เป็นขั้นตอนวิธีอาศัยทักษะที่เรียกว่า การคิดเชิงคำนวณ (computational thinking) ซึ่ง Wing (2006) เสนอว่าเป็นทักษะพื้นฐานที่จำเป็นสำหรับทุกคน ไม่ใช่เฉพาะนักวิทยาการคอมพิวเตอร์ การคิดเชิงคำนวณมักอธิบายด้วยองค์ประกอบสี่ส่วนที่ทำงานร่วมกัน ดังตาราง
| องค์ประกอบ | ความหมาย | ตัวอย่าง: วางแผนจัดกระเป๋าเดินทาง |
|---|---|---|
| การแยกย่อยปัญหา (decomposition) | แบ่งปัญหาใหญ่เป็นส่วนย่อยที่จัดการง่ายขึ้น | แยกเป็นของใช้ เสื้อผ้า และเอกสาร |
| การจดจำรูปแบบ (pattern recognition) | มองหารูปแบบหรือสิ่งที่ซ้ำกัน | ทุกทริปต้องมีของใช้ส่วนตัวชุดเดิม |
| การคิดเชิงนามธรรม (abstraction) | ตัดรายละเอียดที่ไม่จำเป็นออก เหลือหลักการที่ใช้ซ้ำได้ | สร้างรายการของที่ต้องเตรียมที่ใช้ได้กับทุกทริป |
| การออกแบบขั้นตอนวิธี (algorithm design) | เรียงลำดับขั้นการแก้ปัญหาให้มีประสิทธิภาพ | ลำดับการจัดของลงกระเป๋าตามความถี่ที่ใช้ |
ก่อนออกแบบขั้นตอนวิธี ควรวิเคราะห์ปัญหาด้วยกรอบ input–process–output คือระบุว่าข้อมูลเข้าคืออะไร ผลลัพธ์ที่ต้องการคืออะไร และกระบวนการแปลงข้อมูลเข้าเป็นผลลัพธ์เป็นอย่างไร ตัวอย่างเช่น ปัญหาหาคะแนนเฉลี่ยของสามวิชา วิเคราะห์ได้ดังตาราง
| ส่วน | รายละเอียดของปัญหาหาคะแนนเฉลี่ย |
|---|---|
| ข้อมูลเข้า (input) | คะแนนสามวิชา เช่น 78, 85 และ 92 |
| กระบวนการ (process) | รวมคะแนนทั้งสามแล้วหารด้วยจำนวนวิชา คือ 3 |
| ผลลัพธ์ (output) | คะแนนเฉลี่ย คือ (78 + 85 + 92) ÷ 3 = 85.0 |
การวิเคราะห์ที่รอบคอบช่วยให้โปรแกรมที่พัฒนาออกมามีคุณภาพ เพราะลดโอกาสหลงลืมกรณีสำคัญ เช่น กรณีข้อมูลเข้าที่มีค่าเท่ากันหรือค่าขอบเขต ข้อบกพร่องที่พบบ่อยคือการเริ่มเขียนโค้ดก่อนเข้าใจปัญหา ทำให้ต้องแก้ไขซ้ำหลายรอบ (ข้อเท็จจริงเชิงหลักการนี้ยืนยันกับแหล่งอ้างอิงในเอกสารอ้างอิงท้ายบท)
คำถามตรวจความเข้าใจ 1.1: ลำดับขั้นตอนการต้มไข่ถือเป็นขั้นตอนวิธีหรือไม่ จงอธิบายโดยอ้างคุณสมบัติของขั้นตอนวิธี และการสั่งให้ "คนส่วนผสมไปเรื่อย ๆ ไม่หยุด" ขัดกับคุณสมบัติข้อใด
1.2 การออกแบบขั้นตอนวิธี: ผังงานและรหัสเทียม
ระดับที่ 1: ผังงาน (flowchart) คือการแสดงขั้นตอนวิธีด้วยสัญลักษณ์ภาพที่เชื่อมด้วยลูกศร ส่วนรหัสเทียม (pseudocode) คือการบรรยายขั้นตอนวิธีด้วยถ้อยคำใกล้ภาษาธรรมชาติผสมโครงสร้างควบคุม ทั้งสองแบบใช้สื่อสารวิธีแก้ปัญหาก่อนลงมือเขียนโค้ดจริง ข้อดีคือปรับแก้แนวคิดได้ง่ายก่อนจะผูกติดกับไวยากรณ์ของภาษาใดภาษาหนึ่ง
ระดับที่ 2: สัญลักษณ์ผังงานมีการกำหนดเป็นมาตรฐาน โดยองค์กร ANSI กำหนดไว้ตั้งแต่ทศวรรษ 1960 และองค์กร ISO รับมาเป็นมาตรฐานในปี 1970 ต่อมาเป็นมาตรฐาน ISO 5807 ที่เผยแพร่ในปี 1985 สัญลักษณ์ที่ใช้บ่อยสรุปได้ดังตาราง
| สัญลักษณ์ | รูปทรง | ความหมาย |
|---|---|---|
| จุดเริ่ม/จุดจบ (terminator) | วงรีหรือสี่เหลี่ยมมุมมน | จุดเริ่มต้นและจุดสิ้นสุดของขั้นตอนวิธี |
| ประมวลผล (process) | สี่เหลี่ยมผืนผ้า | การคำนวณหรือการเปลี่ยนแปลงค่าของข้อมูล |
| ตัดสินใจ (decision) | สี่เหลี่ยมข้าวหลามตัด | การตรวจเงื่อนไข มีทางออกตามผล เช่น จริง/เท็จ |
| รับเข้า/แสดงผล (input/output) | สี่เหลี่ยมด้านขนาน | การรับข้อมูลเข้าหรือการแสดงผลลัพธ์ |
| เส้นการไหล (flowline) | ลูกศร | ทิศทางการไหลจากขั้นหนึ่งไปอีกขั้น |
| จุดเชื่อม (connector) | วงกลมเล็กมีป้ายกำกับ | เชื่อมผังงานที่อยู่คนละส่วนหรือคนละหน้าเข้าด้วยกัน |
รหัสเทียมไม่มีไวยากรณ์ตายตัว แต่ยึดหลักให้อ่านเข้าใจง่ายและแปลงเป็นโค้ดได้ตรง นิยมใช้คำสั่งสั้น ๆ เช่น รับค่า แสดง กำหนดค่า และใช้การเยื้องย่อหน้าแสดงขอบเขตของเงื่อนไข ตัวอย่างรหัสเทียมของการหาค่ามากที่สุดระหว่างจำนวน a และ b
เริ่ม
รับค่า a และ b
ถ้า a มากกว่า b
ค่ามากที่สุด คือ a
มิฉะนั้น
ค่ามากที่สุด คือ b
แสดง ค่ามากที่สุด
จบสำหรับปัญหาที่มีสามจำนวน แนวทางที่กระชับคือใช้ตัวแปร max เก็บค่ามากสุดที่พบจนถึงปัจจุบัน แล้วเทียบกับจำนวนที่เหลือทีละตัว เขียนเป็นรหัสเทียมและอธิบายผังงานได้ดังนี้
เริ่ม
รับค่า a, b, c
กำหนด max = a
ถ้า b มากกว่า max
max = b
ถ้า c มากกว่า max
max = c
แสดง max
จบผังงานที่ตรงกับรหัสเทียมนี้เริ่มจากสัญลักษณ์จุดเริ่ม ตามด้วยสัญลักษณ์รับเข้าสำหรับ a, b, c แล้วสัญลักษณ์ประมวลผลกำหนด max = a จากนั้นเป็นสัญลักษณ์ตัดสินใจ b มากกว่า max ถ้าจริงให้ไปที่สัญลักษณ์ประมวลผล max = b ถ้าเท็จให้ข้ามไป ทั้งสองทางมาบรรจบกันก่อนเข้าสัญลักษณ์ตัดสินใจถัดไป c มากกว่า max ซึ่งทำงานทำนองเดียวกัน สุดท้ายเป็นสัญลักษณ์แสดงผล max แล้วจบ
การไล่ตรวจ (trace) ด้วยข้อมูลตัวอย่างช่วยยืนยันความถูกต้องก่อนเขียนโค้ด เช่น ใช้ a = 5, b = 9, c = 2
| ขั้น | เงื่อนไข | ค่า max หลังทำขั้นนั้น |
|---|---|---|
| กำหนดค่าเริ่มต้น | — | 5 |
ตรวจ b มากกว่า max | 9 มากกว่า 5 เป็นจริง จึง max = b | 9 |
ตรวจ c มากกว่า max | 2 มากกว่า 9 เป็นเท็จ จึงไม่เปลี่ยน | 9 |
| แสดงผล | — | 9 |
ระดับที่ 3: ผังงานและรหัสเทียมที่ออกแบบสำหรับปัญหาเดียวกันต้องให้ผลสอดคล้องกัน ผังงานมีจุดเด่นที่มองเห็นเส้นทางการตัดสินใจเป็นภาพ แต่ปรับแก้ยากเมื่อขั้นตอนซับซ้อน ส่วนรหัสเทียมแก้ไขง่ายและแปลงเป็นโค้ดได้ตรงกว่า ตัวอย่างปัญหาอื่นที่ออกแบบได้ง่าย เช่น การตรวจว่าจำนวนเต็มเป็นเลขคู่หรือเลขคี่ เขียนรหัสเทียมได้ดังนี้
เริ่ม
รับค่า n
ถ้า เศษของ n หารด้วย 2 เท่ากับ 0
แสดง "เลขคู่"
มิฉะนั้น
แสดง "เลขคี่"
จบข้อบกพร่องที่พบบ่อยคือเส้นทางในผังงานไม่ครบทุกกรณี หรือรหัสเทียมข้ามขั้นที่จำเป็น ทำให้เมื่อแปลงเป็นโค้ดในบทที่ 4–5 เกิดผลลัพธ์ผิดพลาด การไล่ตรวจด้วยข้อมูลตัวอย่างหลายชุด โดยเฉพาะกรณีค่าเท่ากันและค่าขอบเขต จึงเป็นขั้นที่ไม่ควรข้าม (ข้อเท็จจริงมาตรฐานสัญลักษณ์ผังงานยืนยันกับแหล่งอ้างอิงในเอกสารอ้างอิงท้ายบท)
คำถามตรวจความเข้าใจ 1.2: ในผังงาน สัญลักษณ์สี่เหลี่ยมข้าวหลามตัดใช้แทนสิ่งใด และโดยทั่วไปมีทางออกกี่ทาง
1.3 กระบวนการพัฒนาโปรแกรมและภาษา C
ระดับที่ 1: การพัฒนาโปรแกรมหนึ่งชิ้นมีลำดับขั้นหลัก 5 ขั้น ได้แก่ วิเคราะห์ปัญหา ออกแบบขั้นตอนวิธี เขียนโค้ด ทดสอบและดีบัก และบำรุงรักษา ภาษา C เป็นเครื่องมือที่ใช้ในขั้นเขียนโค้ดของรายวิชานี้
ระดับที่ 2: ลำดับขั้นทั้งห้าสอดคล้องกับกรอบวงจรการพัฒนาซอฟต์แวร์ (software development life cycle) ที่ใช้ในงานจริง ดังตาราง
| ขั้น | ทำอะไร | ตัวอย่างในโจทย์หาคะแนนเฉลี่ย |
|---|---|---|
| วิเคราะห์ปัญหา | ระบุความต้องการ ข้อมูลเข้า และผลลัพธ์ | รับคะแนนสามวิชา ต้องการคะแนนเฉลี่ย |
| ออกแบบขั้นตอนวิธี | ร่างลำดับการแก้ปัญหาด้วยผังงาน/รหัสเทียม | รวมคะแนนแล้วหารด้วยจำนวนวิชา |
| เขียนโค้ด | แปลงขั้นตอนวิธีเป็นภาษา C | เขียนโปรแกรมคำนวณและแสดงผล |
| ทดสอบและดีบัก | รันด้วยข้อมูลตัวอย่างและแก้ข้อผิดพลาด | ตรวจว่าชุด 78, 85, 92 ได้ 85.0 |
| บำรุงรักษา | แก้ไขและต่อยอดเมื่อความต้องการเปลี่ยน | เพิ่มการรองรับจำนวนวิชาที่มากกว่าสาม |
ในงานจริงมักมีขั้น นำไปใช้งาน (deployment) คั่นระหว่างการทดสอบกับการบำรุงรักษาด้วย แต่ในบริบทของรายวิชาเบื้องต้นนี้ยึดลำดับห้าขั้นข้างต้นเป็นหลัก
ภาษา C เป็นภาษาเชิงกระบวนการ (procedural) ที่พัฒนาโดย Dennis Ritchie ที่ Bell Labs ราวปี ค.ศ. 1972 โดยพัฒนาต่อจากภาษา B และในปี ค.ศ. 1973 ระบบปฏิบัติการยูนิกซ์ถูกเขียนใหม่ด้วยภาษา C ต่อมาภาษา C ได้รับการกำหนดมาตรฐานอย่างเป็นทางการ โดยองค์กร ANSI ตั้งคณะทำงานในปี ค.ศ. 1983 และประกาศมาตรฐาน C89 ในปี ค.ศ. 1989 จากนั้นองค์กร ISO/IEC รับมาเป็นมาตรฐานหมายเลข 9899 ซึ่งมีการปรับปรุงหลายรุ่นดังตาราง
| รุ่น | ปี | มาตรฐาน ISO/IEC |
|---|---|---|
| C89 / C90 | 1989 / 1990 | ISO/IEC 9899:1990 |
| C99 | 1999 | ISO/IEC 9899:1999 |
| C11 | 2011 | ISO/IEC 9899:2011 |
| C17 | 2018 | ISO/IEC 9899:2018 |
| C23 | 2024 | ISO/IEC 9899:2024 |
รายวิชานี้อ้างอิงรุ่น C11 จึงระบุตัวเลือก -std=c11 เมื่อคอมไพล์ เพื่อให้คอมไพเลอร์ตรวจไวยากรณ์ตามรุ่นที่กำหนดอย่างสม่ำเสมอ
ระดับที่ 3: เมื่อเขียนซอร์สโค้ดไฟล์นามสกุล .c เสร็จ การแปลงเป็นไฟล์ปฏิบัติการผ่านกระบวนการสี่ขั้น ซึ่งปกติ gcc ทำให้ครบในคำสั่งเดียว แต่สามารถสั่งทีละขั้นเพื่อศึกษาได้ ตารางด้านล่างสรุปสี่ขั้น พร้อมผลที่ได้จากการสั่งทีละขั้นกับไฟล์ hello.c จริง (ทดสอบด้วย gcc 13.3.0 ขนาดไฟล์เป็นค่าตัวอย่าง)
| ขั้น | คำสั่ง gcc | ไฟล์ผลลัพธ์ | หน้าที่ |
|---|---|---|---|
| ประมวลผลก่อนแปล (preprocess) | gcc -E hello.c -o hello.i | hello.i | แทรกเนื้อหาของส่วนหัว <stdio.h> ลบคอมเมนต์ และแทนที่มาโคร |
| แปล (compile) | gcc -S hello.i -o hello.s | hello.s | แปลเป็นภาษาแอสเซมบลี |
| แปลงเป็นภาษาเครื่อง (assemble) | gcc -c hello.s -o hello.o | hello.o | แปลงเป็นรหัสเครื่องในไฟล์ออบเจกต์ |
| เชื่อมโยง (link) | gcc hello.o -o hello | hello | เชื่อมฟังก์ชันไลบรารีและโค้ดเริ่มต้น ได้ไฟล์ปฏิบัติการ |
จุดสำคัญของแต่ละขั้น คือ ขั้น preprocess นำเนื้อหาของ <stdio.h> มาแทรกจริง ทำให้ไฟล์ hello.i ยาวขึ้นมาก (จากซอร์สโค้ดราว 185 ไบต์กลายเป็นราว 14,880 ไบต์ หรือหลายร้อยบรรทัด) โดยซอร์สโค้ดที่เขียนเองยังอยู่ท้ายไฟล์ ขั้น compile แปลเป็นภาษาแอสเซมบลีในไฟล์ hello.s ซึ่งยังอ่านเป็นข้อความได้และจะเห็นข้อความ "Hello, World" ปรากฏอยู่ ขั้น assemble แปลงเป็นไฟล์ออบเจกต์ hello.o ที่เป็นรหัสเครื่อง แต่การเรียกฟังก์ชันแสดงผลของไลบรารีมาตรฐานยังไม่ถูกเชื่อม ไฟล์นี้จึงยังรันไม่ได้ และขั้น link เชื่อมการเรียกฟังก์ชันเข้ากับไลบรารีและเพิ่มโค้ดเริ่มต้นของโปรแกรม จึงได้ไฟล์ปฏิบัติการที่มีขนาดใหญ่กว่าไฟล์ออบเจกต์ (ราว 15,960 ไบต์) และรันได้
โครงร่างของโปรแกรมภาษา C ขั้นต่ำประกอบด้วยการนำเข้าส่วนหัวมาตรฐานด้วย #include การประกาศฟังก์ชัน main ซึ่งเป็นจุดเริ่มทำงานของโปรแกรม และการคืนค่าด้วย return โปรแกรมทุกตัวต้องมีฟังก์ชัน main เพียงหนึ่งเดียว เพราะระบบปฏิบัติการเรียกฟังก์ชันนี้เป็นจุดเข้า ข้อบกพร่องที่พบบ่อยของผู้เริ่มต้นคือการสับสนระหว่างขั้นเขียนโค้ดกับขั้นคอมไพล์ ทำให้เข้าใจผิดว่าแก้ซอร์สโค้ดแล้วโปรแกรมจะเปลี่ยนทันทีโดยไม่ต้องคอมไพล์ใหม่ (ข้อเท็จจริงเกี่ยวกับประวัติ มาตรฐาน และกระบวนการแปลภาษา C ยืนยันกับแหล่งอ้างอิงในเอกสารอ้างอิงท้ายบท)
คำถามตรวจความเข้าใจ 1.3: กระบวนการแปลภาษา C มีสี่ขั้น จงเรียงลำดับและอธิบายว่าเหตุใดไฟล์ออบเจกต์ hello.o จึงยังรันไม่ได้จนกว่าจะผ่านขั้นเชื่อมโยง
1.4 โปรแกรมแรกและมาตรฐานการเขียนโค้ดเบื้องต้น
ระดับที่ 1: โปรแกรมภาษา C โปรแกรมแรกที่นิยมใช้เรียนคือการแสดงข้อความต้อนรับออกทางจอภาพ ดังตัวอย่าง
#include <stdio.h>
int main(void) {
printf("Hello, World\n");
return 0;
}ระดับที่ 2: โปรแกรมข้างต้นแปลและรันได้จริง (ทดสอบแล้วด้วย gcc 13.3.0) แต่ละบรรทัดมีหน้าที่ดังตาราง
| ส่วนของโค้ด | หน้าที่ |
|---|---|
#include <stdio.h> | นำเข้าส่วนหัวมาตรฐานสำหรับการรับ-แสดงผล ทำให้เรียกใช้ printf ได้ |
int main(void) | ประกาศฟังก์ชันหลักที่เป็นจุดเริ่มทำงานของโปรแกรม |
printf("Hello, World\n"); | แสดงข้อความออกจอภาพ โดย \n คืออักขระขึ้นบรรทัดใหม่ |
return 0; | คืนค่า 0 เพื่อบอกระบบปฏิบัติการว่าโปรแกรมจบปกติ |
การคอมไพล์และรันทำได้ด้วยคำสั่ง
gcc -std=c11 -Wall hello.c -o hello
./helloผลลัพธ์ที่ได้คือข้อความ Hello, World หนึ่งบรรทัด ตัวเลือก -Wall เปิดการแจ้งเตือน (warnings) ซึ่งช่วยตรวจจับข้อผิดพลาดเชิงคุณภาพของโค้ดตั้งแต่ขั้นคอมไพล์ การพัฒนาโปรแกรมจึงเป็นวงจรเขียน–คอมไพล์–รัน คือเขียนหรือแก้ซอร์สโค้ด คอมไพล์ใหม่ แล้วรันเพื่อตรวจผล หากผลไม่ตรงก็กลับไปแก้ซอร์สโค้ดและคอมไพล์ใหม่อีกครั้ง การแก้ซอร์สโค้ดเพียงอย่างเดียวโดยไม่คอมไพล์ใหม่จะไม่ทำให้ไฟล์ปฏิบัติการเปลี่ยน
ระดับที่ 3: มาตรฐานการเขียนโค้ดเบื้องต้นที่รายวิชากำหนดตั้งแต่บทแรกมีสามด้าน ด้านแรกคือการจัดย่อหน้า (indentation) สม่ำเสมอ 4 ช่องว่างเพื่อแสดงโครงสร้าง ด้านที่สองคือการตั้งชื่อ (naming) ที่สื่อความหมายแบบ snake_case และด้านที่สามคือการใส่คอมเมนต์ (commenting) อธิบายหน้าที่ของโปรแกรมหรือส่วนที่เข้าใจยาก ตารางด้านล่างเทียบโค้ดที่ยังไม่ได้มาตรฐานกับฉบับที่ปรับแล้ว
| ด้าน | ยังไม่ได้มาตรฐาน | ปรับตามมาตรฐาน |
|---|---|---|
| การตั้งชื่อ | int n1 = 80; | int score_math = 80; |
| การจัดย่อหน้า | เขียนคำสั่งชิดซ้ายทุกบรรทัดในบล็อก | เยื้อง 4 ช่องว่างในบล็อกของ main |
| คอมเมนต์ | ไม่มีคอมเมนต์อธิบาย | มีคอมเมนต์ส่วนหัวบอกหน้าที่ของโปรแกรม |
มาตรฐานเหล่านี้สอดคล้องกับ CLO5 และช่วยให้โค้ดอ่านง่าย บำรุงรักษาได้ ซึ่งเป็นพื้นฐานของคุณภาพโค้ดที่จะเน้นย้ำต่อเนื่องในบทถัดไปและจะสรุปรวบยอดในบทที่ 13
คำถามตรวจความเข้าใจ 1.4: เหตุใดการตั้งชื่อตัวแปรว่า n1 จึงด้อยกว่าการตั้งชื่อว่า score_math ในแง่คุณภาพโค้ด
1.5 กรณีศึกษาต่อเนื่อง: จากคำขอคลุมเครือสู่ขั้นตอนที่ตรวจได้
สมมติห้องปฏิบัติการต้องการโปรแกรมช่วยจัดชุดอุปกรณ์ คำขอแรกคือ “ช่วยบอกว่าของพอไหม” ประโยคนี้ยังเขียนโปรแกรมไม่ได้ เพราะไม่รู้ว่าของชนิดใด หนึ่งชุดใช้เท่าไร และต้องรายงานอะไร การเริ่มพิมพ์โค้ดทันทีจะทำให้ผู้เขียนเป็นคนตัดสินความหมายแทนผู้ใช้โดยไม่รู้ตัว
เปลี่ยนคำขอเป็นข้อกำหนดว่า มีสายเชื่อมต่อ 17 เส้น หนึ่งชุดใช้ 3 เส้น ต้องรายงานจำนวนชุดสมบูรณ์และจำนวนเส้นที่เหลือ โดยไม่แบ่งสายหนึ่งเส้นไปหลายชุด ข้อมูลเป็นจำนวนเต็มไม่ติดลบ และจำนวนเส้นต่อชุดต้องมากกว่าศูนย์ ข้อกำหนดนี้บอกทั้งหน่วย ขอบเขต และความหมายของผลลัพธ์
| คำถามก่อนออกแบบ | คำตอบในสถานการณ์นี้ | สิ่งที่ผิดได้ถ้าไม่ถาม |
|---|---|---|
| นับอะไร | สายเชื่อมต่อเป็นเส้น | นำจำนวนกล่องมาหารกับจำนวนเส้น |
| หนึ่งชุดหมายถึงอะไร | ใช้สายครบ 3 เส้น | นับชุดที่ยังไม่ครบเป็นหนึ่งชุด |
| ต้องการผลลัพธ์ใด | ชุดสมบูรณ์และของเหลือ | รายงานเพียง 5.67 โดยไม่อธิบาย |
| รับศูนย์ได้หรือไม่ | ของมีศูนย์ได้ แต่ขนาดชุดเป็นศูนย์ไม่ได้ | เกิดการหารด้วยศูนย์ |
| ผลลัพธ์ตรวจด้วยอะไร | จำนวนชุดคูณขนาดชุด บวกของเหลือ ต้องเท่าของเดิม | เชื่อผลเพราะโปรแกรมรันจบ |
ใบงาน 1: ทำความหมายของโจทย์ก่อนเลือกสูตร
ก่อนอ่านวิธีคำนวณ ให้บันทึกคำตอบของตนเองจากสถานการณ์สายเชื่อมต่อ 17 เส้น ชุดละ 3 เส้น ลองนึกว่าคนจัดอุปกรณ์ต้องนำคำตอบไปทำอะไร หากตอบเป็นเลขทศนิยมอย่างเดียว เขาจะรู้หรือไม่ว่าต้องจัดชุดที่ครบแล้วกี่ชุดและแยกสายเหลือไว้กี่เส้น
| ประเด็นที่ต้องตกลง | สิ่งที่คุณระบุจากโจทย์ |
|---|---|
| ข้อมูลเข้าแต่ละค่าและหน่วย | บันทึกปริมาณทั้งหมดและปริมาณต่อชุด |
| ผลลัพธ์แต่ละช่องและหน่วย | บันทึกสิ่งที่ผู้ใช้ต้องนำไปใช้งาน |
| ค่าศูนย์ที่ยอมรับได้ | ระบุค่าที่เป็นศูนย์ได้พร้อมเหตุผล |
| ค่าศูนย์ที่ต้องปฏิเสธ | ระบุว่าจะตรวจค่าตัวใดก่อนคำนวณ |
| วิธีตรวจคำตอบย้อนกลับ | เขียนความสัมพันธ์ระหว่างของเดิม ชุดที่ได้ และของเหลือ |
เมื่อเขียนครบ ให้เปลี่ยนปริมาณสายเป็น 18, 2 และ 0 โดยคงขนาดชุดไว้เท่าเดิม ทำนายผลก่อนดูตารางตัวอย่าง แล้วแยกให้ได้ว่า “ข้อมูลถูกแต่ได้ศูนย์ชุด” ต่างจาก “ข้อมูลผิดจึงยังไม่ควรคำนวณ” อย่างไร คำอธิบายนี้สำคัญกว่าการจำสูตรหารเพียงบรรทัดเดียว
1.5.1 แยกข้อกำหนด อัลกอริทึม และโปรแกรม
ข้อกำหนดตอบว่า “ต้องการอะไร” อัลกอริทึมตอบว่า “ทำอย่างไร” ส่วนโปรแกรมเป็นการแสดงอัลกอริทึมด้วยภาษาที่เครื่องมือแปลได้ ทั้งสามอย่างเกี่ยวข้องกันแต่ใช้แทนกันไม่ได้ รหัสที่ถูกไวยากรณ์อาจทำผิดข้อกำหนด และรหัสเทียมที่มีแนวคิดถูกต้องก็ยังต้องตรวจรายละเอียดเมื่อแปลงเป็น C
สำหรับตัวอย่างนี้ กระบวนการคือรับจำนวนสายและขนาดชุด ตรวจขอบเขต คำนวณจำนวนชุดด้วยการหารจำนวนเต็ม คำนวณของเหลือ แล้วแสดงพร้อมหน่วย รหัสเทียมต่อไปนี้เป็นคำอธิบายอัลกอริทึม ไม่ใช่โค้ด C ที่นำไปรันได้ทันที
รับจำนวนสายและจำนวนสายต่อชุด
ถ้าจำนวนสายติดลบ หรือจำนวนสายต่อชุดไม่มากกว่าศูนย์
รายงานว่าข้อมูลไม่อยู่ในขอบเขต แล้วจบ
คำนวณจำนวนชุดสมบูรณ์
คำนวณจำนวนสายที่เหลือ
รายงานจำนวนชุดและจำนวนสายที่เหลือ พร้อมหน่วยเหตุผลที่ตรวจขอบเขตก่อนคำนวณคือขั้นตอนหลังมีข้อสมมติว่าตัวหารไม่เป็นศูนย์ หากย้ายการตรวจไปไว้หลังหาร แม้ข้อความเตือนจะถูกต้อง แต่โปรแกรมได้ทำสิ่งที่ไม่อนุญาตไปแล้ว ลำดับขั้นจึงเป็นส่วนหนึ่งของความถูกต้อง ไม่ใช่เพียงรูปแบบการเขียน
1.5.2 ทดลองด้วยมือก่อนเลือกภาษา
ทดลองแจกสายครั้งละ 3 เส้น จาก 17 จะเหลือ 14, 11, 8, 5 และ 2 ทำได้ห้าครั้ง เมื่อเหลือ 2 ไม่พอทำชุดถัดไป ผลจึงเป็น 5 ชุด เหลือ 2 เส้น วิธีแจกทีละชุดกับวิธีหารให้ผลเดียวกันในขอบเขตนี้ แต่จำนวนขั้นต่างกัน เมื่อมีสายจำนวนมาก การใช้สูตรช่วยลดขั้นได้
ลองเปลี่ยนข้อมูลโดยยังไม่เปลี่ยนอัลกอริทึม กรณี 18 เส้นได้ 6 ชุดเหลือ 0 กรณี 2 เส้นได้ 0 ชุดเหลือ 2 และกรณี 0 เส้นได้ 0 ชุดเหลือ 0 กรณีที่ได้ศูนย์ชุดไม่ได้เป็นข้อผิดพลาด เพราะข้อกำหนดอนุญาตให้ของไม่พอหนึ่งชุด นี่เป็นตัวอย่างของการแยก “ผลลัพธ์ศูนย์” ออกจาก “ข้อมูลผิด”
| สายทั้งหมด | ต่อชุด | ผลที่คาดหวัง | เหตุผลที่เลือกทดสอบ |
|---|---|---|---|
| 17 | 3 | 5 ชุด เหลือ 2 | กรณีทั่วไปที่มีเศษ |
| 18 | 3 | 6 ชุด เหลือ 0 | หารลงตัว |
| 2 | 3 | 0 ชุด เหลือ 2 | ของน้อยกว่าหนึ่งชุด |
| 0 | 3 | 0 ชุด เหลือ 0 | ค่าขอบเขตล่างที่ยอมรับ |
| 17 | 0 | ปฏิเสธก่อนคำนวณ | ตัวหารที่ใช้ไม่ได้ |
ตารางนี้ทำหน้าที่เป็นเกณฑ์ตรวจคำตอบ เมื่อถึงบทตัวแปรและตัวดำเนินการจะใช้ข้อมูลเดิมแปลงเป็น C เมื่อถึงบททางเลือกจะเพิ่มการตรวจขอบเขต และเมื่อถึงบทฟังก์ชันจะแยกส่วนคำนวณออกจากการรับข้อมูล จึงเห็นว่าความเข้าใจโจทย์เดิมนำกลับมาใช้ได้หลายครั้ง
1.6 อ่านโปรแกรมเหมือนติดตามเหตุการณ์ ไม่ใช่จำข้อความ
ใบงาน 2: ทำนายลำดับคำสั่งก่อนกดรัน
อ่านโปรแกรมด้านล่างแล้วตอบคำถามต่อไปนี้ก่อนทดลอง อย่าแก้คำทำนายย้อนหลังให้เหมือนผลจริง หากคำตอบต่างกันให้ใช้ความต่างนั้นหาจุดที่ยังเข้าใจไม่ตรงกับการทำงานของโปรแกรม
- โปรแกรมควรแสดงข้อความกี่บรรทัด และเรียงอย่างไร
- หากสลับคำสั่งแสดงข้อความที่สองกับสาม ผลจะเปลี่ยนตรงไหน
- โปรแกรมนี้คำนวณจำนวนชุดหรือเพียงแสดงข้อความ ชี้คำสั่งประกอบคำอธิบาย
- หากโปรแกรมแปลผ่านแต่ลำดับผลไม่ตรงกับสิ่งที่โจทย์ต้องการ ควรตรวจอะไรต่อ
| รอบทดลอง | สิ่งที่คาดก่อนรัน | ผลจริงที่สังเกต | เหตุผลของความต่าง |
|---|---|---|---|
| โปรแกรมตามตัวอย่าง | บันทึกเองก่อนทดลอง | บันทึกหลังรัน | อธิบายตามลำดับคำสั่ง |
| สลับคำสั่งที่สองกับสาม | บันทึกเองก่อนทดลอง | บันทึกหลังแปลและรันใหม่ | ชี้คำสั่งที่เปลี่ยน |
| แก้เฉพาะข้อความหนึ่งบรรทัด | บันทึกเองก่อนทดลอง | บันทึกหลังแปลและรันใหม่ | แยกข้อมูลข้อความจากโครงสร้างคำสั่ง |
ใช้การสลับลำดับหรือแก้ข้อความที่ยังเป็นโค้ดถูกต้องเพื่อเปรียบเทียบพฤติกรรม ไม่ต้องเพิ่มตัวแปร เงื่อนไข หรือคำสั่งรับข้อมูลที่ยังไม่เรียน
พิจารณาโปรแกรมขนาดเล็กที่ยังไม่รับข้อมูล ตัวเลขในโปรแกรมเป็นข้อมูลสมมติเพื่อฝึกติดตามลำดับเท่านั้น
#include <stdio.h>
int main(void)
{
puts("Prepare equipment");
puts("Check the number of cables");
puts("Report complete kits and leftovers");
return 0;
}ผลที่เห็นเป็นข้อความสามบรรทัดตามลำดับที่เขียน โปรแกรมนี้ยังไม่ได้คำนวณจำนวนชุดจริง การมีคำว่า “Check” หรือ “Report” ในข้อความไม่ได้ทำให้คอมพิวเตอร์ตรวจและรายงานเอง เครื่องทำงานตามคำสั่งเรียกฟังก์ชันแสดงข้อความ ไม่ได้ตีความความตั้งใจจากภาษาอังกฤษภายในเครื่องหมายคำพูด
ให้ทดลองสลับบรรทัดที่สองกับสาม ผลลัพธ์จะเปลี่ยนลำดับ แต่ยังคอมไพล์ได้ การคอมไพล์จึงตรวจได้บางส่วน เช่น รูปแบบภาษาและการใช้ชื่อที่ประกาศไว้ ไม่ได้รับรองว่าลำดับงานเหมาะสมกับโจทย์ จากนั้นทดลองเปลี่ยนข้อความโดยคงคำสั่งเดิม จะเห็นความต่างระหว่างข้อมูลที่แสดงกับโครงสร้างโปรแกรม
ขั้นตอนแปลภาษาอาจประกอบด้วยการประมวลผลก่อนแปล การแปล และการเชื่อมโยง แม้เครื่องมือบนแพลตฟอร์มจะรวมให้กดปุ่มเดียวก็ตาม เวลารายงานปัญหาจึงควรบอกว่าเกิดระหว่างแปลหรือหลังเริ่มรัน พร้อมข้อความจริงและข้อมูลที่ใช้ ไม่ใช้คำว่า “มันไม่ได้” เพียงอย่างเดียว แนวคิดเรื่องการแปลและสภาพแวดล้อมของโปรแกรมอ้างอิงได้จาก WG14 N1570 หมวด 5.1 ซึ่งเป็นร่างคณะกรรมการสำหรับ C11 ไม่ใช่เอกสารกำหนดขั้นตอนกดปุ่มของแพลตฟอร์มนี้
1.6.1 การอธิบายที่แสดงว่าเข้าใจ
คำอธิบาย “โปรแกรมพิมพ์สามบรรทัด” บอกเพียงสิ่งที่สังเกต คำอธิบายที่ลึกขึ้นต้องบอกว่าเริ่มทำงานใน main เรียก puts ทีละคำสั่ง แต่ละครั้งแสดงสตริงและขึ้นบรรทัดใหม่ แล้วส่งสถานะสำเร็จกลับเมื่อจบ เป้าหมายไม่ใช่ท่องศัพท์ทุกคำ แต่ติดตามได้ว่าหากเปลี่ยนหนึ่งคำสั่ง สิ่งใดจะเปลี่ยน
ในการทบทวน ให้เพื่อนอ่านรหัสเทียมเรื่องจัดชุดอุปกรณ์โดยไม่บอกคำตอบล่วงหน้า ถ้าเพื่อนถามว่า “เหลือไม่ถึงชุดต้องทำอย่างไร” แสดงว่าคำอธิบายยังไม่ครบ คำถามนี้เป็นข้อมูลเพื่อปรับขั้นตอน ไม่ใช่ข้อพิสูจน์ว่าผู้อ่านไม่เข้าใจ การออกแบบที่ดีช่วยให้คนอีกคนทำตามและได้ผลเดียวกัน
1.7 เวิร์กช็อปขยาย: เปรียบเทียบขั้นตอนและตรวจหลักฐาน
เริ่มจากเขียนวิธีจัดชุดอุปกรณ์สองแบบ แบบแรกแจกทีละชุด แบบที่สองหารและหาเศษ ใช้ข้อมูลในตารางเดิมทำ trace ทั้งสองวิธี แล้วระบุว่าตัวเลขใดเปลี่ยนในแต่ละขั้นและเงื่อนไขใดทำให้จบ ไม่จำเป็นต้องเขียนลูป C ในบทนี้ เพราะกำลังฝึกแบบจำลองการคิดก่อนเรียนไวยากรณ์
ต่อยอดเป็นสถานการณ์จัดโต๊ะให้นักศึกษา 23 คน โต๊ะละ 4 คน สังเกตว่าคำถาม “จัดได้กี่โต๊ะเต็ม” กับ “ต้องใช้กี่โต๊ะให้ทุกคนได้นั่ง” ให้คำตอบต่างกัน คำถามแรกได้ 5 โต๊ะเต็มเหลือ 3 คน ส่วนคำถามหลังต้องมี 6 โต๊ะ แม้ข้อมูลเข้าเหมือนกัน ความหมายผลลัพธ์ต่างกัน อัลกอริทึมจึงต้องต่างตามข้อกำหนด
ทำบันทึกสามช่อง ได้แก่ สิ่งที่โจทย์ระบุ สิ่งที่ตนเองสมมติ และสิ่งที่ต้องถามเพิ่ม จากนั้นแก้รหัสเทียมให้รองรับคำถามเรื่องจำนวนโต๊ะทั้งหมด ตรวจด้วยกรณี 0, 4, 5 และ 23 คน แล้วให้เพื่อนทดลองทำตาม ผู้เรียนควรส่งคำอธิบายเหตุผลควบคู่กับผังงาน เพื่อแสดงว่าลูกศรแต่ละเส้นสะท้อนการตัดสินใจใด
ก่อนเริ่มปฏิบัติการหลัก ให้ตรวจว่ามีข้อกำหนดที่วัดได้ ตารางกรณีทดสอบอย่างน้อยหนึ่งกรณีปกติและสองกรณีขอบเขต และรหัสเทียมที่ทำงานได้โดยไม่ต้องเดาความหมาย การวิเคราะห์นี้จะช่วยให้การเขียนโปรแกรมแรกเป็นการนำแบบไปใช้ และช่วยแยกได้ว่าเมื่อผลไม่ตรง ปัญหาอยู่ที่โจทย์ ขั้นตอน หรือการเขียนภาษา
1.8 ตัวอย่างเปรียบเทียบ: ค่าสูงสุดสามค่ากับการเก็บผู้ชนะชั่วคราว
โจทย์หาค่าสูงสุดของสามค่าเหมาะกับการฝึกแยก “ค่าที่มากที่สุด” ออกจาก “ตัวแปรตัวที่ชนะ” สมมติข้อมูล 8, 3 และ 8 หากต้องการเพียงค่าสูงสุด คำตอบคือ 8 แต่ถ้าถามว่าค่าที่มากที่สุดมาจากตำแหน่งใด ต้องกำหนดว่าจะเลือกตำแหน่งแรก ตำแหน่งสุดท้าย หรือรายงานทุกตำแหน่ง ข้อกำหนดที่ไม่ชัดเรื่องค่าเท่ากันทำให้ผังงานหลายแบบดูถูกได้พร้อมกัน
แนวทางที่ตรวจง่ายคือเริ่มผู้ชนะชั่วคราวจากค่าแรก เปรียบเทียบค่าที่สองกับผู้ชนะแล้วแทนเมื่อมากกว่า จากนั้นเปรียบเทียบค่าที่สาม หลังเปรียบเทียบหนึ่งครั้ง ผู้ชนะเป็นค่าสูงสุดของสองค่าแรก หลังครั้งที่สองเป็นค่าสูงสุดของทั้งสาม การอธิบายเป็นช่วงเช่นนี้ช่วยให้เหตุผลได้ว่าทำไมไม่ต้องเปรียบเทียบทุกคู่
ใบงาน 3: บันทึกผู้ชนะชั่วคราวด้วยตนเอง
ก่อนอ่านตารางไล่ค่าที่แสดงคำตอบ ให้สร้างตารางของตนเองสำหรับข้อมูลทั้งห้าชุดด้านล่าง บันทึกค่าเริ่มต้น ค่าหลังตรวจตัวที่สอง และค่าหลังตรวจตัวที่สาม พร้อมเหตุผลเมื่อเปลี่ยนหรือคงผู้ชนะไว้
| ชุดข้อมูล | ค่าเริ่มต้นที่เลือก | หลังตรวจตัวที่สอง | หลังตรวจตัวที่สาม | เหตุผล |
|---|---|---|---|---|
| 8, 3, 5 | บันทึกเอง | บันทึกเอง | บันทึกเอง | อธิบายทุกการเปลี่ยน |
| 3, 8, 5 | บันทึกเอง | บันทึกเอง | บันทึกเอง | อธิบายทุกการเปลี่ยน |
| 3, 5, 8 | บันทึกเอง | บันทึกเอง | บันทึกเอง | อธิบายทุกการเปลี่ยน |
| -8, -3, -5 | บันทึกเอง | บันทึกเอง | บันทึกเอง | ตรวจเหตุผลของค่าเริ่มต้น |
| 8, 3, 8 | บันทึกเอง | บันทึกเอง | บันทึกเอง | แยกค่าสูงสุดจากตำแหน่ง |
หลังทำแล้วจึงเทียบกับตัวอย่าง และอธิบายว่าชุดใดช่วยพบการเริ่มผู้ชนะที่ศูนย์โดยไม่ดูขอบเขตข้อมูล หากโจทย์ถามตำแหน่งแทนค่า ให้บอกด้วยว่าต้องถามกติกาเรื่องค่าซ้ำเพิ่มอย่างไร
| ข้อมูล | เริ่มผู้ชนะ | หลังเทียบตัวที่สอง | หลังเทียบตัวที่สาม |
|---|---|---|---|
| 8, 3, 5 | 8 | 8 | 8 |
| 3, 8, 5 | 3 | 8 | 8 |
| 3, 5, 8 | 3 | 5 | 8 |
| -8, -3, -5 | -8 | -3 | -3 |
| 8, 3, 8 | 8 | 8 | 8 |
แถวติดลบแสดงว่าการเริ่มผู้ชนะที่ศูนย์ไม่เหมาะหากข้อมูลอนุญาตค่าลบ เพราะศูนย์ไม่ได้อยู่ในข้อมูลแต่กลับมากกว่าทุกค่า การเลือกค่าเริ่มต้นจึงควรอาศัยข้อมูลจริงหรือขอบเขตที่พิสูจน์แล้ว ไม่ใช่ความเคยชิน
ให้แปลงแนวทางเป็นผังงาน โดยมีการกำหนดค่าเริ่ม การตัดสินใจสองจุด และการแสดงผลหนึ่งจุด ใช้ชุดข้อมูลในตารางเดินตามลูกศรทุกเส้นที่เกี่ยวข้อง แล้วเขียนรหัสเทียมอีกแบบที่เปรียบเทียบคู่โดยตรง เปรียบเทียบความอ่านง่ายและโอกาสลืมกรณีค่าเท่ากัน ยังไม่ต้องตัดสินว่าแบบใด “ดีที่สุด” โดยไม่ระบุเกณฑ์
เมื่ออธิบายต่อชั้น ให้ผู้หนึ่งเป็นผู้ถือค่าผู้ชนะ อีกสองคนเป็นข้อมูลที่เข้ามาใหม่ ผู้ถือค่าต้องบอกเหตุผลทุกครั้งที่เปลี่ยนหรือไม่เปลี่ยน หลังจบจึงเชื่อมกิจกรรมกับการกำหนดค่าและเงื่อนไขที่จะเขียนในบทต่อไป กิจกรรมมีเป้าหมายสร้างแบบจำลองสถานะ ไม่ใช่เพียงอ่านข้อความจากเอกสารให้ครบ
1.9 อ่านโค้ดที่ผิดและทำความเข้าใจข้อความวินิจฉัย
ตัวอย่างต่อไปนี้เป็นโค้ดฝึกแยกจากงานที่ต้องส่ง แสดงข้อผิดพลาดที่สัมพันธ์กับเนื้อหาบท พร้อมข้อความวินิจฉัยจริง วิธีอ่าน และฉบับแก้ คำว่า diagnostic ใช้รวมข้อความ error, warning และ note จึงไม่ควรเรียกทุกบรรทัดว่า error หรือถือว่าการไม่มี error แปลว่าโปรแกรมถูกตามโจทย์
ที่มาของ log: ผู้เขียนทดสอบด้วย GCC 11.4.0 บน Ubuntu ผ่าน Linux environment เมื่อ 24 ตุลาคม 2569 ใช้ C11 และตัวเลือกดังนี้ ชื่อไฟล์ เลขบรรทัด คอลัมน์ ถ้อยคำ และคำเตือนที่เปิดใช้อาจต่างจากแพลตฟอร์มการเรียน นักศึกษาไม่จำเป็นต้องเปลี่ยนเครื่องมือหรือการติดตั้งตามชุดทดสอบของผู้เขียน
-std=c11 -O0 -Wall -Wextra -Wpedantic -Wformat=2 -fdiagnostics-color=never -fmessage-length=0ข้อความรูปแบบ bad.c:5:17 อ่านว่าไฟล์ bad.c บรรทัด 5 คอลัมน์ 17 ส่วน ^ และ ~ ช่วยชี้บริเวณที่ตรวจพบ จุดนี้อาจเป็นปลายเหตุจากบรรทัดก่อนหน้า error ทำให้การสร้างโปรแกรมล้มในกรณีนั้น warning เตือนความเสี่ยงแม้คำสั่งสร้างอาจจบสำเร็จ และ note ให้บริบท เช่น declaration เดิม ต้องอ่านคู่กัน (GCC: Diagnostics)
ตัวอย่างที่ผิด 1: ลืมเครื่องหมายปิดคำสั่ง
ประเภท: ข้อผิดพลาดขณะคอมไพล์
คำสั่งเรียก puts ไม่มี semicolon ปิดท้าย บรรทัดถัดไปจึงถูกอ่านในบริบทที่ยังไม่จบคำสั่งเดิม ตัวอย่างนี้แยกข้อผิดพลาดทางไวยากรณ์ออกจากความถูกต้องของอัลกอริทึม แม้ลำดับความคิดถูกต้อง compiler ยังสร้างโปรแกรมไม่ได้
โค้ดที่ผิด — ไม่ใช้แทนฉบับแก้
#include <stdio.h>
int main(void)
{
puts("Prepare equipment")
return 0;
}คำสั่งสร้างและข้อความที่ได้จริง
gcc -std=c11 -O0 -Wall -Wextra -Wpedantic -Wformat=2 -fdiagnostics-color=never -fmessage-length=0 bad.c -o badbad.c: In function 'main':
bad.c:4:30: error: expected ';' before 'return'
4 | puts("Prepare equipment")
| ^
| ;
5 | return 0;
| ~~~~~~สถานะจบของคำสั่งสร้างที่ตัวเก็บผลอ่านได้: 1 คำสั่งล้มและไม่ได้รัน executable ของตัวอย่างนี้ การรันไฟล์เก่าที่อาจค้างจาก build ครั้งก่อนจะไม่ใช่หลักฐานของโค้ดปัจจุบัน
อ่านข้อความว่าแจ้งอะไรและผิดอย่างไร
อ่านข้อความ expected ก่อน แล้วดูตำแหน่ง before ซึ่งชี้ token ที่ compiler พบขณะคาดว่าจะเจอ semicolon จุดที่รายงานอาจเป็น return บรรทัดถัดไป จึงต้องตรวจบรรทัดก่อนหน้าด้วย ไม่เพิ่มเครื่องหมายแบบสุ่มตรงลูกศรเพียงอย่างเดียว
โค้ดที่แก้แล้ว
#include <stdio.h>
int main(void)
{
puts("Prepare equipment");
return 0;
}เหตุผลของการแก้และสิ่งที่ต้องตรวจซ้ำ
เติม semicolon หลังการเรียก puts แล้วคอมไพล์ใหม่ โปรแกรมที่แก้ต้องแสดงข้อความหนึ่งบรรทัดและจบสำเร็จ การอ่าน error แรกก่อนช่วยลดการไล่แก้ข้อความต่อเนื่องที่เกิดจากสาเหตุเดียวกัน
ผลตรวจฉบับแก้จริง: คอมไพล์ด้วยตัวเลือกเดิมและเพิ่ม -Werror เพื่อให้ชุดทดสอบผู้เขียนไม่ยอมรับ warning ไม่มีข้อความวินิจฉัยและคำสั่งสร้างจบด้วยสถานะ 0 จากนั้นรันได้ stdout ดังนี้ และ stderr ว่าง
Prepare equipmentตัวอย่างที่ผิด 2: สะกดชื่อตัวแปรไม่ตรงกับที่ประกาศ
ประเภท: ข้อผิดพลาดขณะคอมไพล์
ประกาศ total แต่เรียก totla ภาษา C แยกตัวสะกดและตัวพิมพ์ของ identifier จึงถือว่าเป็นคนละชื่อ กรณีนี้ยังไม่ได้เข้าสู่ขั้นคำนวณผลรวม ไม่ใช่ปัญหาที่ printf คำนวณผิด
โค้ดที่ผิด — ไม่ใช้แทนฉบับแก้
#include <stdio.h>
int main(void)
{
int total = 3 + 4;
printf("%d\n", totla);
return 0;
}คำสั่งสร้างและข้อความที่ได้จริง
gcc -std=c11 -O0 -Wall -Wextra -Wpedantic -Wformat=2 -fdiagnostics-color=never -fmessage-length=0 bad.c -o badbad.c: In function 'main':
bad.c:5:20: error: 'totla' undeclared (first use in this function); did you mean 'total'?
5 | printf("%d\n", totla);
| ^~~~~
| total
bad.c:5:20: note: each undeclared identifier is reported only once for each function it appears in
bad.c:4:9: warning: unused variable 'total' [-Wunused-variable]
4 | int total = 3 + 4;
| ^~~~~สถานะจบของคำสั่งสร้างที่ตัวเก็บผลอ่านได้: 1 คำสั่งล้มและไม่ได้รัน executable ของตัวอย่างนี้ การรันไฟล์เก่าที่อาจค้างจาก build ครั้งก่อนจะไม่ใช่หลักฐานของโค้ดปัจจุบัน
อ่านข้อความว่าแจ้งอะไรและผิดอย่างไร
undeclared หมายถึงไม่มีการประกาศชื่อนี้ให้ใช้งานในบริบทนั้น first use in this function หมายถึงตำแหน่งใช้ครั้งแรกที่ตรวจพบ ข้อเสนอ did you mean เป็นเพียงคำแนะนำ ต้องเทียบกับเจตนาและ declaration จริง ส่วน unused variable ที่ตามมาเป็นเบาะแสว่า total ถูกประกาศแต่ไม่ถูกใช้
โค้ดที่แก้แล้ว
#include <stdio.h>
int main(void)
{
int total = 3 + 4;
printf("%d\n", total);
return 0;
}เหตุผลของการแก้และสิ่งที่ต้องตรวจซ้ำ
แก้ชื่อที่เรียกให้ตรง total และคอมไพล์ซ้ำ ไม่สร้างตัวแปร totla อีกตัวเพื่อทำให้ error หาย เพราะจะคงการสะกดผิดไว้และอาจนำค่าคนละตัวมาแสดง
ผลตรวจฉบับแก้จริง: คอมไพล์ด้วยตัวเลือกเดิมและเพิ่ม -Werror เพื่อให้ชุดทดสอบผู้เขียนไม่ยอมรับ warning ไม่มีข้อความวินิจฉัยและคำสั่งสร้างจบด้วยสถานะ 0 จากนั้นรันได้ stdout ดังนี้ และ stderr ว่าง
7ลำดับการอ่าน log เมื่อลองโปรแกรมของบทนี้
- ระบุว่าเกิดในขั้น compile, link, run หรือ test และแยกข้อความจากระบบออกจากข้อความที่โปรแกรมพิมพ์เอง
- อ่าน diagnostic แรกกับบริบทบรรทัดก่อนหน้า แล้วใช้ note เพื่อเทียบ declaration หรือชนิดข้อมูล อย่าแก้ทุกข้อความตามลำดับโดยไม่หาสาเหตุร่วม
- แก้ทีละสาเหตุ สร้างโปรแกรมใหม่ และตรวจว่ากำลังรันผล build ใหม่ การเติมวงเล็บ ปิด warning หรือลบ test อาจทำให้ log เงียบโดยยังผิดโจทย์
- ใช้ข้อมูลเดิมที่ทำให้ผิดทดสอบซ้ำ แล้วเพิ่มกรณีขอบเขตที่สัมพันธ์กับบท การรันจบสถานะศูนย์เพียงครั้งเดียวไม่แทนการตรวจข้อกำหนดครบถ้วน
ความหมายตามภาษาอ้างจากร่างมาตรฐาน C11 โดยข้อความ diagnostic เฉพาะถ้อยคำเป็นของเครื่องมือที่ใช้ ไม่ได้กำหนดให้ compiler ทุกตัวพิมพ์เหมือนกัน (WG14 N1570, GCC: Warning Options)
ปฏิบัติการที่ 1 การออกแบบขั้นตอนวิธีและการเขียนโปรแกรมแรก
ปฏิบัติการนี้แบ่งเป็นสองส่วน ส่วนแรกฝึกออกแบบขั้นตอนวิธีด้วยผังงานและรหัสเทียม ส่วนที่สองฝึกเขียน คอมไพล์ และรันโปรแกรมภาษา C พร้อมตรวจมาตรฐานโค้ด ทั้งสองส่วนทำแยกกันได้ แต่ควรทำตามลำดับเพื่อให้เห็นการเชื่อมโยงจากการออกแบบสู่การเขียนโค้ด
ไฟล์ซอร์สโค้ดในปฏิบัติการนี้ให้ตั้งชื่อเป็นภาษาอังกฤษแบบ snake_case และบันทึกไว้ในโฟลเดอร์ของผู้เรียนเอง คำสั่งคอมไพล์ในเอกสารนี้ทดสอบด้วย gcc 13.3.0
Lab A: ออกแบบผังงานและรหัสเทียมหาค่ามากที่สุดของจำนวน 3 จำนวน
สถานการณ์ ต้องการหาค่าที่มากที่สุดของจำนวนเต็ม 3 จำนวนที่รับเข้ามา โดยยังไม่ต้องเขียนเป็นภาษา C เป็นการฝึกออกแบบขั้นตอนวิธีก่อนลงมือเขียนโค้ดจริงในบทถัดไป
เป้าหมาย ฝึก LLO1.1 และ LLO1.2 คือวิเคราะห์ปัญหาและออกแบบขั้นตอนวิธีด้วยผังงานและรหัสเทียมที่สอดคล้องกัน
ขั้นปฏิบัติ
- ระบุข้อมูลเข้าและผลลัพธ์: ข้อมูลเข้าคือจำนวนเต็ม 3 จำนวน ผลลัพธ์คือค่าที่มากที่สุด
- ร่างแนวทางเป็นถ้อยคำ: เปรียบเทียบทีละคู่เพื่อหาค่ามากที่สุด
- เขียนรหัสเทียมตามแนวทาง
- แปลงรหัสเทียมเป็นผังงานโดยใช้สัญลักษณ์มาตรฐาน
- ไล่ตรวจด้วยข้อมูลตัวอย่างอย่างน้อยสองชุด รวมกรณีที่มีค่าซ้ำ
ใบงานตรวจ Lab A ด้วยเพื่อน
ก่อนอ่านรหัสเทียมตัวอย่าง ให้เขียนแนวทางและร่างผังงานของคุณเอง แล้วให้เพื่อนเดินตามโดยไม่ช่วยบอกขั้นตอนระหว่างทาง ถ้าเพื่อนต้องถามความหมายเพิ่ม ให้จดตำแหน่งนั้นไว้และปรับขั้นตอนให้ชัด ไม่ถือว่าความกำกวมเป็นความผิดของผู้อ่านโดยอัตโนมัติ
| สิ่งที่บันทึก | หลักฐานจากการทดลองของคุณ |
|---|---|
| ข้อมูลที่ใช้และคำตอบที่คาด | ระบุค่าทั้งสามก่อนเริ่มไล่ |
| ผลจากการเดินตามผังงาน | บันทึกผู้ชนะหลังแต่ละการเปรียบเทียบ |
| จุดที่เพื่อนต้องเดาหรือถามเพิ่ม | ระบุขั้นตอนหรือลูกศรที่ยังไม่ชัด |
| สิ่งที่แก้พร้อมเหตุผล | เชื่อมกับกรณีที่พบปัญหา |
| ผลหลังตรวจซ้ำ | ใช้ข้อมูลเดิมตรวจว่าปัญหาถูกแก้แล้ว |
ตรวจทั้งกรณีค่าสูงสุดอยู่หน้า กลาง และท้าย รวมถึงค่าลบทั้งหมดและค่าเท่ากัน การใช้ข้อมูลหลายแบบมีเป้าหมายให้ตรวจแนวคิดคนละจุด ไม่ใช่เปลี่ยนตัวเลขเพื่อให้มีรายการทดลองมากขึ้นอย่างเดียว
ตัวอย่างรหัสเทียมที่เป็นไปได้
เริ่ม
รับค่า a, b, c
กำหนด max = a
ถ้า b มากกว่า max
max = b
ถ้า c มากกว่า max
max = c
แสดง max
จบตัดสินใจเอง A.1 เลือกแนวทางเปรียบเทียบด้วยตนเองระหว่างการใช้ตัวแปร max เก็บค่ามากสุด กับการซ้อนเงื่อนไขเปรียบเทียบทีละคู่ แล้วให้เหตุผลประกอบว่าเหตุใดจึงเลือกแนวทางนั้น
ผลลัพธ์ที่คาดหวัง A.1 ผังงานที่ทุกเส้นทางการตัดสินใจไปถึงจุดจบ และรหัสเทียมที่ให้ผลตรงกับผังงาน ครอบคลุมกรณีที่มีค่าซ้ำกัน
จุดตรวจ A ผังงานมีจุดเริ่มและจุดจบครบ มีสัญลักษณ์ตัดสินใจอย่างน้อยหนึ่งจุด ทุกเส้นทางไปถึงจุดจบ รหัสเทียมสอดคล้องกับผังงาน และไล่ตรวจด้วยข้อมูลตัวอย่างแล้วได้ผลถูกต้อง
ปัญหาที่พบบ่อย
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
| ผลลัพธ์ผิดเมื่อมีค่าซ้ำ | เงื่อนไขใช้ มากกว่าหรือเท่ากับ ไม่สม่ำเสมอ | ทดสอบด้วยชุดค่าที่ซ้ำกันและปรับเงื่อนไขให้ครอบคลุม |
| ผังงานมีเส้นทางไม่ถึงจุดจบ | ลืมเชื่อมลูกศรบางกรณี | ไล่ตรวจทุกทางออกของสัญลักษณ์ตัดสินใจ |
| รหัสเทียมไม่ตรงกับผังงาน | แก้ด้านเดียวแล้วไม่ปรับอีกด้าน | แก้ทั้งสองแบบพร้อมกันและเทียบขั้นต่อขั้น |
เปิดหลังผู้เรียนออกแบบด้วยตนเองแล้ว
Lab B: เขียน คอมไพล์ และรันโปรแกรมภาษา C โปรแกรมแรก
สถานการณ์ สร้างโปรแกรมภาษา C ที่แสดงข้อความต้อนรับและผลการคำนวณอย่างง่ายออกทางจอภาพ เพื่อฝึกวงจรเขียน–คอมไพล์–รัน และตั้งมาตรฐานโค้ดตั้งแต่โปรแกรมแรก
เป้าหมาย ฝึก LLO1.3 และ LLO1.4 คือเขียนโปรแกรมที่คอมไพล์และรันได้ถูกต้อง และเป็นไปตามมาตรฐานการเขียนโค้ดเบื้องต้น
ขั้นปฏิบัติ
- สร้างไฟล์ชื่อ
welcome.cด้วยโปรแกรมแก้ไขข้อความหรือ IDE - พิมพ์ซอร์สโค้ดต่อไปนี้ โดยจัดย่อหน้า 4 ช่องว่างและใส่คอมเมนต์ส่วนหัว
/* welcome.c : โปรแกรมแรก แสดงข้อความต้อนรับและผลการคำนวณอย่างง่าย */
#include <stdio.h>
int main(void) {
printf("ยินดีต้อนรับสู่รายวิชา 10306103\n");
printf("ผลรวมของ 3 และ 4 คือ %d\n", 3 + 4);
return 0;
}ใบงานตรวจ Lab B: จากคำทำนายสู่ผลจริง
เมื่ออ่านข้อความในโปรแกรมแล้ว ให้เขียนผลที่คาดให้ครบทุกบรรทัดก่อนกดรัน จากนั้นบันทึกผลจริงโดยรักษาคำทำนายเดิมไว้ ถ้าผลต่างกันให้ระบุว่าต่างที่ข้อความ ลำดับบรรทัด ผลคำนวณ หรือฉบับซอร์สที่กำลังรัน
| รอบทำงาน | สิ่งที่ต้องบันทึก |
|---|---|
| ก่อนรันโปรแกรมตัวอย่าง | ผลที่คาดและคำสั่งที่ทำให้เกิดแต่ละบรรทัด |
| หลังรันโปรแกรมตัวอย่าง | ผลจริงและจุดที่ต่างจากคำทำนาย |
| หลังออกแบบข้อความของตนเอง | ชื่อไฟล์ ข้อความใหม่ และนิพจน์ที่เลือก |
| หลังแก้และรันฉบับใหม่ | ผลจริงที่ใช้ตรวจว่าการแก้มีผลแล้ว |
| ก่อนส่งตามประกาศเดิม | ผลการตรวจไวยากรณ์ ผลลัพธ์ และมาตรฐานโค้ด |
ใช้แพลตฟอร์มภาษา C ที่รายวิชากำหนด ไม่ต้องติดตั้งเครื่องมือหรือสร้างบัญชีเพิ่มเพื่อทำใบงานนี้ เมื่อแก้ซอร์สแล้วให้แปลและรันฉบับใหม่ตามวิธีของแพลตฟอร์ม หากผลยังเหมือนเดิม ให้ตรวจว่ารันไฟล์หรือฉบับที่เพิ่งแก้จริงหรือไม่
- คอมไพล์และรันด้วยคำสั่ง
gcc -std=c11 -Wall welcome.c -o welcome
./welcome- ตรวจผลลัพธ์ที่ปรากฏ แล้วทบทวนว่าโค้ดเป็นไปตามมาตรฐานโค้ดหรือไม่
ผลการรันจริง (ทดสอบแล้วด้วย gcc 13.3.0)
ยินดีต้อนรับสู่รายวิชา 10306103
ผลรวมของ 3 และ 4 คือ 7ในบรรทัด printf("ผลรวมของ 3 และ 4 คือ %d\n", 3 + 4); ส่วน %d เป็นตัวแทนตำแหน่งสำหรับค่าจำนวนเต็ม ซึ่งจะแทนที่ด้วยผลของนิพจน์ 3 + 4 เรื่องการจัดรูปแบบการแสดงผลจะอธิบายละเอียดในบทที่ 3
ตัดสินใจเอง B.1 ออกแบบข้อความต้อนรับของตนเองและเลือกนิพจน์คำนวณอย่างง่ายหนึ่งนิพจน์ (เช่น ผลคูณหรือผลต่าง) เพื่อแสดงผลเพิ่มอีกหนึ่งบรรทัด พร้อมตั้งชื่อไฟล์ให้สื่อความหมาย
ผลลัพธ์ที่คาดหวัง B.1 โปรแกรมคอมไพล์ผ่านโดยไม่มีข้อผิดพลาดและไม่มีการแจ้งเตือน และแสดงข้อความตามที่ออกแบบ รวมถึงผลการคำนวณที่ถูกต้อง
จุดตรวจ B คอมไพล์ผ่านไม่มีข้อผิดพลาดและไม่มีการแจ้งเตือน ผลลัพธ์ตรงกับที่ออกแบบ และโค้ดมีการจัดย่อหน้า 4 ช่องว่าง ตั้งชื่อไฟล์สื่อความหมาย และมีคอมเมนต์ส่วนหัว
ปัญหาที่พบบ่อย
| อาการ | สาเหตุ | วิธีแก้ |
|---|---|---|
คอมไพล์แจ้ง error เกี่ยวกับ printf | ลืมบรรทัด #include <stdio.h> | เพิ่มการนำเข้าส่วนหัวมาตรฐานที่ต้นไฟล์ |
| คอมไพล์แจ้ง error ขาดเครื่องหมาย | ลืมเครื่องหมาย ; ท้ายคำสั่ง | เติม ; ให้ครบทุกคำสั่ง |
| รันแล้วไม่พบไฟล์ | สับสนระหว่างชื่อซอร์สกับชื่อไฟล์ปฏิบัติการ | รันไฟล์ที่ระบุหลัง -o เช่น ./welcome |
| แก้โค้ดแล้วผลไม่เปลี่ยน | ยังไม่คอมไพล์ใหม่ | คอมไพล์ใหม่ทุกครั้งหลังแก้ซอร์สโค้ด |
เปิดหลังผู้เรียนส่งงานแล้ว
เก็บกวาด
เมื่อจบปฏิบัติการ ให้ลบไฟล์ปฏิบัติการที่สร้างจากการคอมไพล์ (เช่น welcome) และเก็บเฉพาะไฟล์ซอร์สโค้ด .c ไว้ และส่งไฟล์ซอร์สโค้ด .c พร้อมบันทึกผลการรันตามที่กำหนด
ตรวจความเข้าใจก่อนเริ่มบทที่ 2
ใช้คำถามต่อไปนี้ทบทวนด้วยภาษาของตนเองหลังทำปฏิบัติการ ข้อเหล่านี้เป็นจุดตรวจระหว่างเรียน ไม่เพิ่มเงื่อนไขผ่านหรือคะแนนจากแผนเดิม
- ยกหนึ่งตัวอย่างจากงานจัดชุดหรือจัดโต๊ะที่แสดงว่าข้อกำหนดกับอัลกอริทึมทำหน้าที่ต่างกัน
- กรณีขอบเขตใดช่วยพบข้อผิดพลาดในงานของคุณ และถ้าไม่ทดลองกรณีนั้นจะพลาดอะไร
- เหตุใดการแปลผ่านจึงยังต้องตรวจผลกับโจทย์ ยกกรณีสลับคำสั่งแสดงข้อความประกอบ
- เรื่องใดที่คุณยังอยากทบทวนก่อนเริ่มตัวแปรและชนิดข้อมูลในบทที่ 2
บันทึกข้อมูลที่ใช้ ผลที่คาด ผลจริง และเหตุผลการแก้หนึ่งจุดไว้ด้วยกัน จะช่วยแยกได้ว่าความเข้าใจที่เปลี่ยนเกิดจากข้อกำหนด ขั้นตอนวิธี หรือการเขียนภาษา C เมื่อนำไปเรียนบทที่ 2 ตัวแปร ชนิดข้อมูล และนิพจน์ ให้เริ่มจากข้อตกลงข้อมูลที่ชัดแล้วค่อยเลือกตัวแปรและนิพจน์
สรุป
บทนี้ปูพื้นฐานวิธีคิดในการแก้ปัญหาด้วยคอมพิวเตอร์ เริ่มจากความหมายของปัญหาและขั้นตอนวิธีพร้อมคุณสมบัติ 5 ประการและที่มาของคำว่า algorithm การคิดเชิงคำนวณสี่องค์ประกอบ การออกแบบขั้นตอนวิธีด้วยผังงานและรหัสเทียมที่สอดคล้องกันพร้อมการไล่ตรวจด้วยข้อมูลตัวอย่าง กระบวนการพัฒนาโปรแกรม 5 ขั้น ประวัติและมาตรฐานภาษา C และกระบวนการแปลสี่ขั้นจากซอร์สโค้ดเป็นไฟล์ปฏิบัติการ จากนั้นฝึกเขียน คอมไพล์ และรันโปรแกรมภาษา C โปรแกรมแรก พร้อมตั้งมาตรฐานการเขียนโค้ดเบื้องต้นที่จะใช้ต่อเนื่องตลอดรายวิชา ทักษะการวิเคราะห์ปัญหาและการออกแบบขั้นตอนวิธีในบทนี้เป็นรากฐานของการเขียนโปรแกรมที่มีคุณภาพในบทถัดไป
สิ่งที่ส่งต่อไปยังบทถัดไป
| สิ่งที่ส่งต่อ | ค่า/รูปแบบ | ใช้ในบท |
|---|---|---|
| ภาษาและมาตรฐานที่ใช้ | ภาษา C รุ่น C11 | บท 2 เป็นต้นไป |
| คำสั่งคอมไพล์มาตรฐาน | gcc -std=c11 -Wall ไฟล์.c -o ชื่อ | ทุกปฏิบัติการ |
| โครงร่างโปรแกรม C ขั้นต่ำ | #include + int main(void) + return 0; | บท 2 เป็นต้นไป |
| มาตรฐานโค้ดเบื้องต้น | ย่อหน้า 4 ช่องว่าง, ชื่อ snake_case, คอมเมนต์ส่วนหัว | ทุกบท (จุดตรวจ CLO5) |
สรุปคำสั่ง
| คำสั่ง | หน้าที่ |
|---|---|
gcc -std=c11 -Wall welcome.c -o welcome | คอมไพล์ซอร์สโค้ด welcome.c เป็นไฟล์ปฏิบัติการ welcome พร้อมเปิดการแจ้งเตือน |
./welcome | รันไฟล์ปฏิบัติการที่คอมไพล์แล้ว |
gcc -E ไฟล์.c -o ไฟล์.i | สั่งเฉพาะขั้นประมวลผลก่อนแปล (เพื่อศึกษากระบวนการแปล) |
gcc -S ไฟล์.i -o ไฟล์.s | สั่งเฉพาะขั้นแปลเป็นภาษาแอสเซมบลี |
gcc -c ไฟล์.s -o ไฟล์.o | สั่งเฉพาะขั้นแปลงเป็นไฟล์ออบเจกต์ |
แบบฝึกหัดท้ายบท
ตอนที่ 1 ฝึกทบทวน (15 ข้อ ตรวจคำตอบให้ทันที)
ตอนที่ 2 แบบฝึกหัดเขียนตอบ (5 ข้อ)
กลุ่ม ก (เข้าใจ)
- ก1 (LLO1.1) จงอธิบายความแตกต่างระหว่างปัญหาและขั้นตอนวิธี พร้อมยกตัวอย่างขั้นตอนวิธีในชีวิตประจำวันหนึ่งตัวอย่างและระบุคุณสมบัติที่สอดคล้องครบทั้งห้าข้อ
- ก2 (LLO1.1) จงเรียงลำดับขั้นของกระบวนการพัฒนาโปรแกรม 5 ขั้น และอธิบายสั้น ๆ ว่าแต่ละขั้นทำอะไร
กลุ่ม ข (ประยุกต์)
- ข1 (LLO1.2) จงออกแบบผังงานและรหัสเทียมของการคำนวณพื้นที่สามเหลี่ยมจากฐานและสูงที่รับเข้ามา แล้วไล่ตรวจด้วยข้อมูลตัวอย่างหนึ่งชุด
- ข2 (LLO1.3) จงเขียนโปรแกรมภาษา C ที่แสดงชื่อและรหัสนักศึกษาออกทางจอภาพคนละบรรทัด แล้วคอมไพล์และรันให้ได้ผลจริง
กลุ่ม ค (วิเคราะห์)
- ค1 (LLO1.4) จากโค้ดที่ตั้งชื่อตัวแปรว่า
a,b,xและไม่มีคอมเมนต์ จงวิเคราะห์ว่าโค้ดนั้นด้อยด้านคุณภาพอย่างไร และเสนอการปรับปรุงให้เป็นไปตามมาตรฐานโค้ดเบื้องต้น
การศึกษาค้นคว้าเพิ่มเติม
- ศึกษาคุณสมบัติของขั้นตอนวิธีเพิ่มเติมจาก Knuth (1997) บทว่าด้วยนิยามของอัลกอริทึม แล้วสรุปคุณสมบัติด้วยถ้อยคำของตนเอง
- ศึกษาแนวคิดการคิดเชิงคำนวณจาก Wing (2006) แล้วยกตัวอย่างการนำองค์ประกอบสี่ส่วนไปใช้กับปัญหาในชีวิตประจำวันหนึ่งเรื่อง
- ศึกษาโครงสร้างโปรแกรมภาษา C และฟังก์ชัน
mainจาก Kernighan และ Ritchie (1988) บทที่ 1 แล้วทดลองปรับโปรแกรมตัวอย่างให้แสดงผลหลายบรรทัด - ทบทวนภาพรวมรุ่นมาตรฐานภาษา C ตาม ISO/IEC 9899 เพื่อเข้าใจว่าเหตุใดจึงต้องระบุ
-std=c11ขณะคอมไพล์
เอกสารอ้างอิง
International Organization for Standardization. (1985). ISO 5807:1985 — Information processing — Documentation symbols and conventions for data, program and system flowcharts, program network charts and system resources charts. ISO.
International Organization for Standardization. (2011). ISO/IEC 9899:2011 — Information technology — Programming languages — C. ISO.
Kernighan, B. W., & Ritchie, D. M. (1988). The C programming language (2nd ed.). Prentice Hall.
Knuth, D. E. (1997). The art of computer programming: Vol. 1. Fundamental algorithms (3rd ed.). Addison-Wesley.
Wing, J. M. (2006). Computational thinking. Communications of the ACM, 49(3), 33–35.
ตำราหลักภาษาไทยของรายวิชา. (ผู้สอนเติมรายละเอียดบรรณานุกรม — เพิ่มตามมติผู้สอน 21 ต.ค. 2569).
แหล่งอ้างอิงออนไลน์ประกอบ (ใช้ยืนยันข้อเท็จจริงในเซสชันจัดทำ): Wikipedia — "Algorithm", "Computational thinking", "Flowchart"; cppreference — "C language history"; GeeksforGeeks — "Compiling a C program: Behind the Scenes", "Software Development Life Cycle (SDLC)"
แหล่งปฐมภูมิที่ตรวจประกอบการปรับปรุง 23 ตุลาคม 2569
ใช้เอกสารข้างต้นตรวจหลักการก่อนเรียบเรียงส่วนขยายและสร้างข้อมูลสมมติ ตัวอย่างใหม่ที่เป็นโปรแกรม C ครบไฟล์ตรวจด้วย GCC 12.2.0 (Debian Linux) และ GCC 6.3.0 (MinGW-w64), C11 และคำเตือน -Wall -Wextra -Wpedantic เมื่อ 23 ตุลาคม 2569 แยกจากผลทดสอบ GCC 13.3.0 ของตัวอย่างเดิม ค่ารูปแบบและผลคำนวณตรวจจากการรัน ส่วนเวลา CPU ขึ้นกับสภาพแวดล้อม ไม่ใช่ผลตายตัว