วันอังคารที่ 5 กุมภาพันธ์ พ.ศ. 2556

การเขียนโปรแกรมภาษา C Introduction to C Programming


                              การเขียนโปรแกรมภาษา C Introduction to C Programming


                   ดร. จันทร์จิรา สินทนะโยธิน, วิศรุต พลสิทธิ สำนักงานพัฒนาวิทยาศาสตร์และเทคโนโลยีแห่งชาติ (สวทช)ฝึกฝนและพัฒนาการเขียนโปรแกรมภาษา C Introduction to C Programming การพัฒนาโปรแกรมคอมพิวเตอร์ บางคนก็ว่ายาก บางคนก็ว่าเป็นเรื่องสนุก หลายคนบอกว่า ขอเป็นแค่ผู้ใช้สนุกที่สุด แต่จะมีซักกี่คนที่จะมีใจรักที่จะก้าวไปบนถนนแห่งการพัฒนาฝีมือและฝึกฝนการเขียนโปรแกรมด้วยตัวเอง เพื่อให้มีผู้ที่สนใจนำไปใช้งาน และเพิ่มประสิทธิ์ภาพในการทำงาน และ ความสะดวกสบายๆ ต่างๆมากขึ้น ว่าไปแล้วนักโปรแกรมเมอร์เหล่านี้ ก็ไม่แตกต่างจากผู้ที่ปิดทองหลังพระมากนัก เพราะหลายๆ โปรแกรมที่มีให้ใช้งานกันในปัจจุบัน จะมีใครทราบบ้างไหมว่า ผู้เขียนโปรแกรมเหล่านั้นมีใครกันบ้าง ดังนั้น ผู้ที่คิดจะก้าวมาเป็นนักพัฒนาโปรแกรมมืออาชีพ คงต้องอาศัยใจรักที่จะอยากจะพัฒนา และฝึกฝนฝืมือในการเป็นโปรแกมเมอร์มืออาชีพมาเป็นอันดับหนึ่ง สำหรับบทความนี้จะเริ่มต้นด้วยการสอนให้เข้าใจในหลักการพื้นฐานของการการพัฒนาโปรแกรมในภาษา C ความรู้และความเข้าใจที่จำเป็นต่อการเป็นโปรแกรมเมอร์มืออาชีพในอนาคต เราลองเริ่มมาเรียนรู้กันอย่างคร่าวๆ กันเลยล่ะกัน โดยผู้เขียนจะอธิบายเป็นตอนๆ ทั้งหมด 8 ตอนด้วยกันได้แก่ 1. พื้นฐานโปรแกรมภาษา C (Introduction to C Programming) 2. การเขียนโปรแกรมทางเลือก (Selection Structures) 3. การเขียนโปรแกรมแบบ วนซ้ำ (Repetition & Loop) 4. ฟังก์ชัน และการเขียนโปรแกรมแยกเป็นโมดูล (Functions & Modular Programming) 5. ตารางอาเรย์ (Arrays) 6. ตัวแปรพอยเตอร์ (Pointers) 7. ตัวแปรสตริง (String) 8. โครงสร้างสตักเจอร์ (Structure) 1. พื้นฐานโปรแกรมภาษา C (Introduction to C Programming) ก่อนอื่นของแนะนำพื้นฐานเกี่ยวกับคอมพิวเตอร์กันซักนิด ก่อนที่จะเริ่มเรียนรู้ภาษา C กัน หน่วยสำคัญที่สุดของคอมพิวเตอร์ก็คือ หน่วยประมวลผลหรือที่เรียกกันว่า CPU โดยปกติ CPU จะมีภาษาของตัวเองที่เรียกว่า ภาษาเครื่อง (Machine Language) ซึ่งจะเป็นภาษาที่ประกอบไปด้วยเลขฐานสองมากมาย ดังนั้นการที่จะเขียนโปรแกรมควบคุมการทำงานของคอมพิวเตอร์ โดยใช้ภาษาเครื่องโดยตรงนั้นจึงทำได้ยาก จึงได้มีการพัฒนาตัวแปรภาษาเครื่องที่เรียกว่า โปรแกรมภาษาระดับสูงขึ้นมา หรือที่เรียกว่า High Level Languages โดยภาษาในระดับสูงเหล่านี้ จะมีลักษณะรูปแบบการเขียน (Syntax) ที่ทำให้เข้าใจได้ง่ายต่อการสื่อสารกับผู้พัฒนา และถูกออกแบบมาให้ง่ายต่อการใช้งาน และจะเปลี่ยนคำสั่งจากผู้ใช้งาน ไปเป็นเป็นภาษาเครื่อง เพื่อที่จะควบคุมการทำงานของคอมพิวเตอร์ต่อไป ตัวอย่างของโปรแกรมภาษาระดับสูง ได้แก่ COBOL ใช้กันมากสำหรับโปรแกรมทางด้านธุรกิจ, Fortran ใช้กันมากสำหรับการพัฒนาโปรแกรมด้านวิทยาศาสตร์และวิศวกรรมศาสตร์ เพราะง่ายต่อการคำนวณ, Pascal มีใช้กันทั่วไป แต่เน้นสำหรับการพัฒนาเครื่องมือสำหรับการเรียนการสอน, C & C++ ใช้ทั่วไป ปัจจุบันมีผู้เลือกที่จะใช้กันอย่างแพร่หลาย, PROLOG เน้นหนักไปทางด้านงานประเภท AI และ JAVA ใช้ได้ทั่วไป ปัจจุบันเริ่มมีผู้หันมาสนใจกันมากและเพิ่มขึ้นอย่างรวดเร็ว คราวนี้เราลองมาเตรียมตัวกันซักนิก ก่อนที่จะลงมือพัฒนาโปรแกรมคอมพิวเตอร์ ขั้นแรก เราต้องศึกษารูปแบบความต้องการของโปรแกรมที่จะพัฒนา จากนั้นก็วิเคราะห์ถึงปัญหาตลอดจนวิธีการแก้ปัญหา จากนั้นจึงนำเอาความคิดในการแก้ปัญหาอย่างเป็นขั้นตอน ไปเขียนในรูปแบบของโปรแกรมภาษาในระดับสูง ซึ่งจะอยู่ในรูปแบบของ Source Program หรือ Source Code จากนั้นเราก็จะใช้ Complier ของภาษาที่เราเลือก มาทำการ Compile Source code หรือกล่าวง่ายๆ คือแปลง Source code ของเราให้เป็นภาษาเครื่องนั่นเอง ซึ่งในขั้นตอนนี้ ผลที่ได้ เราจะเรียกว่า Object code จากนั้น Complier ก็จะทำการ Link หรือเชื่อม Object code เข้ากับฟังก์ชันการทำงานใน Libraries ต่างๆ ที่จำเป็นต่อการใช้งาน แล้วนำไปไว้ในหน่วยความจำ แล้วเราก็จะสามารถ Run เพื่อดูผลของการทำงานโปรแกรมได้ หากโปรแกรมมีข้อผิดพลาด เราก็จะทำการแก้ หรือที่เรียกกันในภาษาคอมพิวเตอร์ว่า การ Debug นั่นเอง ภาษา C เป็นโปรแกรมภาษาระดับสูง ถูกพัฒนาขึ้นในปี 1972 ที่ AT&T Bell Lab เราสามารถใช้ภาษา C มาเขียนเป็นคำสั่งต่างๆ ที่คอมพิวเตอร์สามารถเข้าใจได้ และกลุ่มของคำสั่งเหล่านี้ เราก็เรียกกันว่า อัลกอริธึม ได้มีผู้ให้คำจำกัดความของคำว่า อัลกอริธึม ว่าเป็น “A precise description of a step-by-step process that is guaranteed to terminate after a finite number of steps with a correct answer for every particular instance of an algorithmic problem that may occur.” สำหรับ Compiler ภาษา C ที่มีในปัจจุบัน มี 2 ค่ายใหญ่ๆ ที่มีผู้คนสนใจใช้กันมากได้แก่ Microsoft และ Borland การใช้งาน Compiler ทั้งสองตัวนี้ สามารถเรียนรู้ได้ไม่ยากนัก เราจึงจะมาเริ่มต้นที่การเขียนโปรแกรมในภาษา C กันเลย เราลองมาเริ่มจากตัวอย่างการเขียน ภาษา C แบบ ง่ายๆ กันก่อนกับโปรแกรม Hello World #include main() { printf("Hello World  !! "); } บรรทัดแรก #include เป็นการบอกว่าให้ทำการรวม Header file ที่ชื่อว่า stdio.h (.h = header) ซึ่งเป็น header ที่เกี่ยวข้องกับการรับและให้ข้อมูล (Standard Input Output) นอกจาก stdio.h แล้ว ก็ยังมี Header อื่นๆ ที่ผู้พัฒนาสามารถที่จะเรียกใช้งาน Function ที่จำเป็นจาก Header นั้นๆ ได้ อาทิเช่น
5519
รู้จัก Header File กันไปล่ะ คราวนี้ เราลองมาดูบรรทัดถัดไปกัน ก็คือ ฟังก์ชัน main() จะเป็นจุดเริ่มต้นของโปรแกรม และโปรแกรมทุกโปรแกรมในภาษา C จะต้องมี Function main() นี้ โดยส่วนมาก เราจะใช้ Function main() ในการกำหนดค่าเริ่มต้นต่างๆ ของโปรแกรม จากนั้นจึงเข้าสู่ Function ต่างๆ ที่ผู้พัฒนา ได้กำหนดขึ้นไว้ บรรทัดถัดมาจะเป็นเครื่องหมาย { ซึ่งเป็นเครื่องหมายบ่งบอกขอบเขตของ Function โดยขอบเขตของฟังก์ชัน จะเปิดและปิดโดยใช้เครื่องหมายเปิด { และเครื่องหมายปิด } ตามลำดับ ภายใน Function main() จะมีคำสั่ง (Statement) printf("Hello World  !! "); ซึ่ง printf เป็น Function ในภาษา C ทำหน้าที่ให้โปรแกรม ทำการแสดงผลออกทางหน้าจอว่า Hello World  !! และทุกครั้ง ผู้พัฒนาจะต้องทำการจบคำสั่งหรือ Statement ด้วยเครื่องหมาย semi-colon ; ดังนั้นรูปแบบของการเขียนโปรแกรม จึงเขียนออกมาในรูปแบบดังนี้ // ข้อความที่อยู่ข้างหลังเครื่องหมาย // จะเป็นคำอธิบายโปรแกรม #include void main() { constant declarations; // การกำหนดค่าคงที่ต่างๆ variable declarations; // การกำหนดตัวแปรต่างๆ executable statements; // คำสั่งการทำงานของโปรแกรม } การอ่านข้อมูลและการแสดงผล (Input & Output) รูปแบบการใช้งานฟังก์ชัน printf จะทำการพิมพ์ในรูปแบบที่ เริ่มต้นด้วย Format ที่ต้องการจะพิมพ์ และตามด้วยตัวแปรที่ต้องการพิมพ์ ดังนี้ printf( const char *format [, argument]... ); สำหรับการนำข้อมูลเข้าก็เช่นกัน จะใช้ฟังก์ชัน scanf ซึ่งจะเป็นฟังก์ชันสำหรับอ่านข้อมูลจากคีย์บอร์ด และจะนำข้อมูลที่ User ทำการพิมพ์ไปเก็บไว้ใน argument โดยแต่ละ argument จะต้องเป็นตัวแปรที่เรียกว่า pointer (รายละเอียดจะได้กล่าวต่อไป) และมีชนิดที่ตัวแปรที่สัมพันธ์กับที่ได้กำหนดไว้ใน Format รูปแบบการใช้งานของฟังก์ชัน scanf สามารถเขียนได้ดังนี้ scanf( const char *format [,argument]... );

หน้าที่ 2 - ตัวแปร (Variables)
ตัวแปร (Variables) ตัวแปรจะเป็นชื่อที่ใช้ในการบอกจำนวนหรือปริมาณ ซึ่งสามารถที่จะทำการเปลี่ยนแปลงจำนวนได้ด้วยโปรแกรมคอมพิวเตอร์ การตั้งชื่อตัวแปร จะต้องตั้งชื่อให้แตกต่างไปจากชื่อของตัวแปรอื่นๆ ยกตัวอย่างชื่อของตัวแปร ได้แก่ x, y, peter, num_of_points และ streetnum เป็นต้น โดยปกติการเขียนโปรแกรมที่ดี ควรจะตั้งชื่อตัวแปรให้สอดคล้องกับการทำงานหรือหน้าที่ของตัวแปรนั้นๆ เพราะเมื่อถึงเวลาต้องมาทำการปรับปรุงแก้ไขโปรแกรม จะสามารถทำได้โดยไม่ยากนัก ในภาษา C หรือ C++ ได้มีกฏในการตั้งชื่อตัวแปรที่สามารถใช้งานได้ดังนี้ - ชื่อตัวแปรจะต้องขึ้นต้นด้วยตัวอักษร - ชื่อตัวแปรจะประกอบไปด้วย ตัวอักษร ตัวแลข และ _ ได้เท่านั้น - ชื่อตัวแปรจะต้องไม่ใช่ชื่อ reserved word (ชื่อที่มีการจองไว้แล้ว) ตัวอย่างของชื่อตัวแปรที่สามารถนำมาใช้ตั้งชื่อได้ ได้แก่ length, days_in_year, DataSet1, Profit95, Pressure, first_one และตัวอย่างของชื่อ ที่ไม่สามารถนำมาใช้เป็นชื่อตัวแปรได้ ยกตัวอย่างเช่น day-in-year, 1data, int, first.val เป็นต้น reserved word (ชื่อที่มีการจองไว้แล้ว) Reserved words หรือตัวแปรที่ได้จองไว้แล้วนั้น จะประกอบไปด้วยตัวอักษรตัวเล็กทั้งหมด และจะมีความสำคัญสำหรับภาษา C++ และจะไม่นำมาใช้ด้วยวัตถุประสงค์อื่นๆ ตัวอย่างของ Reserved words ได้แก่ and, bool, break, case, catch, char, class, continue, default, delete, do, double, if , else, enum, export, extern เป็นต้น นอกจากนี้ในภาษา C หรือ C++ ชื่อตัวแปร ที่ประกอบไปด้วยอักษรเล็ก หรือใหญ่ ก็มีความแตกต่างกัน หรือที่เรียกว่า Case sensitive ยกตัวอย่างเช่น ‘X’ และ ‘x’ เป็นตัวแปรต่างกัน ‘peter’ และ ‘Peter’ เป็นตัวแปรต่างกัน ‘bookno1’ และ ‘bookNo1’ เป็นตัวแปรต่างกัน ‘XTREME’ และ ‘xtreme’ เป็นตัวแปรต่างกัน ‘X1’ และ ‘x1’ เป็นตัวแปรต่างกัน ‘int’ และ ‘Int’ เป็นตัวแปรต่างกัน การกำหนดชนิดของตัวแปร (Declaration of Variables) ในภาษา C หรือ C++ (และโปรแกรมในภาษาอื่นๆ) ตัวแปรทุกตัวที่จะมีการเรียกใช้ในโปรแกรมจำเป็นต้องมีการกำหนดชนิดของตัวแปรนั้นๆ ก่อนที่จะทำการเรียกใช้ตัวแปร การกำหนดชนิดของตัวแปรมีวัตถุประสงค์หลัก 2 ประการได้แก่ - เป็นการบอกชนิด และตั้งชื่อตัวแปรที่จะเรียกใช้ ชนิดของตัวแปรจะทำให้คอมไพเลอร์สามารถแปลคำสั่งได้อย่างถูกต้อง (ยกตัวอย่างเช่น ใน CPU คำสั่งที่ใช้ในการบวกตัวเลขจำนวนเต็ม 2 จำนวน ย่อมแตกต่างจากคำสั่งที่จะบวกจำนวนจริง 2 จำนวนเข้าด้วยกัน) - ชนิดของตัวแปร ยังเป็นบ่งบอกคอมไพเลอร์ให้ทราบว่าจะต้องจัดเตรียมเนื้อที่ให้กับตัวแปรตัวนั้นมากน้อยเท่าใด และจะจัดวางตัวแปรนั้นไว้แอดเดรส (Address) ไหนที่สามารถเรียกมาใช้ใน code ได้ สำหรับในบทความนี้จะพิจารณาชนิดตัวแปร 4 ชนิดที่ใช้กันมากได้แก่ int, float, bool และ char int ชนิดตัวแปรที่สามารถแทนค่าจำนวนเต็มได้ทั้งบวกและลบ โดยปกติสำหรับคอมพิวเตอร์ทั่วไป คอมไพเลอร์ จะจองเนื้อที่ 2 ไบต์ สำหรับตัวแปรชนิด int จึงทำให้ค่าของตัวแปรมีค่าตั้งแต่ -32768 ถึง +32768 ตัวอย่างของค่า int ได้แก่ 123 -56 0 5645 เป็นต้น floatชนิดของตัวแปรที่เป็นตัวแทนของจำนวนจริง หรือตัวเลขที่มีค่าทศนิยม ความละเอียดของตัวเลขหลังจุดทศนิยมขึ้นอยู่กับระบบคอมพิวเตอร์ โดยปกติแล้ว ตัวแปรชนิด float จะใช้เนื้อที่ 4 ไบต์ นั่นคือจะให้ความละเอียดของตัวเลขหลังจุดทศนิยม 6 ตำแหน่ง และมีค่าอยู่ระหว่าง -1038 ถึง +1038 ตัวอย่างของค่า float ได้แก่ 16.315 -0.67 31.567 bool ชนิดของตัวแปรที่สามารถเก็บค่าลอจิก จริง (True) หรือ เท็จ (False) ตัวแปรชนิดนี้ เป็นที่รู้จักกันอีกชื่อคือ ตัวแปรบูลีน (Boolean) ตัวอย่างของตัวแปรชนิด bool ได้แก่ 1 0 true false (เมื่อ 1 = true และ 0 = false) char เป็นชนิดตัวแปรที่เป็นตัวแทนของ ตัวอักษรเพียงตัวเดียว อาจเป็นตัวอักษร ตัวเลข หรือตัวอักขระพิเศษ โดยปกติตัวแปรชนิดนี้จะใช้เนื้อที่เพียง 1 ไบต์ ซึ่งจะให้ตัวอักษรในรูปแบบที่แตกต่างกันได้ถึง 256 ค่า การเขียนรูปแบบของ char หลายๆ ตัว โดยปกติ จะอ้างอิงกับ American Standard Code for Information Interchange (ASCII) ตัวอย่างของตัวแปรชนิด char ได้แก่ '+' 'A' 'a' '*' '7' การกำหนดชนิดของตัวแปร สามารถเขียนได้อยู่ในรูป type identifier-list; เมื่อ type บ่งบอกชนิดของตัวแปร ส่วน identifier-list เป็นการกำหนดชื่อของตัวแปร ซึ่งอาจจะมีมากกว่า 1 ตัวแปร และจะแยกตัวแปรแต่ละตัวออกจากกันด้วยเครื่องหมาย comma (,) ตัวอย่าง รูปแบบของการกำหนดชนิดของตัวแปร ได้แก่
int i, j, count;
 float sum, product;
 char ch;
 bool passed_exam;
มาถึงตอนนี้ เราก็จะสามารถปรับปรุงการเขียนโปรแกรมแบบง่ายๆ ได้ดังนี้
#include 
main()
{
   int its_price;
   printf("How much is that ? ");
   scanf("%d", &its_price);
   printf("oh! %d ?, hmmm...., too expensivenn",its_price);
}
จาก code ข้างบน ผู้อ่านจะเห็น %d เมื่อมีการเรียกใช้ฟังก์ชัน scanf และ printf ทั้งนี้ %d จะเป็น format ที่ใช้บ่งบอกชนิดของตำแหน่ง (Place Holders) ที่จะมีการส่งข้อมูล โดยในที่นี้ %d หมายถึงตำแหน่งของจำนวนเต็ม หรือ int นั่นเอง ตัวอย่างของ Place Holders อื่นๆ สามารถแสดงได้ดังตาราง คราวนี้ลองมาดูตัวอย่างของการใช้ Place Holders
printf("C=%f, F=%f",cel,fah);
printf("He wants to score %d goals today",9);
เมื่อ % เป็นการบ่งบอกตำแหน่งเริ่มต้นของ Place Holder จากนั้น ตัวอักษร f ตัวแรก จะบ่งบอกถึง ตัวแปรcel ว่ามีค่าเป็นจำนวนจริง (Float) ส่วน f ตัวทีสอง จะบ่งบอกคอมไพเลอร์ว่า ตัวแปร fah ก็มีค่าเป็นจำนวนจริงเช่นกัน นอกจากนี้ Place holder %d และ %f ยังสามารถใช้กับการกำหนดตำแหน่งตัวเลขตามต้องการได้ ยกตัวอย่างเช่น สมมุติให้ x=235; และ y=6.54321;
5520
การให้กำหนดค่าตัวแปร (Variable Assignment) เราสามารถกำหนดค่าให้กับตัวแปรได้ ด้วยเครื่องหมาย = ยกตัวอย่างเช่น int name; // กำหนดตัวแปร name ที่เก็บค่าจำนวนเต็ม name = 23; // กำหนดให้ตัวแปร name มีค่าเป็น 23 ในขณะเดียวกัน เราสามารถใช้เครื่องหมาย = ระหว่างตัวแปรกับตัวแปร หรือตัวแปรกับจำนวนใดๆ ได้ อาทิเช่น
change = x1 - x2;
mean = (x1 + x2)/2;
x = x + 1;
ตอนนี้เราลองมาเขียนโปรแกรมอย่างง่าย เพื่อทำการแก้ปัญหาทางคณิตศาสตร์ ด้วยการแปลงค่า อุณหภูมิ ในหน่วยของ ฟาเรนไฮต์ เป็น เซลเซียส เมื่ออุณหภูมิในหน่วยฟาเรนไฮต์ มีค่า = 85 และเป็นที่ทราบกันดีว่า ความสัมพันธ์ระหว่าง องศาฟาเรนไฮต์ และ เซลเซียส สามารถเขียนได้อยู่ในรูปของสมการ
5521
การเขียนโปรแกรม เพื่อแก้ปัญหา การแปลงค่า 85 ฟาเรนไฮต์ให้เป็นเซลเซียส สามารถเขียนได้ดังนี้
#include 
void main()
{
     float F;
 float C;

 F = 85;
 C = 5*(F-32)/9;
 printf("the result is %f",C);
}
อีกตัวอย่าง ของโปรแกรม การบวกค่าจำนวนเต็ม 2 จำนวนเข้าด้วยกัน แล้วแสดงผลลัพธ์ออกทางหน้าจอ การเขียนโปรแกรมเพื่อแก้ปัญหานี้ สามารถเขียนได้ดังนี้
#include 
void main()
{
    int N1, N2, Sum;
 
 printf("please input an integer number : ");
 scanf("%d",&N1);
 printf("please input another integer number : ");
 scanf("%d",&N2);

 Sum = N1 + N2;
 printf("so, %d + %d = %d",N1,N2,Sum);
}
จากตัวอย่างการเขียนโปรแกรมข้างต้น จะเห็นว่ามีการคำนวณทางคณิตศาสตร์เข้ามาเกี่ยวข้อง คราวนี้เราลองมาดู การคำนวณในภาษา C กันว่าจะเขียนกันได้อย่างไรบ้าง
5522


หน้าที่ 3 - การเปรียบเทียบ แบบมีทางเลือก (Selection Structures)
2.การเขียนโปรแกรมแบบมีทางเลือก (Selection Structures) การเขียนโปรแกรมแบบมีทางเลือก จะสามารถทำให้โปรแกรมสามารถตัดสินใจหรือเปรียบเทียบ จากนั้นก็จะเลือกดำเนินการไปในทิศทางหนึ่งจากสองทิศทาง ขึ้นอยู่กับผลที่ได้จากการเปรียบเทียบนั้น เงื่อนไข (Condition) - เป็นตัวกำหนดเงื่อนไขที่ผู้พัฒนาโปรแกรมได้สร้างขึ้นมา - ผลลัพธ์ที่ได้จากเงื่อนไข จะมีค่า จริงหรือ เท็จ โครงสร้างของเงื่อนไข (Condition Control Structures) ประโยคเงื่อนไขสามารถที่จะเขียนให้อยู่ในรูปภาษา C จะเขียนได้ดังนี้ if condition then A else B ซึ่งหมายความว่า ถ้าเงื่อนไข (condition) มีค่าเป็นจริง ก็จะดำเนินการทำคำสั่ง A มิเช่นนั้นก็จะทำคำสั่ง B ตัวอย่างของการเขียนโครงสร้างทางเลือกในภาษา C สามารถเขียนได้ดังนี้
if (x < y)
 a = x * 2;
else
 a = x + y;
ความหมายของ code ดังกล่าว หมายความว่า ถ้า ค่า x มีค่าน้อยกว่า y แล้ว a = x*2 แต่ถ้า x มีค่ามากกว่าหรือเท่ากับ y แล้ว a = x+y นั่นเอง รูปแบบของเงื่อนไข ส่วนใหญ่จะอยู่ในรูป “ตัวแปร โอเปอเรเตอร์ ตัวแปร” โอเปอเรเตอร์ที่กล่าวถึงนี้จะมีอยู่ 2 แบบ ด้วยกันคือ โอเปอเรเตอร์สัมพันธ์ (Relational Operator) และ โอเปอเรเตอร์ลอจิก (Logical Operator) โอเปอเรเตอร์สัมพันธ์ที่ใช้ในภาษา C มีดังต่อไปนี้
5523
if ( condition1 ) 
   statement1 ; 
else 
      if ( condition2 ) 
           statement2 ; 
           . . . 
        else if ( condition-n ) 
                  statement-n ; 
                else 
                  statement-e ;
ยกตัวอย่างของโปรแกรม Nested if สามารถเขียนได้ดังนี้
if (x < 0.25)
  count1++;
else if (x < 0.5)
           count2++;
        else if (x < 0.75)
                  count3++;
                else
                    count4++;
นอกจากรูปแบบของ if-else แล้ว เรายังสามารถใช้เครื่องหมาย ? มาประยุกต์ในการเขียน code เพื่อให้ได้ความหมายเดียวกันกับ if-else ดังแสดงให้เห็นดังนี้
if (x < y)
 a = x * 2;
else
 a = x + y;
สามารถเขียนได้ในอีกรูปแบบหนึ่งคือ a = x < y ? x*2: x+y ; // ซึ่งจะให้ความหมายเดียวกันกับ code ข้างบนนั่นเอง ในบางครั้งที่เราต้องเขียนโปรแกรมแบบมีทางเลือก โดยบางครั้งเราต้องการให้มีทางเลือกมากว่า 2 ทาง Nested if เป็นวิธีหนึ่งที่สามารถใช้แก้ปัญหาได้ แต่เพื่อให้ง่ายขึ้น ในภาษา C เราจึงสามารถใช้คำสั่ง switch ได้ โดยรูปแบบการเขียน คำสั่ง switch สามารถเขียนให้อยู่ในรูป
switch (selector) 
      {
      case label1: statement1;
          break;
      case label2: statement2;
          break;
          ...
      case labeln: statementn;
          break;
      default: statementd; // optional
          break;
      }
โดยที่ selector จะต้องเป็นจำนวนเต็ม ตัวอักษร หรือผลลัพธ์ของการกระทำที่ให้เลขจำนวนเต็มหรือตัวอักษร ตัวอย่างของการเขียน code โดยมีการเรียกใช้คำสั่ง switch สามารถเขียนได้ดังนี้ switch (i) { case 1 : grade = 'A'; break; case 2 : grade = 'B'; break; case 3 : grade = 'c'; break; default : printf("%c not in range", i); break; } โดยหลักการของ switch คือ compiler จะทำการเปรียบเทียบค่าของ selector เทียบกับ label ถ้าไม่ตรงกับ label ใดๆ ก็จะเข้าไปทำในคำสั่งของ default นอกจากนี้ การใส่คำสั่ง break หรือไม่มีคำสั่ง break ก็จะให้ผลลัพธ์ที่แตกต่างกัน ดังแสดงให้เห็นดังตัวอย่างต่อไปนี้ (ทดลอง Run แล้วจะเห็นความแตกต่าง)
5524
5525
การเปรียบเทียบตัวอักษร คุณผู้อ่านทราบกันหรือไม่ว่า ตัวอักษรสามารถเปรียบเทียบค่ากันได้ เบื้องต้นเราต้องทราบก่อนว่า ตัวอักษรมีค่าอย่างไรกันบ้าง  ตัวอักษรตัวเล็ก ‘a’ มีค่า 97 ไปจนถึง ‘z’ มีค่า 122  ตัวอักษรตัวใหญ่ ‘A’ มีค่า 65 ไปจนถึง ‘Z’ มีค่า 90 ตัวอย่างของการเปรียบเทียบตัวอักษร สามารถแสดงให้เห็นได้ดังนี้  ‘9’ >= ‘0’ มีค่าเป็นจริง (1)  ‘a’ < ‘e’ มีค่าเป็นจริง (1)  ‘B’ <= ‘A’ มีค่าเป็นเท็จ (0)  ‘a’ <= ‘A’ ขึ้นอยู่กับระบบ แต่ส่วนใหญ่ เป็นเท็จ  ‘a’ <= ‘c’ && ‘c’ <= ‘z’ มีค่าเป็นจริง คราวนี้เราลองมาดูโจทย์กัน สมมุติว่า เราจะเขียนโปรแกรม เพื่ออ่านค่าตัวอักษร 4 ตัว แล้ว เราต้องการที่จะเปลี่ยนตัวอักษรแต่ละตัว ให้เป็นตัวอักษรใหญ่ หรือเล็กที่ตรงข้ามกับค่าที่รับเข้าไป ยกตัวอย่างเช่น PooH ให้เปลี่ยนเป็น pOOh เราจะเขียนโปรแกรมอย่างไร คำตอบ วิธีหนึ่งที่สามารถทำได้ คือใช้ Nested-if ดังนี้ #include void main() { char A, B, C, D; printf("Input 4 charactersn"); scanf("%c %c %c %c", &A, &B, &C, &D); if((A <= 90)&&(A >= 65)) A = (A - 65) + 97; else if ((A >= 97)&&(A <= 122)) A = (A-97) + 65; else A = A; if((B <= 90)&&(B >= 65)) B = (B - 65) + 97; else if ((B >= 97)&&(B <= 122)) B = (B-97) + 65; else B = B; if((C <= 90)&&(C >= 65)) C = (C - 65) + 97; else if ((C >= 97)&&(C <= 122)) C = (C-97) + 65; else C = C; if((D <= 90)&&(D >= 65)) D = (D - 65) + 97; else if ((D >= 97)&&(D <= 122)) D = (D-97) + 65; else D = D; printf("The answer is %c %c %c %cn", A, B, C, D);

หน้าที่ 4 - การเขียนโปรแกรมแบบ วนซ้ำ (Loop)
3.การเขียนโปรแกรมแบบ วนซ้ำ (Repetition & Loop) กระบวนการหนึ่งที่สำคัญในการออกแบบอัลกอริทึม ก็คือความสามารถในการวนลูปของการทำงานของกลุ่มคำสั่งตามที่นักพัฒนาต้องการ ดังนั้นสำหรับตอนนี้ ก็จะนำเสนอการพัฒนาโปรแกรมเพื่อให้บางส่วนของคำสั่งสามารถมีการวนซ้ำได้หลายครั้ง สำหรับคำสั่งที่สามารถใช้ในการเขียนโปรแกรมแบบวนซ้ำในภาษา C ได้แก่ While, Do-while และ For ตัวอย่างของการใช้คำสั่ง while, for และ do-while สามารถเขียนให้เห็นได้ดังตาราง ซึ่งผลลัพทธ์ของโปรแกรมทั้ง 3 ข้างต้นจะให้ผลลัพท์ที่เหมือนกัน คือจะแสดงผลบนหน้าจอเป็น i = 0 i = 1 i = 2 i = 3 i = 4 i = 5 i = 6 คราวนี้เราลองมาดูโครงสร้างของการใช้งานแต่ละคำสั่งกัน while ( condition ) // เมื่อ เงื่อนไข (condition) เป็นจริง ก็จะทำการวนซ้ำ ใน statement ถัดไป statement ยกตัวอย่างเช่น
sum = 0.0;
x = 5;
while (x > 0.0)
   {
    sum += x;
    x = x – 1;
   }
ในที่นี้จะเห็นว่า ค่า x มีค่าเริ่มต้นเท่ากับ 5 ซึ่ง 5 > 0 เงื่อนไขของคำสั่ง while เป็นจริง จึงทำคำสั่งถัดมาคือ sum += x; หมายความว่า sum = sum + x = 5 จากนั้นค่า x ก็มีค่าลดลงไป 1 เหลือ 4 ก็จะทำการ check เงื่อนไขว่า 4 > 0 หรือไม่ เมื่อเงื่อนไขเป็นจริง ก็จะทำการวนซ้ำ sum ก็จะมีค่าเป็น 5 + 4 = 9 และ x ก็จะมีค่าลดลงเหลือ 3 และดำเนินการวนซ้ำเช่นนี้จนกระทั่ง x มีค่าเป็น 0 ซึ่งค่า 0 ไม่ได้มีค่ามากกว่า 0.0 เงื่อนไขจึงเป็นเท็จ โปรแกรมจึงจะจบการวนซ้ำ คราวนี้เราลองมาดูตัวอย่างของการใช้คำสั่ง while ในการเขียนโปรแกรมแบบวนซ้ำ และผลลัพท์ที่ได้
x=0;
while( x <=2 ){
   printf("%d %dn",x, x*2);
}

ผลลัพท์ที่ได้จะได้ดังนี้
 0 0
 0 0
 0 0
 :   :
 0 0  (infinite loop)
การที่ผลลัพท์ออกมาเช่นนี้ ก็เนื่องจากว่า x มีค่าเริ่มต้น 0 และเงื่อนไข x <= 2 เป็นจริงตลอด โปรแกรมจึงทำการพิมพ์ค่า 0 0 ออกมา และเนื่องจากค่า x ไม่มีการเปลี่ยนแปลง เงื่อนไขจึงเป็นจริงตลอด โปรแกรมจึงแสดงผลบนหน้าจอโดยไม่หยุดนั่นเอง อีกตัวอย่างของการใช้งาน while ในการเขียนโปรแกรมแบบวนซ้ำ แสดงได้ดังนี้
scanf(“%d”,&n);
a = 10;
while (a > n) {
   printf(“%dn”,a);
   a = a-1;
}
ผลลัพท์ของโปรแกรมจะสามารถแสดงให้เห็นได้ดังนี้
10
 9
 8
 7
คราวนี้เราลองมาแก้โจทย์ปัญหา การหาค่า ห.ร.ม (หารร่วมมาก) ของตัวเลข 2 ตัวใดๆ โดยอัลกอริทึม Euclidean โดยอัลกอริทึมดังกล่าว จะทำการแปลงค่าตัวเลข 2 ตัวเลขบวกใดๆ (m, n) เป็นค่า (d, 0) โดยการนำตัวเลขที่มีค่ามาก นำมาหารด้วยตัวเลขที่มีค่าน้อยกว่า นำค่าเศษที่หารได้มาแทนตัวเลขที่มีค่ามากกว่า ทำเช่นนี้จนกระทั่งได้ค่าเศษจากการหารมีค่าเป็น 0 ตัวเลขอีกตัวก็จะเป็นค่า ห.ร.ม. ยกตัวอย่างเมื่อเราทำการ Run โปรแกรม จะได้ผลดังนี้ Enter two positive integers: 532 112 The g.c.d. of 532 and 112 is 28 คราวนี้เราลองมาดูการเขียนโปรแกรมเพื่อแก้ปัญหาดังกล่าวข้างต้น สามารถเขียนได้ดังนี้
#include 
void main()
{
 int A, B, start;
     printf("Enter two positive intergers: ");
 scanf("%d %d", &A, &B);
 if(A < B) start = A;
 else start = B;
 while(((A%start) != 0)||((B%start) != 0))
 {
  start = start-1; 
 }
 printf("The g.c.d of %d and %d is %dn", A, B, start);
}
การดำเนินการทางคณิตศาสตร์ สามารถเขียนให้อยู่ในรูปแบบสั้นๆ ได้ ดังตัวอย่างในตารางดังนี้
5526
ความแตกต่างระหว่าง i++ และ ++i i++ และ ++i จะมีความหมายใกล้เคียงกันมาก จะแตกต่างเพียง การจัดลำดับในการคำนวณ เมื่อต้องนำไปใช้กับตัวแปรตัวอื่น A = 10; C = A++; // A= 11, C = 10 A = 10; C = ++A; // A = 11, C = 11 A = 10; C = A--; // A = 9, C = 10 A = 10; C = --A; // A = 9, C = 9 โครงสร้างการเขียนโปรแกรมแบบวนซ้ำโดยใช้คำสั่ง For คำสัง for สามารถเขียนให้อยู่ในรูปแบบได้ดังนี้ for ( เริ่มต้น ; เงื่อนไข ; เปลี่ยนแปลง ) statement; เมื่อเริ่มต้น เป็นการกำหนดค่าตัวแปรเริ่มต้นที่ต้องการ ส่วนเงื่อนไขหากค่าลอจิกมีค่าเป็นจริง ก็จะทำตามในโครงสร้างของการวนซ้ำคือ run คำสั่ง statement แต่ถ้าเป็นเท็จก็จะออกจากโครงสร้างการวนซ้ำ ส่วนเปลี่ยนแปลง จะทำการปรับค่าของตัวแปรที่ต้องการ ยกตัวอย่างเช่น
for ( count=0 ; count < 10 ; count++)
  {
   printf(“count = %dn”,count);
  }
ใน code ข้างต้น ตัวแปร count จะเริ่มต้นจากค่า 0 ซึ่งค่า 0 มีค่าน้อยกว่า 10 ก็จะทำคำสั่ง print ค่าของตัวแปร count จากนั้นค่า count ก็จะเพิ่มค่าเป็น 1 เงื่อนไข count < 10 ก็ยังคงเป็นจริง ก็จะทำการพิมพ์ ค่าของตัวแปร count วนซ้ำเช่นนี้ จนกระทั่ง count มีค่าเพิ่มขึ้นจนเป็น 10 เงื่อนไขก็จะเป็นเท็จ และจบโครงสร้างของการวนซ้ำ การเปลี่ยนแปลงค่าของตัวแปร อาจจะมีการเปลี่ยนแปลงมากกว่า 1 ค่า ยกตัวอย่างเช่น
for ( count=0 ; count < 10 ; count += 2)  // ตัวแปร count มีค่าเปลี่ยนแปลงเพิ่มขึ้นครั้งละ 2
{
   printf(“count = %dn”,count);
}
for ( count=10 ; count > 5 ; count -= 2)   // ตัวแปร count มีค่าเปลี่ยนแปลงลดลงครั้งละ 2
{  
   printf(“count = %dn”,count);
}
นอกจากนี้เรายังสามารถใช้ตัวแปร เป็นการกำหนด ค่าเริ่มต้น เงื่อนไข และ เปลี่ยนแปลงได้ ยกตัวอย่างเช่น
start = 0; end = 20; step=3;
for ( count=start ; count < end ; count += step)
{
   printf(“count = %dn”,count);
}
คราวนี้ เราลองมาทดลองเขียนโปรแกรม โดยให้โปรแกรม สามารถรับค่าตัวเลขใดๆ และแสดงค่าในรูปแบบดังตัวอย่างต่อไปนี้
5527
Input the number > 4

0
0 1
0 1 2
0 1 2 3
0 1 2
0 1
0

เราสามารถแก้ปัญหาข้างต้น โดยใช้โครงสร้างการเขียนโปรแกรมแบบวนซ้ำดังต่อไปนี้
#include 
void main()
{
 int number, i, j;
     printf("Enter number: ");
 scanf("%d", &number);
 for(j= 0; j< number; j++)
 {
  for(i=0; i<= j; i++)
  {
   printf("%d ", i);
  }
  printf("n");
 }
 for(j= number-1; j>= 0; j--)
 {
  for(i=0; i< j; i++)
  {
   printf("%d ", i);
  }
  printf("n");
 }
}
โครงสร้างการเขียนโปรแกรมแบบวนซ้ำโดยใช้คำสั่ง do-while รูปแบบของการเขียน code สำหรับโปรแกรมแบบวนซ้ำที่ใช้ do-while สามารถเขียนให้อยู่ในรูปทั่วไปได้ดังนี้ do statement while ( เงื่อนไข ); ตัวอย่างของโครงสร้าง do-while สามารถเขียนได้ดังนี้
sum = 0.0;
scanf(“%f”, &x);
do {
    sum += x;
    scanf(“%f”, &x);
  }
while (x > 0.0);
โปรแกรมข้างต้นจะทำการอ่านค่าจะ keyboard เมื่อ User พิมพ์ค่าที่มีค่ามากกว่าศูนย์ ก็จะทำการบวกค่าเหล่านี้ไปที่ตัวแปร sum จนกระทั่ง User พิมพ์ ตัวเลข 0 หรือค่าที่น้อยกว่า ศูนย์ ทำให้เงื่อนไขเป็นเท็จ และโปรแกรมจึงจะออกจากโครงสร้าง do-while คราวนี้เราลองมาเขียนโปรแกรมที่ใช้โครงสร้าง do-while โดยโจทย์กำหนดให้ว่า ให้โปรแกรมสามารถรับค่าตัวเลขใดๆ (X) และ แสดงผลของตัวเลข ระหว่าง 0 ถึง X ที่สามารถหารด้วย 4 ลงตัว
#include 
void main()
{  
 int number, i;
 printf("enter the numbern");
 scanf("%d", &number);
            i = 0;
 do
 {
  if((i % 4) == 0) printf("%d ", i);
                       i++;
 }
            while(i <= number);
}
ตอนนี้ผู้อ่านก็คงจะรู้จัก การเขียนโปรแกรมแบบวนซ้ำกันแล้วนะ ต่อไป เราก็จะไปเรียนรู้เกี่ยวกับการเขียนโปรแกรมแบบแยกเป็นโมดูลกัน

หน้าที่ 5 - ฟังก์ชัน (Functions) และ โปรแกรมแยกเป็นโมดูล (Modular Programming)
4.ฟังก์ชัน และการเขียนโปรแกรมแยกเป็นโมดูล (Functions & Modular Programming) สำหรับนักพัฒนา ที่ได้ทำการพัฒนาโปรแกรมมามากๆ บางครั้ง จำเป็นต้องเขียนโปรแกรมที่มีขนาดใหญ่และมีความสลับซับซ้อน จึงจำเป็นต้องหาวิธีในการพัฒนาโปรแกรมที่ดี ซึ่งสามารถทำได้ด้วยการ แตกปัญหาใหญ่ออกเป็นปัญหาย่อยๆ แล้วแก้ปัญหาย่อยออกไปที่ละส่วนจนกว่าจะหมด ซึ่งจะช่วยให้แก้ปัญหาใหญ่ๆ ได้สำเร็จนั่นเอง ซึ่งเราเรียกกันว่า วิธีแบ่งแยกแล้วพิชิต (Divide and Conquer) ซึ่งจะเป็นแนวการแก้ปัญหาแบบจากบนลงล่าง (Top down approach) ดังแสดงให้เห็นดังภาพที่ 4.1
5529
การแตกปัญหาออกเป็นฟังก์ชันย่อยๆ มีข้อดีดังนี้ 1) การแยกปัญหาที่จะใช้ในการเขียนโปรแกรมออกเป็นฟังก์ชันย่อยๆ จะช่วยให้เขียนโปรแกรมได้ง่ายขึ้นเพราะปัญหามีความซับซ้อนน้อยลง 2) การแยกปัญหาที่จะใช้ในการเขียนโปรแกรมออกเป็นฟังก์ชันย่อยๆ สามารถแก้ปัญหาตามที่โปรแกรมต้องทำ โดยมีโอกาสที่จะผิดพลาดน้อยลงเนื่องจากได้ทดสอบแก้ไขข้อผิดพลาดภายในฟังก์ชันย่อยๆ ก่อนรวมกันเป็นโปรแกรมใหญ่แล้ว 3) การแยกปัญหาออกเป็นฟังก์ชันย่อยนั้นมีประโยชน์ ที่ทำให้เราสามารถใช้ฟังกชันย่อยๆ เหล่านี้กลับไปใช้กับโปรแกรมอื่นๆ ได้ด้วย 4) การนำฟังกชันย่อยๆ เหล่านี้กลับมาใช้อีก จะช่วยลดขนาดของโปรแกรมลง และยังช่วยลดเวลาและค่าใช้จ่ายในการพัฒนาและการซ่อมบำรุงโปรแกรมได้อีกด้วย เพราะไม่ต้องเสียเวลาในการเขียนฟังก์ชันซ้ำ นอกจากฟังก์ชันย่อยที่ยังไม่ได้เขียนมาก่อน ตัวอย่างการเขียนโปรแกรมออกเป็นโมดูลต่างๆ จะแสดงให้เป็นดังผังในภาพที่ 4.2 ซึ่งในภาพดังกล่าวได้แยกโปรแกรม Main ออกเป็นส่วนๆ คือ
5530
1) ส่วนรับข้อมูล (Input) ซึ่งจะเป็นไปตามความต้องการของผู้ใช้ เช่นการป้อนข้อมุล หรือ การอ่านไฟล์ข้อมูล 2) ส่วนการคำนวณ (CAL) ซึ่งประกอบด้วยฟังก์ชันที่ใช้กับการคำนวณ ได้แก่ i. AVG สำหรับคำนวณค่าเกรดเฉลี่ยสำหรับเทอมปัจจุบัน ii. GPA สำหรับคำนวณเกรดเฉลี่ยสะสม 3) ส่วนการแสดงผล (Display) ซึ่งเป็นการแสดงผลบนจอภาพ หรือจะพิมพ์ผลออกมาก็ได้ตามความต้องการของผู้ใช้โปรแกรม ที่กำหนดให้ผู้เขียนโปรแกรมทำให้สำเร็จตามเป้าหมาย ภาพที่ 4.2: ตัวอย่างการเขียนโปรแกรมคำนวณค่าเกรดเฉลี่ย และ เกรดเฉลี่ยสะสมออกเป็นโมดูล ส่วนในการตั้งชื่อฟังก์ชันนั้น ก็มีข้อกำหนดดังนี้ 1) ห้ามขึ้นต้นด้วยตัวเลข 2) ห้ามเอาชื่อตารางอาเรย์ ชื่อตัวแปร หรือ คำสำคัญ (keywords) มาตั้งชื่อฟังก์ชันโดยเด็ดขาด 3) ในการใช้งานจริง นั้น ไม่ควรตั้งชื่อฟังก์ชันโดยไม่สื่อความหมายถึงการทำงานของฟังก์ชัน เพราะจะทำให้ลำบากในการซ่อมบำรุงโปรแกรม โดยทั่วไปแล้วในการประกาศฟังก์ชันนั้น จะต้องมีการกำหนด type ให้ตัวแปรร่วมภายในฟังก์ชันด้วยเสมอ ดังตัวอย่างต่อไปนี้ ชนิดของฟังก์ชัน[function-type] ชื่อฟังก์ชัน [function-name] (บัญชีตัวแปรร่วม [parameter-list])
{
  การประกาศตัวแปรเฉพาะที่; [local-definitions declaration;]
  กลไกการทำงานของฟังก์ชัน; [function-implementation;]
  การคืนค่าถ้าชนิดฟังก์ชันไม่เป็น void; [return statement if function type NOT void]
}

ยกตัวอย่างเช่น

float distance(float x, float y) // float คือ ชนิดของฟังก์ชัน ส่วน distance คือ ชื่อฟังก์ชัน
{    // float x, float y คือ บัญชีตัวแปรร่วม
 float dist;  // float dist คือ การประกาศตัวแปรเฉพาะที่;
 dist = sqrt(x*x+y*y); // dist = ระยะห่างระหว่างพิกัด (x,y) ไป (0,0) 
 return dist ;
}
ก่อนจะทำการเรียกใช้ฟังก์ชัน จำเป็นต้องมี การกำหนดฟังก์ชัน (function prototype) ซึ่งเป็น copy ของ function heading และมีข้อกำหนดดังนี้ 1) ตัวแปรร่วมในฟังก์ชัน ที่ประกาศไว้ และ ตัวแปรร่วมขณะเรียกใช้ฟังกชันนั้นต้องมีจำนวนเท่ากันและต้องมี type ตรงกัน มิฉะนั้นจะเกิด error ขึ้น 2) ต้องกำหนดการทำงานของฟังก์ชันก่อนการเรียกใช้ฟังก์ชัน ใน main function เพื่อให้ตัวแปรภาษารู้ว่าฟังก์ชันนี้ทำงานอย่างไร 3) แม้ฟังก์ชันที่ใช้จะไม่มีค่าตัวแปรร่วม ก็ต้องใส่วงเล็บ [ ( ) ] ไว้หลังชื่อฟังก์ชันเสมอ 4) การกำหนดฟังก์ชัน จะต้องกำหนดก่อนการใช้ Main function เพื่อให้ Main function ได้รับรู้ว่าฟังก์ชันดังกล่าวมีอะไรเป็นตัวแปรร่วม และ จะคืนค่าอะไรออกมา 5) กลไกการทำงานเต็มของฟังก์ชันย่อยจะแสดงหลังจากที่เรียก Main function แล้ว หรืออยู่ในไฟล์ที่แยกต่างหาก ซึ่งจะมีการแปรออกมาแล้วเชื่อมต่อกับ Main function การกำหนดฟังก์ชันจะมีลักษณะดังนี้
float distance(float, float); // การกำหนดฟังก์ชัน [function prototype]

 void main()
 {
  float x0 = ….,y0 = …;
 float dist1 = distance(x0,y0); 
}
float distance(float x, float y) // float คือ ชนิดของฟังก์ชัน distance คือ ชื่อฟังก์ชัน
{    // float x, float y คือ บัญชีตัวแปรร่วม
 float dist;  // float dist คือ การประกาศตัวแปรเฉพาะที่;
 dist = sqrt(x*x+y*y); 
 return dist ;
}
ในการส่งผ่านตัวแปรเข้า ฟังก์ชัน (Passing argument) นั้นมีการเรียกได้ 2 แบบ คือ 1) ส่งผ่านตามค่า (Pass by Value) ซึ่งส่งผ่านค่า ลงในตัวแปรร่วมของฟังก์ชันโดยตรง 2) ส่งผ่านตามการอ้างอิง (pass by Reference) ซึ่งส่งผ่านค่า address ในหน่วยความจำของตัวแปร ให้กับตัวแปรร่วมของฟังก์ชัน ถ้ามีการเปลี่ยนแปลงข้อมูล ณ ตำแหน่งหน่วยความจำดังกล่าว ค่าที่ส่งให้ตัวแปรร่วมของฟังก์ชันก็จะเปลี่ยนด้วยตัวแปรที่เกี่ยวข้องกับฟังก์ชันคือ 1) ตัวแปรเฉพาะที่ (Local variables) เป็นตัวแปรที่อยู่และเปลี่ยนแปลงเฉพาะภายในฟังก์ชันที่เรียกใช้ตัวแปรดังกล่าว การเปลี่ยนแปลงภายนอกฟังก์ชันที่เรียกใช้ตัวแปรเฉพาะที่จะไม่มีผลต่อตัวแปรเฉพาะที่ดังกล่าว ดังตัวอย่างต่อไปนี้
void test_locvar(int num)
{
 int myvar; // Local variable fro this function
 myvar = num;
}
void main()
{
 int myvar, myvar_before, myvar_after; //Local variable for this function 
 myvar = 5;
 myvar_before = myvar; // myvar_before = 5;
 test_locvar(100); // call function
 myvar_after = myvar; // myvar_after = 5;
}
2) ตัวแปรส่วนกลาง (Global variables) เป็นตัวแปรที่อยู่นอกฟังก์ชันซึ่งสามารถเปลี่ยนแปลงค่าภายในตัวแปรได้ตลอดเวลาเมื่อตัวแปรได้รับการเปลี่ยนแปลงโดยฟังก์ชัน ดังตัวอย่างต่อไปนี้
int myvar; // Global varible
void test_locvar(int num)
{
 myvar = 20;
}

void main()
{
 int myvar_before, myvar_after;  //Local variable fro this function 
 myvar = 5;
 myvar_before = myvar; // myvar_before == 5;
 test_locvar(100); // call function
 myvar_after = myvar; // myvar_after == 20;
}
ฟังก์ชันมีหลายประเภทได้แก่ 1) ฟังก์ชันที่ไม่มี อาร์กิวเมนต์ และ ไม่คืนค่า เช่น ฟังก์ชัน void main() 2) ฟังก์ชันที่มี อาร์กิวเมนต์ แต่ ไม่คืนค่า เช่นฟังก์ชัน void do_something(float x, float y) ซึ่งจะทำงานตามที่ต้องการโดยอาศัยค่าอาร์กิวเมนต์ (ตัวแปร x,y) โดยไม่คืนค่าออกมา ฟังก์ชันดังกล่าวจะมีกลไกการับข้อมูลเข้าต่างหาก โดยไม่ต้องใช้ตัวแปรที่เป็น อาร์กิวเมนต์ 3) ฟังก์ชันที่ไม่มี อาร์กิวเมนต์ แต่ก็คืนค่า เช่น ฟังก์ชัน float do_something2() ค่าที่คืนมาได้จาก ตัวแปรเฉพาะที่และกลไกการคำนวณภายในฟังก์ชันดังกล่าว 4) ฟังก์ชันที่มี อาร์กิวเมนต์ และ คืนค่า เช่นฟังก์ชัน float distance(float x, float y) ฟังก์ชันดังกล่าว สามารถคืนค่า โดยไม่จำเป็นต้องใช้ตัวแปรเฉพาะที่ทำหน้าที่เป็นตัวแปรชั่วคราวในการคืนค่า ตัวอย่างเช่น
float distance3D(float x, float y, float z)
{
  return sqrt((x*x)+(y*y)+(z*z));
}


หน้าที่ 6 - อาเรย์ (Arrays)
5. ตารางอาเรย์ (Arrays) ตารางอาเรย์ เป็นตัวแปรสำหรับรวบรวมข้อมูลชนิดเดียวกัน ลงในตัวช่องรับข้อมูลที่ติดกันตั้งแต่ 2 ช่องขึ้นไป ซึ่งข้อมูลในตารางอาเรย์ดังกล่าวสามารถเข้าถึงได้ พร้อมกันหลายช่อง โดยใช้ตัวแปรตัวเดียวในการเข้าถึง การสร้างตารางอาเรย์ จะต้องมีการประกาศค่าตั้งต้นภายในตารางอาเรย์ที่จะใช้ดังต่อไปนี้
Type ArrayName[size];    // Format of Blank array 
Type ArrayNameInitialized[size] = {…};  // Format of initialized array 
int a[5] = {0,0,0,0,0};
double air[5];
char vowel[] = {’A’,’E’,’I’,’O’,’U’};
ในกรณีใช้ตัวแปรดัชนี้ชี้ตำแหน่งข้อมูลในตาราง ค่าของตัวแปรที่จะชี้จะต้องอยู่ในช่วงระหว่าง 0 กับ N-1 โดยที่ N คือขนาดตารางอาเรย์ ดังตัวอย่างที่แสดงในภาพที่ 5.1
5531
ถ้าค่าดัชนีน้อยกว่า 0 หรือมากกว่า N – 1 แล้วโปรแกรมจะทำงานผิดพลาดหรือหยุดทำงาน การแยกแยะช่องตาราง (Array subscription) ทำได้โดย การใช้ชื่อตัวแปรอาเรย์ ตามด้วย วงเล็บเหลี่ยมที่มีค่าดัชนี (เช่น Data[i], i = 0, 1, 2, … N-1 ) การประกาศค่าตั้งต้นให้ตัวแปรอาเรย์สามารถทำได้โดยใช้เครื่องหมายปีกกา ( { } ) หรือจะยกประกาศค่าตั้งต้นที่ละช่องตารางก็ได้ตามความต้องการของผู้ใช้ โดยส่วนที่ ไม่ได้ใส่ค่าตั้งต้นจะมีค่าเป็นศูนย์ (กรณีตารางอาเรย์แบบ int, double, หรือ float) หรือเป็นค่าว่าง ดังตัวอย่างต่อไปนี้
int a[4] = {9, 8, 7}; ซึ่งจะได้ค่าออกมาตรงกัย a[0] = 9; a[1] = 8; a[2] = 7; และ a[3] = 0;

 กรณีที่ตารางมีหลายมิติ จะมีการเรียกใช้ตามรูปแบบตารางมิติเดียวต่อไปนี้ 
ตาราง 2 มิติ: type arrayname2D[size1][size2];
ตาราง 3 มิติ: type arrayname3D[size01][size02][size03];

 การค้นข้อมูลในตารางอาเรย์นั้น สามารถเข้าถึงได้อย่างรวดเร็วไม่ว่าตารางจะใหญ่เพียงไหน เช่น

 const int SIZE = 100; // #define SIZE 100 for C
 float A[SIZE],B[SIZE],C[SIZE];
for(i = 0; i <= SIZE-1; i++)
 {
  C[i] = B[i] – A[i];
}
ในการใช้ตัวแปรอาเรย์เป็นอาร์กิวเมนต์ให้ฟังก์ชันนั้น แบ่งได้หลายกรณีได้แก่ 1) กรณีที่จะเอาข้อมูลเฉพาะช่องตาราง จะมีการส่งผ่านข้อมูลในตารางอาเรย์ดังนี้
void main()
{
float X[10], X[0] = 123.23, X[1] = 24.56, X[2] = 45.67; 
float total = sum_element(X[0],X[1],X[2]);
 … 
}
float sum_element(float A, float B, float C)
{
 return (A+B+C);
}
2) กรณีที่ใช้ข้อมูลทั้งตารางอาเรย์ การส่งผ่านข้อมูลในตารางลงในฟังก์ชันจะเป็นดังนี้
void main()
{
float X[10], X[0] = 123.23, X[1] = 24.56, X[2] = 45.67; 
float total = sum_element_array(X)
 … 
}
float sum_element_array(float A[])
{
 int index; float Sum = 0;
 for(index =0; index <= 3-1; index++)
{
  Sum +=A[index];
}
return Sum;
}
3) กรณีที่ใช้ข้อมูลทั้งตารางเพื่อให้ได้ผลลัพธ์ออกมาเป็นตารางอาเรย์ให้ทำดังนี้
void add_arrays(float ar1[],  // input array 1
  float ar2[],  // input array 2
  float ar_sum[],  // Output array
  int N)  // Array Size
{
 for(int i = 0; i <= N-1; i++)
 {
  ar_sum[i] = ar1[i] + ar[2];
}
}
การค้นหาข้อมูลในตาราง (Array searching) ในการค้นข้อมูลนั้นมักใช้ linear search หาข้อมูลในตารางตามที่ต้องการ โดยกำหนดเงื่อนไขว่า 1) ถ้าหาข้อมูลพบ ให้แสดงดัชนีของค่าที่ค้นพบ ก่อนออกจากวงรอบการค้นหา 2) ถ้าหาข้อมูลไม่พบ ให้ออกจากโปรแกรมแล้วคืนค่า ที่อยู่นอก ขอบเขต 0 – N-1, N คือ ขนาดตารางอาเรย์ (โดยมากให้คืนค่า -1) การสับเรียงข้อมูลในตาราง (Array Sorting) การสับเรียงข้อมูลมีหลายวิธี ซึ่งจะกล่าวถึงในที่นี้พอสังเขปดังนี้ 1) Bubble Sort ซึ่งเขียนใช้งานง่ายแต่ สับตำแหน่งข้อมูลได้ผลช้าที่สุด ซึ่งมีกลไกดังนี้
void BubbleSort(float list[], int N)
{
 int i,j;
 float temp;
 for(i = N-1; i>=0; i--)
 {
  for(j = 1; j <=i; j++)
  {
   if(list[j-1] > list[j])
   {
    temp = list[j-1];
    list[j-1] = list[j];
    list[j] = temp;
}
}

}
}
2) Selection Sort ซึ่งจะเลือกค่าที่ยังไม่ได้สับเปลี่ยนที่น้อยที่สุดเป็นหลัก ในการสลับที่
void SelectSort(float list[], int N)
{
 int i,j, MinIndex;
 float temp;
 for(i = 0; i<=N-2; i--)
 {
  MinIndex = I;
  
for(j = i+1; j <=N-1; j++)
  {
  
   if(list[j] < list[MinIndex])
   {
    minIndex = j 
} 
   
   temp = list[j-1];
   list[j-1] = list[j];
   list[j] = temp;
}
}
}
3) Insertion Sort ซึ่งจะเติมข้อมูลลงในตำแหน่งที่เหมาะสมในขั้นสุดท้าย ซึ่งจะต้องมีตัวแปรอาเรย์ อย่างน้อย 2 ตัว โดยที่อาเรย์ตัวแรกทำหน้าที่ เป็น List เก็บข้อมูล ต้นฉบับ (Source List) และอาเรย์ตัวหลังทำหน้าที่รับข้อมูลที่ผ่านการสับตำแหน่งแล้ว (Sorted List) ในการสับที่กันนั้น จะให้ข้อมูลปัจจุบันเคลื่อนผ่านข้อมูลที่ผ่านการสับตำแหน่งแล้ว จากนั้นจึงลงมือสลับข้อมูลอีกครั้งจนกว่าข้อมูลทั้งหมดจะเข้าที่
void insert_sort(float data[], int Size)
{
 int i,j;
 float DatElement;
 for(i=1;i<=Size-1;i++)
 {
  DatElement = data[i];
  j = i;
  while((j >= 1) && data[j-1] >DatElement)
  {
   data[j-1] = data[j];
   j = j-1;
}
data[j] = DatElement;
}
}


หน้าที่ 7 - ตัวแปรพอยเตอร์ (Pointers)
6. ตัวแปรพอยเตอร์ (Pointers) Pointer คือตัวแปรดัชนีที่ เก็บค่าตำแหน่งแอดเดรสของหน่วยความจำ ซึ่งตัวแปรพอยเตอร์นั้น จะมีเครื่องหมายดอกจันทร์ (*) นำหน้าเสมอ ดังตัวอย่างต่อไปนี้ int *Num; float *GreatNum; char *Name; ตัวแปรพอยเตอร์มีประโยชน์ในการลดปริมาณหน่วยความจำที่ต้องใช้ในการเขียนโปรแกรม โดยการส่งข้อมูลในรูปพอยเตอร์ เข้าไปในฟังก์ชันที่โปรแกรมเรียกพร้อมกันหลายฟังก์ชัน แทนการส่งข้อมูลในรูปตัวแปรธรรมดา ซึ่งต้องใช้ตัวแปรหลายตัว ตัวแปรพอยเตอร์มีลักษณะคล้ายตัวแปรตารางอาเรย์ แต่ที่แตกต่างกันคือ ตัวแปรตารางอาเรย์จะเก็บเฉพาะค่าต่างๆ ที่เป็นชนิดกันเดียวกับตัวแปรอาเรย์แต่ ตัวแปรพอยเตอร์จะเก็บเฉพาะค่าตำแหน่ง Address ตัวแปรเท่านั้น โดยไม่ได้มีการจัดเตรียมหน่วยความจำแบบไดนามิกส์ (Dynamic Memory Allocation) ไว้ การเข้าถึงตำแหน่งแอดเดรสทำได้โดย ใช้เครื่องหมายแอมเปอร์แซนด์ (&) ซึ่งจะแสดงให้เห็นดังตัวอย่างต่อไปนี้ ในที่นี้กำหนดให้ตัวแปร Andy อยู่ในตำแหน่ง Address ที่ 1776 ดังตังอย่างในภาพที่ 6.1
5533
Andy = 25; // Assigning Value 25 to Andy Fred = Andy; // Assigning Value 25 (Value of Andy) to Fred Ted = &Andy // Assigning Value 1776 (Address of Andy) to Ted via & อย่างไรก็ดี ถ้าต้องการให้ตัวแปร Ted สามารถ ดึงค่า จากตัวแปร Andy ได้ ให้ ใช้สัญลักษณ์ ตัวอ้างอิงโดยอ้อม (Indirect operand) ซึ่งเป็นนำเครื่องหมายดอกจันทร์ (*) นำหน้าตัวแปรที่เก็บค่าแอดเดรสตัวแปร ดังตัวอย่างในภาพที่ 6.2
5534
Beth = *Ted // Beth มีค่าเท่ากับ ค่าที่ตัวแปร Ted ชี้ซึ่งเท่ากับ 25 ตัวพอยเตอร์จะใช้กับตัวแปรชนิดใดก็ได้โดยที่ ตัวแปรพอยเตอร์ดังกล่าวจะได้รับการกำหนดหน่วยความจำตามลักษณะชนิดตัวแปรด้วย เช่น ตัวแปรพอยเตอร์ประเภท int จะได้รับการกำหนดหน่วยความจำไว้ที่ 4 ไบต์ ตัวอย่างการกำหนด ค่า Pointer จะแสดงให้เห็นดังนี้ โดยผลการกำหนดค่าจะแสดงให้เห็นในภาพที่ 6.3 สังเกตให้ดีจะพบว่า ตำแหน่งแอดเดรสหน่วยความจำเลื่อนไป 4ไบท์ ระหว่างตัวแปร j กับ k และ ตัวแปร k กับ ptr
5535
จากตัวแปรพอยเตอร์สู่ตัวแปรอาเรย์ (Pointer to Array) ตัวแปรอาเรย์มีความเกี่ยวข้องสัมพันธ์กับตัวแปรพอยเตอร์คือ ชื่อตัวแปรอาเรย์ (Array identifier) จะมีค่าเทียบได้กับตำแหน่งแอดเดรสของตารางช่องแรกซึ่งเทียบได้กับตำแหน่งแรก ตัวแปรพอยเตอร์ จะมีค่าเท่ากับแอดเดรสของตัวแปรแรกที่ตัวแปรพอยเตอร์ชี้ ดังตัวอย่างต่อไปนี้
int Num[20]; int *Ptr;

 การกำหนดค่าต่อไปนี้ถือว่าใช้ได้เหมือนกัน
 Ptr = Num; มีลักษณะเท่าเทียมกับ Ptr = &Num[0];
ความแตกต่างจะเกิดขึ้นเมื่อ มีการกำหนดค่าตัวต่อไป โดยที่เราสามารถกำหนดค่าแอดเดรสใหม่ให้ตัวแปร Ptr ได้ทันที ขณะที่ ตัวแปร Num จะชี้ไปที่ตำแหน่งแรกของตัวแปรจำนวนเต็ม ซึ่งมี 20 ตำแหน่งเสมอ ดังนั้น ตัวแปร Ptr จึงเป็นตัวแปรพอยเตอร์ที่เปลี่ยนตำแหน่งการชี้ได้ (Variable Pointer) ขณะที่ตัวแปร Num หรือชื่อตัวแปรอาเรย์เป็นตัวแปรพอยเตอร์ที่ตำแหน่งการชี้คงที่ตายตัว (Constant pointer) ดังตัวอย่างต่อไปนี้
int Num[20]; int *y; int *Ptr;
 Ptr = Num;
 *(Ptr+1) จะแสดงค่า Num[1];
 *(Ptr+i) จะแสดงค่า Num[i];
 y = &Num[0];
 y++;  // ตัวแปรนี้จะชี้ไปที่ Num[1] เท่านั้น
ตัวอย่างต่อไปนี้แสดงให้เห็นถึงการ ใช้ตัวแปรพอยเตอร์ชี้ไปที่ตัวแปรตารางอาเรย์ ซึ่งผลที่ได้จะแสดงให้เห็นในภาพที่ 6.4
5536
ให้ผู้อ่านลองเปลี่ยนคำสั่งในบรรทัด B เป็น printf(“ptr + d = %dn“”, i.*ptr++); ก่อนการทดสอบครั้งต่อไป เพื่อดูว่าโปรแกรมจะให้ผลออกออกมาผิดจากโปรแกรมเดิม เมื่อทดสอบแล้ว ให้ ลองแก้บรรทัด B อีกครั้งโดยแก้เป็น printf(“ptr + d = %dn“”, i.*(++ptr)); ในการกำหนดค่าให้ตารางอาเรย์แต่ละช่องโดยใช้ตัวแปรพอยเตอร์ นั้นทำได้โดยการใช้วงเล็บครอบตัวแปรอาเรย์ที่ตามด้วยเครื่องหมายบวกและตัวเลขแสดงดัชนีพร้อมใช้เครื่องหมายดอกจันทร์ (*) นำหน้า เนื่องจากวิธีดังกล่าวจะเหมือนกับการใช้เครื่องหมาย [] และเลขดัชนี เพื่อเข้าถึงข้อมูลในตัวแปรอาเรย์ดังตัวอย่างต่อไปนี้ *(array+5) = 50 จะมีค่าเทียบเท่ากับ array[5] = 50; ส่วนในการกำหนดและเปลี่ยนแปลงค่าโดยใช้ตัวแปรพอยเตอร์นั้นทำได้ดังโปรแกรมต่อไปนี้
void main(void)
{
 int i, j=1,k=2;
 int *ptr1, *ptr2; // Declare both variables as integer pointers
 float value[100], result[100];
 float *ptr3, *ptr4; // Declare both variables as integer pointers

 prt1 = &j;  // Defining ptr1 pointing to j 
ptr2 = &k;  // Defining ptr2 pointing to k
 ptr3 = value;  // ptr3 contain the address for the 1st element of value
 ptr4 = &value[0]; //  ptr4 contain the address for the 1st element of value

 // Value manipulation
*ptr1 = *ptr1+2  /* การบวกค่าที่ตัวแปรพอยเตอร์ ptr ชี้ไป อีก 2 */
*ptr2 = *ptr1  /* กำหนดให้ค่าที่ ตัวแปร ptr2 ชี้ เท่ากับค่าที่ตัวแปร prt1 ชี้ */
k = *ptr2  /* กำหนดให้ k มีค่าเท่ากับ ค่าที่ตัวแปร ptr2 ชี้ */ 
}
การเปลี่ยนแปลง ตัวแปรพอยเตอร์ด้วยวิธีการทางคณิตศาสตร์ สามารถทำได้ดังตัวอย่างต่อนี้
float *ptr3, *ptr4; float table[100];  float Pi = 3.1415927;
ptr3 = &table[0]; // กำหนดให้ ptr3 เก็บค่าตำแหน่งแอดเดรส ของตาราง table ช่องแรก
ptr3++; // เปลี่ยนค่าตำแหน่งแอดเดรส ใน ptr3 เป็นแอดเดรสตาราง table ช่องที่2 
*ptr3 = Pi;  // ข้อมูลช่องที่ 2 ของตาราง table มีค่าเท่ากับ Pi   
ptr3+=25;  // กำหนดให้ ptr3 ชี้ไปที่ตำแหน่งแอดเดรสตาราง table ช่องที่ 26 
*ptr3 = 2.2222;  // ข้อมูล ตาราง table ช่องที่ 26 มีคาเท่ากีบ 2.2222  

ptr3 = table;  // กำหนดให้ ptr3 ชี้ไปที่ table ช่องแรก
 for(int ii =0; ii < 100; ii++)
 {
  *ptr3++ = 37.0 // กำหนดให้ข้อมูลทุกช่องของ ตาราง table เท่ากับ 37 
}
ptr3 = &table[0]; //  ptr3 contain the address for the 1st element of value
ptr4 = &table[0]; //  ptr4 contain the address for the 1st element of value
ข้อพึงระมัดระวังคือ เครื่องหมาย ++ และ -– นั้นมีลำดับความสำคัญที่สูงกว่า * ดังนั้น *ptr++ มีค่าเท่ากับ *(ptr++) ซึ่งตัวแปรทั้ง 2 หมายถึงการเพิ่มตัวเลขตำแหน่ง แอดเดรส ไม่ใช้เพิ่มค่าที่ตัวพอยเตอร์ชี้ ส่วนกรณี *p++ = *q++ นั้น การกำหนดให้ค่าที่ตัวแปรพอยเตอร์ p มึค่าเท่ากับ ค่าที่ตัวแปรพอยเตอร์ q ชี้ จากน้นจึงมีการเลื่อนตำแหน่งแอดเดรสของตัวแปรพอยเตอร์ทั้ง 2 ไปอีก 1 ช่วง ดังตัวอย่างต่อไปนี้ *p = *q; p++; q++; ในการเตรียมพื้นที่ตารางแบบไดนามิกให้ตัวแปรพอยเตอร์นั้นทำได้ดังนี้ กรณี C: int *ptr; Ptr = (int *)malloc(6* sizeof(int)); กรณี C++: int *ptr; ptr = new int[6]; ส่วนการคืนหน่วยความจำเมื่อสิ้นสุดการทำงานของโปรแกรมทำได้ดังนี้ ซึ่งต้องทำทุกครั้งเมื่อใช้คำสั่งออกจากโปรแกรม มิฉะนั้นเครื่องคอมพิวเตอร์ จะเกิดอาการค้าง (Hang) เมื่อปิดโปรแกรมเพราะไม่ได้คืนหน่วยความจำอย่างที่ควรจะทำ กรณี C: free(ptr); กรณี C++: delete[] ptr; ตัวแปรพอยเตอร์และการเรียกฟังก์ชัน การเรียกฟังก์ชันมีหลายแบบ ได้แก่ 1) ฟังก์ชันที่ ไม่มีตัวแปรร่วมเป็นอาร์กิวเมนต์ และ ไม่คืนค่า (function with no parameter and no return value) ฟังกชันพวกนี้เพีบงแต่มีหน้าที่ทำงานอะไรบางอย่างตามที่ผู้เขียนโปรแกรมต้องการ เช่นกรณีฟังก์ชัน void skip3(void) เพื่อการกระโดดไปครั้งละ 3 บรรทัดเป็นต้น 2) ฟังก์ชันที่มีตัวแปรร่วมแต่ไม่คืนค่า ฟังก์ชันนี้จะทำงานตามค่าที่ตัวแปรร่วมกำหนด เช่นกรณีฟังก์ชัน void skip(int num) ซึ่งจะกระโดดครั้งละกี่บรรทัดตามจำนวนที่กำหนดลงในตัวแปร num 3) ฟังก์ชันที่ไม่มีตัวแปรร่วมแต่มีการคืนค่า ฟังก์ชันนี้มักจะให้ผู้ใช้โปรแกรมป้อนข้อมูลให้ฟังก์ชันจัดการประมวลผล ก่อนที่จะคืนค่าออกมา เช่นกรณีฟังก์ชัน float input(void) ที่จะคืนค่าหลังจากผู้ใช้โปรแกรมได้ป้อนข้อมูลให้ตามที่ฟังก์ชันสั่งให้ทำแล้ว 4) ฟังก์ชันที่มีตัวแปรร่วมและมีการ คืนค่า เช่นกรณีฟังก์ชัน float diff(float x, float y) ที่จะคืนค่าเป็นผลต่างระหว่างตัวแปร x และ ตัวแปร y ส่วนฟังก์ชันที่มีการใช้ตัวแปรร่วม นั้น มีวิธีการเรียกอยู่ 2 แบบคือ 1) กรณี เรียกตามค่า (Call by Value) กรณีนี้การเปลี่ยนค่าตัวแปรร่วมที่เกิดขึ้นในฟังก์ชัน จะไม่มีผลต่อ ค่าตัวแปรร่วมตั้งต้นดังตัวอย่างต่อไปนี้
void skipline(int num)
{
 int i ;
 for(i = 0 ; i <=num-1 ; i++)
 {
  printf(“n”);
}
num = 100;
}
void main(void)
{
 int num1 = 60;
 printf(“%d”,num1);
 skipline(num1) ;
}
กรณี เรียกตามค่านี้ ค่า num มีการเปลี่ยนแปลง แต่ไม่มีผลต่อค่า num1 ใน main function ตัวแปรร่วมในฟังก์ชันจะถือว่าเป็นกรณีเรียกตามค่า เมื่อการใช้ตัวแปรร่วมเป็นไปตามเงื่อนไขต่อไปนี้ • ตัวแปรร่วมนั้นแค่ส่งผ่านข้อมูลไปให้ฟังก์ชัน • ตัวแปรร่วมดังกล่าวจะไม่เป้นตัวแปรที่คืนค่าหลังสิ้นสุดการทำงานของฟังก์ชัน 2) กรณี เรียกตามการอ้างอิง (Call by Reference) ซึ่งต้องมีการเรียกใช้ตัวแปรพอยเตอร์กรณีนี้การเปลี่ยนค่าตัวแปรร่วมที่เกิดขึ้นในฟังก์ชัน จะมีผลต่อ ค่าตัวแปรร่วมตั้งต้นดังตัวอย่างต่อไปนี้
void flip(int *x, int *y)
{
 int temp;
 temp = *x;
 *x = *y;
 *y = temp; 
}
ในการเรียกใช้ฟังก์ชัน flip นั้น จะต้องเรียกจาก แอดเดรสตัวแปร ดังนี้ flip(&a,&b) มีบางกรณีที่มีการ เรียกตามค่าและเรียกตามการอ้างอิงในฟังก์ชันเดียวกันเช่นการแก้สมการกำลัง 2
bool quardsolve(float a, float b, float c, float *root1, float *root2)
{
 float disc = (b*b) – (4*a*c);
 if(disc < 0.0)
 {
  return false;
} 
else
{
 *root1 = (-b + sqrt(disc))/(2*a);
 *root2 = (-b – sqrt(disc))/(2*a);
 return true;
}
}
ตัวแปรดัชนี root1 และ root2 ทำหน้าที่เป็นตัวแปรร่วม Output ที่เรียกโดยการใช้อ้างอิง (Call by Reference) และ ตัวแปร a b c เป็นตัวแปรร่วม Input ที่ใช้กับการเรียกตามค่า (Call by Value) ถ้า การแก้สมการกำลัง 2 มีคำตอบให้คืนค่าเป็น true และ ค่า root1 และ root2 เป็นจำนวนจริง มิฉะนั้นให้ฟังก์ชันคืนค่า false ออกมาแทน เนื่องจาก ค่า root1 และ root2 นั้นได้รับการประกาศให้เป็น ตัวแปรร่วมอ้างอิง (Reference parameter) มีผลทำให้ฟังก์ชันต้นแบบ (Function Prototype) มีลักษณะเป็น bool quardsolve(float, float, float, float *, float *) เมื่อเรียกใช้งานฟังก์ชัน quardsolve ให้เรียกใช้งานฟังก์ชันดังนี้ float x1, y1; float test = quardsolve(1.0,2.0,1.0,&x,&y); ซึ่งการเรียกใช้ฟังก์ชันดังกล้าวคล้ายคลึงกับการเรียกใช้คำสั่ง scanf int number; scanf(“%d”, &number); ตัวอย่างการเรียกใช้ฟังก์ชันที่มีตัวแปรพอยเตอร์จะแสดงให้เห็นดังตัวอย่างต่อไปนี้ 1) ฟังก์ชันที่ มี ตัวแปรพอยเตอร์ที่แสดงในภาพที่ 6.5 นั้น จะอยู่ที่ฟังก์ชัน cal_cum โดยในฟังก์ชัน cal_sum มี ตัวแปร a และ b เป็น ตัวแปร input ขณะที่ตัวแปรพอยเตอร์ *r เป็นตัวแปร output เวลาเรียกใช้งานฟังก์ชัน cal_sum ในฟังก์ชัน main จะเรียกใช้งานดังนี้ double num1 = 2.4, num2 = 1.2,result; cal_cum(num1,num2,&result); แอดเดรสของตัวแปร result (&result) จะมีค่าเท่ากับชื่อตัวแปรพอยเตอร์ แม้ว่าตัวแปร result จะไม่ใช่ตัวแปรพอยเตอร์ก็ตาม 2) ฟังก์ชันที่มี ตัวแปรพอยเตอร์ที่แสดงในภาพที่ 6.6 นั้น จะอยู่ที่ฟังก์ชัน order ซึ่งใช้ตัวแปรพอยเตอร์ เป็น input และ output ทั้งคู่ ฟังก์ชัน order จะทำหน้าที่ จากเล็กไปหาใหญ่ โดยที่ ถ้า ค่าที่ตัวแปรพอยเตอร์ *small ชี้ขนาดใหญ่กว่าค่าที่ตัวแปรพอยเตอร์ *big ชี้ ให้ลงมือสับตำแหน่งการชี้ค่า
5537


หน้าที่ 8 - ตัวแปรสตริง
7. ตัวแปรสตริง (String) ตัวแปร string หรือแถวตารางอาเรย์ของตัวหนังสือนั้น ภาษา C ไม่มีกลไกที่จะสนับสนุนได้โดยตรง ถ้าต้องการให้ภาษา C สามารถรองรับข้อมูลที่เป็นตัวหนังสือแล้ว จะต้องมีการเตรียมพื้นที่หน่วยความจำให่เหมาะสมหรือการใช้สตริงค่าคงที่ (strong constant) ซึ่งจะทำให้โปรแกรมภาษา C เข้าถึงข้อมูลสตริงซึ่งจะเป็นทั้งข้อมูลที่เข้ามาในโปรแกรมและเปป็นข้อมูลที่ออกจากโปรแกรมได้ โดยทั่วไปแล้วโปรแกรมภาษา C จะสนับสนุนข้อมูลที่เป็นอักษรโดยกำหนดให้อักษรแต่ละตัว ในรูปแบบตัวแปรประเภท char และข้อมูลสตริงนั้นโปรแกรมที่เขียนด้วยภาษา C จะถือว่าเป็นชุดข้อมูลตัวหนังสือที่เรียงกันตามลำดับ ขณะที่โปรแกรมที่เขียนด้วยภาษา C++ จะถือว่าสตริงเป็นตารางอาเรย์ข้อมูลประเภทตัวหนังสือ (Array of char) โดยตัวหนังสือจะอยู่ในตารางแต่ละช่อง และ ณ ตำแหน่งสิ้นสุดของตารางอาเรย์ที่เก็บตัวแปรสตริงนั้นจะมีสัญลักษณ์ “{PBODY}” (ตัวสิ้นสุดสตริง หรือ ตัว NULL) บรรจุอยู่ ดังนั้น ในการเตรียมเนื้อที่สำหรับตัวแปรสตริงที่ประกอบด้วยตัวหนังสือ n ตัวนั้นจะต้องเตรียมตารางไดนามิกขนาด n+1 ช่องเสมอ ดังตัวอย่างต่อไปนี้ 1) ตัวหนังสือ ‘a’ เป็นตัวแปร char จะใช้เนื้อที่ 1 ไบต์ แต่ “a” เป็นตัวแปร string แล้ว จะต้องใช้เนื้อที่ขนาด 2 ไบต์เพื่อจุตัวอักษร ‘a’ และ ตัวสิ้นสุดสตริง ({PBODY}) 2) ตัวแปรสตริงสามารถประกาศให้อยู่ในรูปตารางต่อไปนี้ได้ a. ตารางอาเรย์ตัวหนังสือ char String1[10] สามารถรองรับตัวหนังสือได้มากที่สุด 9 ตัว และ ตัวสิ้นสุดสตริง b. ตัวแปรพอยเตอร์ตัวหนังสือ char *String2 สามารถรองนับตัวหนังสือได้ตามที่ผู้เขียนโปรแกรมได้เตรียมเนื้อที่ตารางไดนามิกส์ไว้ ถ้าต้องการทำอะไรกับตัวแปรสตริงแล้วให้เรียกใช้เฮดเดอร์ไฟล์ string.h ซึ่งเป็นไลบรารีไฟล์มาตรฐานสำหรับจัดการกับตัวแปรสตริง เราสามารถตั้งค่าเริ่มต้นให้ตัวแปรสตริงได้ 2 วิธีหลักคือ char S1[] = “Example”; ซึ่งภายในตัวแปรประกอบด้วย S1 |E|x|a|m|p|l|e|{PBODY}| ทั้งนี้เนื่องจากการเตรียมพื้นที่ขนาด 8 ช่องตาราง โดย 7 ช่องตารางแรกเก็บตัวหนังสือ และ ข้อมูลช่องสุดท้ายเก็บตัวสิ้นสุดสตริง char S2[20] = “Another Example”; ซึ่งภายในตัวแปรประกอบด้วย
S2            |A|n|o|t|h|e|r| |E|x|a|m|p|l|e|{PBODY}||?|?|?|?| 
ทั้งนี้เนื่องจากการเตรียมพื้นที่ขนาด 20 ช่องตาราง แต่ใช้จริง 16 ช่อง คือตัวหนังสือ 15 ช่องและ ช่องที่ 16 เก็บตัวสิ้นสุดสตริง การตั้งต้นตัวแปรสตริง ดังตัวอย่างต่อไปนี้ถือว่าเป็นการตั้งต้นตัวแปรสตริงที่ถูกต้อง
5538
ดังนั้น สิ่งที่เกี่ยวข้องสตริงสามารถสรุปออกมาได้ดังนี้ - ตัวแปรสตริงคือ ลำดับตัวหนังสือที่อยู่ภายในเครื่องหมายอัญประกาศ หรือเครื่องหมายคำพูด (“ ”) หรือ ตัวแปรสตริงคงที่ (String Constant) - อีกทางหนึ่งตัวแปรสตริงถือว่าเป็นตัวแปรตารางอาเรย์ ของตัวหนังสือ (Array of char) - สามารถใช้คำสั่ง printf scanf และ print ของภาษา C กับตัวแปรสตริงได้ - การประมวลเท็กซ์ คือการประมวลตัวแปรสตริง - หน่วยข้อมูลพื้นฐานของตัวแปรสตริงคือตัวหนังสือหรือ ชุดตัวหนังสือ ไมใช่ตัวเลข - การประยุกต์ใช้ตัวแปรสตริงนั้นคือ Word Processing หรือ Text Editor ตัวอย่างการใช้ตัวแปรสตริงจะแสดงให้เห็นดังนี้
#include  
void main()
{
 char first[100], last[100];
 int i;

 printf("nEnter your first name:");
 scanf("%s", first );
 printf("nEnter your last name:");
 scanf("%s", last );
 printf("nYour full name is: %s %sn", first, last );
 printf("First name is: ");
 for( i=0; (i<100 && first[i] != '{PBODY}') ; i++ ){
    printf("%c ",first[i]);
 }
 printf("nLast name is: ");
 for( i=0; (i<100 && last[i] != '{PBODY}') ; i++ ){
    printf("%c ",last[i]);
 }
 printf("n");
} 
ผลที่ได้การเขียนโปรแกรมเติมชื่อและนามสกุลจะแสดงให้เห็นในภาพที่ 7.1
5539
การใช้งานตัวแปรสตริงนั้นมีหลักการดังนี้ - เตรียมพื้นที่ตารางอาเรย์ให้ใหญ่พอรับตัวหนังสือแทนคำและ ตัวสิ้นสุดสตริงดังต่อไปนี้ char str1[6] = “Hello”; char str2[] = “Hello”; char *str3 = “Hello”; char str4[6] = {‘H’,’e’,’l’,’l’,’o’,’{PBODY}’}; ตัวแปรสตริงแต่ละตัวถือว่าเป็นตัวแปรคงที่ ดังนั้นจึง Assign ค่าแทนกันเช่นตัวอย่างต่อไปนี้ไม่ได้ Str1 = Str2; // ห้ามทำเช่นนี้กับตัวแปรสตริง เพราะมีวิธีอื่นที่ดีกว่านั้น ตัวอย่างต่อไปนี้แสดงให้เห็น วิธี Assign ตัวแปรสตริงโดยใช้ตัวแปรพอยเตอร์ เข้าช่วย char *S1 = “Hello”, *S2 = “Goodbye”; // ตัวแปร S1 และ S2 แก่ไขเปลี่ยนแปลงไม่ได้ char *S3; S3 = S1; // บังคับให้ S3 ชี้ไปที่ แอดเดรสของตัวแปรพอยเตอร์ S1 S3 = S2; // บังคับให้ S3 ชี้ไปที่ แอดเดรสของตัวแปรพอยเตอร์ S2 อีกตัวอย่างในการ Assign ตัวแปรสตริงสามารถแสดงให้เห็นดังนี้ char Str[6] = “Hello”; // ตั้งต้นตัวแปร Str ด้วยคำว่า Hellow char Str[0] = ‘Y’; char Str[4] = ‘{PBODY}’; // การแก้ไขให้ Str = “Yell” อย่างไรก็ตาม วิธีแก้ไขเปลี่ยนแปลงข้อมูลสตริงในตารางมีเงื่อนไขว่า - ตารางอาเรย์ที่ทำหน้าที่เป็นสตริงจะต้องปิดท้ายด้วย ‘{PBODY}’ เสมอ มิฉะนั้นตัวแปรอาเรย์ที่ทำหน้าที่เป็นสตริงจะไม่มีจุดสิ้นสุดสตริง - สตริงที่แก้ไขต้องมีขนาดน้อยกว่าขนาดของตารางอาเรย์ที่เก็บค่าสตริง การเปลี่ยนแปลงแก้ไขตัวแปรสตริงโดยใช้ไดนามิกอาเรย์นั้นต้องใช้ความระมัดระวังเป็นอย่างยิ่ง เพราะตารางไดนามิกส์นั้นต้องเตรียมพื้นที่ให้ ตัวสิ้นสุดสตริง (NULL) มิฉะนั้นโปรแกรมจะพิมพ์ข้อมูลสตริงออกมาผิดไปจากที่ต้องการ ดังตัวอย่างต่อไปนี้
char *s; 
 s = (char *)malloc(sizeof(char) * 0); // - WRONG, need to allocate 1 more space
 strcpy(s, "linux"); 
 printf("%sn", s);  
กรณีที่ใช้คำสั่ง strlen เพื่อหา ขนาดอาเรย์ก่อนทำ Dynamic allocation (malloc) นั้น พึงรับทราบว่า คำสั่ง strlen จะมีขนาดเพียงพอสำหรับตัวจำนวนอักษรที่ใช้ในตัวแปรสตริงเท่านั้น แต่ไม่ได้นับตัวแปร NULL ที่ใช้กำหนดจุดสิ้นสุดของสตริงด้วย โดยที่รายละเอียดเกี่ยวกับคำสั่ง strlen จะกล่าวถึงในตอนต่อไป การกำหนดค่าให้ตัวแปรสตริง (String Assignment) ตัวอย่างการกำหนดค่าให้ตัวแปรสตริง
char s[5]="SIIT";       // ใช้ได้, กำหนดค่าตัวแปรสตริงให้ตัวแปรอาเรย์
 char dept[5], *d=dept;  // ใช้ได้, กำหนดค่าตัวแปรสตริงให้ตัวแปรพอยเตอร์
 char name[20];
 name = “C. Sinthanayothin"; // ผิด อย่ากำหนดตัวแปรสตริงให้ตัวแปรอาเรย์ด้วยวิธีนี้
 strcpy(name,“C. Sinthanayothin"); // ใช้ได้, ให้ก๊อปปี้ค่าสตริงโดยใช้คำสั่ง strcpy  
 strcpy(dept,"IT");  // ใช้ได้, ก๊อปปี้ค่าสตริง ลงในตัวแปร dept
 printf("%s %s %sn",d,s,dept); // ใช้ได้, แสดงผลค่าสตริงด้ว printf
 d = strcpy(s,"EE");  // ใช้ได้, นี่คือการคืนค่าตัวแปรสตริง ลงใน ตัวแปร d ด้วยคำสั่ง strcpy
 printf("%s %s %s %sn",name,d,s,dept);

 char c1[30], c2[30]=“This is new c1 string”;
 char s[30] = "c programming "; 
 char str1[30];  // วิธี้ทำให้ตัวแปร str1 ไม่เป็น l-value เพราะเป็น constant array
 char *str; // วิธี้ทำให้ตัวแปร str เป็น l-value เพราะเป็น ตัวแปรพอยเตอร์ 
 strcpy(c1, c2);   // ใช้ได้, ก๊อปปี้ข้อมูลใน c2 ลงใน c1
 str = strcat(s,"is great!!"); // ใช้ได้, คือค่าเป็น ตัวแปรพอยเตอร์ประเภท char 
 str1 = strcat(s,"is great!!"); // ผิด, ฟังก์ชัน strcat ตอ้งคืนค่าด้วยตัวแปรพอยเตอร์ประเภท char ไม่ใช่ตารางอาเรย์ประเภท char
ข้อควรจำคือ: ต้องเตรียมพื้นที่หน่วยความจำไว้ให้พร้อมก่อนการกำหนดค่าให้ตัวแปรสตริงมิฉะนั้นอักษรบางตัวก็จะแหว่งหายไป ตัวแปรสตริงนั้นจะใช้ %s เป็นตัว place holder ขณะที่ใช้คำสั่ง sscanf ในการอ่านข้อมูลจำพวกสตริงแล้วจัดการแปลงข้อมูลให้อยู่รูปตามที่กำหนด ดังตัวอย่างต่อไปนี้
int sscanf( const char *buffer, const char *format [, argument ] ... ); 

char ch, int inum, float fnum; 
char buffer[100] = “A10 50.0”;
sscanf(buffer,”%c%d%f”,&ch,&inum,&fnum); /* puts ‘A’ in ch, 10 in inum and 50.0 in fnum */

sscanf("  85  96.2  hello","%d%.3lf%s",&num,&val,word);

// results: num=85, val = 96.2, word = "hello"
  ส่วน sprintf ใช้แสดงผลลัพธ์ที่อยู่ในรูปแบบต่างๆ ให้เป็นตัวแปรสตริงดังตัวอย่างต่อไปนี้
int sprintf( char *buffer, const char *format [, argument] ... );

char buffer[100];
sprintf(buffer,”%s, %s”,LastName,FirstName);
if (strlen(buffer) > 15)
  printf(“Long name %s %sn”,FirstName,LastName);
ถ้าต้องการแปลงตัวเลขให้เป็นข้อมูลสตริงให้ใช้ฟังก์ชัน sprintf และ ตัวแปรดัชนี้ char ทำตามคำสั่งต่อไปนี้
int sscanf(char *buffer, const char *format [, argument ] ... ); 
char S[10]; int day, month,year;
sprintf(S,”%d/%d/%d”, day, month, year);
ถ้า day = 23, month = 8, year = 2001 ผลลัพธ์คือ S = “23/8/2001”
ต่อไปนี้คือตัวอย่างการใช้ sprintf กับ sscanf เมื่อเปรียบเทียบกับ printf
#include 
#include 
int main()
{
 char s[30]="85  96.2  hello";
 int num, mon=8,day=23,year=2001;
 double val;
 char word[10];  // can we use: char *word;   
  // make sure your assign the proper address for pointer
 sscanf("  85  96.2  hello","%d%lf%s",&num,&val,word);
 printf("num=%d   val=%.3lf   word=%sn",num,val,word);
 sprintf(s,"%d/%d/%d", mon, day, year);
 printf("s = %sn",s);
 return 0;
}
ข้อทบทวน: ภาษาซี มีฟังก์ชันที่ใช้ดัดแปลงแก้ไขตัวแปรสตริง หลายแบบตามความต้องการของผู้ใช้ได้แก่: strlen(str) – คำนวณความยาวสตริง ซึ่งจะมีการนับไปเรื่อยๆ จนกว่าจะพบตัวแปร NULL ถึงจะหยุดโดยไม่มีการนับตัวแปร NULL ที่สิ้นสุดประโยคเข้าไปด้วย ดังตัวอย่างต่อไปนี้ int strlen(char *str); char str1 = “hello”; strlen(str1) จะคืนค่าออกเป็น 5 เพราะ มีอักษร 5 ตัว strcpy(dst,src) – ก็อปปี้ข้อมูลจากตัวแปรสตริง src พร้อมตัวสิ้นสุดสตริง NULL ไปที่ตัวแปรสตริง dst แต่มีเงื่อนไขว่าตัวแปร des ต้องได้รับการเตรียมพื้นที่ให้ใหญ่พอๆกับตัวแปร src และการเตรียมพื้นที่ ให้ ตัวแปร src และ ตัวแปร dst ต้องไม่ทับซ้อนกันมิฉะนั้นจะให้ผลที่คาดเดาไม่ได้ การประกาศใช้ฟังก์ชัน strcpy จะทำได้ดังนี้ char *strcpy(char *dst, char *src) strncpy(dst,src,n) – ก็อปปี้ข้อมูลจากตัวแปรสตริง src โดยไม่ก๊อปปี้ตัวสิ้นสุดสตริง NULL ไปที่ตัวแปรสตริง dst เนื่องจากมีจำนวนตัวอักษร n เป็นตัวจำกัดไว้ แต่มีเงื่อนไขว่าตัวแปร des ต้องได้รับการเตรียมพื้นที่ให้ใหญ่พอๆกับตัวแปร src และการเตรียมพื้นที่ ให้ ตัวแปร src และ ตัวแปร dst ต้องไม่ทับซ้อนกันมิฉะนั้นจะให้ผลที่คาดเดาไม่ได้ การประกาศใช้ฟังก์ชัน strncpy จะทำได้ดังนี้ char *strncpy(char *dst, char *src, int n) strcmp(str1,str2) – เปรียบเทียบข้อมูลในตัวแปร str1 กับข้อมูลในตัวแปรสตริง str2 โดยใช้อักษรตัวแรกที่เริ่มต่างกันเป็นหลักซึ่งให้ผลดังนี้ น้อยกว่า 0 -- ถ้าค่า ASCII ที่เริ่มแตกต่างใน str1 มีขนาดเล็กกว่า str2 หรือ str1 เริ่มต้นเหมือนกับ str2 แต่ str2 นั้นมีตัวอักษรมากกว่า มากกว่า 0 -- ถ้าค่า ASCII ที่เริ่มแตกต่างใน str1 มีขนาดใหญ่กว่า str2 หรือ str1 เริ่มต้นเหมือนกับ str2 แต่ str1 นั้นมีตัวอักษรมากกว่า 0 ถ้าตัวแปรสตริงทั้ง 2 ตัวนั้นใช้ตัวอักษรเดียวกันและความยาวเท่ากัน การประกาศใช้ฟังก์ชัน strcmp จะทำได้ดังตัวอย่างต่อไปนี้
int strcmp(char *str1, char *str2) 
#include 
#include 
void main()
{
 printf("%d n", strcmp("hello","hello")); // returns 0
 printf("%d n", strcmp("yello","hello")); //returns value > 0
 printf("%d n", strcmp("Hello","hello")); // returns value < 0
 printf("%d n", strcmp("hello","hello there")); // returns value < 0
 printf("%d n", strcmp("some diff","some dift")); //returns value<0
}
strncmp(str1,str2,n) – เปรียบเทียบข้อมูลในตัวแปร str1 กับข้อมูลในตัวแปรสตริง str2 เป็นจำนวนอักษร n ตัวโดยใช้อักษรตัวแรกที่เริ่มต่างกันเป็นหลัก และ จะมีการเปรียบเทียบในกรณีที่อักษรในตัวแปรมีจำนวนน้อยกว่า n การประกาศใช้ฟังก์ชัน strncmp จะทำได้ดังตัวอย่างต่อไปนี้ int strncmp(char *str1, char *str2,int n) ความแตกต่างระหว่าง strcmp และ strncmp จะแสดงให้เห็นดังตัวอย่างต่อไปนี้ strcmp(“some diff”,”some DIFF”) -- returns value > 0 strncmp(“some diff”,”some DIFF”,4) -- returns 0 strcat(str1,str2) – ใช้ในการนำข้อมูลในตัวแปร str2 ไปต่อท้ายตัวแปร str1 ซึ่งจะคืนค่าเป็น str1 ที่ได้รับการต่อให้ยาวขึ้น ตัวอย่างเช่น char *s1 = “C. “, *s3 = strcat(s1,“Sinthanayothin”); ผลลัพธ์: s1 = s3 = “C. Sinthanayothin” การประกาศใช้ฟังก์ชัน strcat จะทำได้ดังตัวอย่างต่อไปนี้ char* strcat(char *s1, const char* s2); strncat(str1,str2,n) – ใช้ในการนำข้อมูลในตัวแปร str2 จำนวน n อักษรไปต่อท้ายตัวแปร str1 ซึ่งจะคืนค่าเป็น str1 ที่ได้รับการต่อให้ยาวขึ้น ตัวอย่างเช่น char s1[10] = "IT "; char *s3 = strncat(s1,"050Basic",3); printf("%s n", s1); printf("%s n", s3); ผลลัพธ์: s1 = s3 = IT 050 การประกาศใช้ฟังก์ชัน strncat จะทำได้ดังตัวอย่างต่อไปนี้ char* strncat(char *s1, const char* s2ม int n); ฟังก์ชันเหล่านี้มีอยู่ในไลบรารีเฮดเดอร์ไฟล์ string.h ซึ่งต้องใช้คำสั่ง #include ถึงจะเรียกใช้ได้ เราสามารถสร้างตารางอาเรย์ให้ตัวแปรสตริง (Array of string) ดังตัวอย่างต่อไปนี้ char month[12][10] = {“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December” }; แต่ถ้าต้องการให้ตารางอาเรย์สำหรับตัวแปรสตริง สามารถรองรับข้อมูลสตริงที่มีความยาวต่างกัน (Ragged array of string) ให้ดังนี้ char *MonthNames[13]; /* an array of 13 strings */ MonthNames[1] = “January”; /* String with 8 chars */ MonthNames[2] = “February”; /* String with 9 chars */ MonthNames[3] = “March”; /* String with 6 chars */ … ตัวอย่างตารางอาเรย์ให้ตัวแปรสตริงแสดงวันทั้ง 7 แบบ Ragged array of string จะแสดงให้เห็นในตัวอย่างต่อไปนี้
#include 
#include 
void main() 
{
  char *days[7]; char TheDay[10];int day;
  days[0] = "Sunday"; days[1] = "Monday";
  days[2] = "Tuesday"; days[3] = "Wednesday";
  days[4] = "Thursday"; days[5] = "Friday";
  days[6] = "Saturday";
  printf("Please enter a day: ");
  scanf("%9s",TheDay);
  day = 0;
  while ((day < 7) && (strcmp(TheDay,days[day])))
        day++;
  if (day < 7) printf("%s is day %d.n",TheDay, day);
  else printf("No day %s!n",TheDay);
} 
ในการรับและส่งข้อมูลจำพวกสตริงนั้นทำได้หลายวิธี ได้แก่ 1) ในกรณีที่ใช้คำสั่ง printf และ scanf นั้นให้ใช้ %s ในการอ่านข้อมูลและ แสดงข้อมูลสตริงออกมา 2) ใช้คำสั่ง gets ในการข้อมูลสตริงออกมาทีละบรรทัด ดังตัวอย่างต่อไปนี้ char name1[10], name2[30]; scanf(“%s”,name1); // Input: IT 050 gets(name2); // Input: C Programming printf(“Course is %sn”,name); // Output: IT 050 printf(“Detail is %sn”,name2); // C Programming
5540
การใช้งานคำสั่งกับตัวแปร อักษร (char operators) นี่คือตัวอย่างการใช้งานฟังก์ชันที่คุมการรับส่งข้อมูลตัวอักษร char ch; ch = getchar(); // Input ch – ใช้แทน scanf("%c",&ch); putchar(ch); // Output ch – ใช้แทน printf("Character is %cn",ch); ch = 'S'; // ใช้ได้ ตัวอย่างการกำหนดค่าตัวอักษรให้ตัวแปร char putchar(ch); // ผลที่ได้ออกมาคือ S putchar('T'); // ผลที่ได้ออกมาคือ T ฟังก์ชันที่ใช้กำหนดการทำงานให้ตัวแปร char ได้แก่ คำสั่ง: isalpha(ch); การใช้งาน: คืนค่าเป็น TRUE (จริง) ถ้า ch มีค่าในช่วง A-Z หรือ a-z ตัวอย่าง: c = isalpha(ch); // คืนค่า TRUE ถ้า ch=‘M’ และ คืนค่า FALSE ถ้า ch=‘5’ คำสั่ง: isdigit(ch); การใช้งาน: คืนค่าเป็น TRUE (จริง) ถ้า ch มีค่าในช่วง0-9 ตัวอย่าง: d = isdigit(ch); // คืนค่า FALSE ถ้า ch=‘M’ และคืนค่า TRUE ถ้า ch=‘5’ คำสั่ง: islower(ch); การใช้งาน: คืนค่าเป็น TRUE (จริง) ถ้า ch มีค่าในช่วง a-z ตัวอย่าง: c = islower(ch); // คืนค่า FALSE ถ้า ch=‘M’ return false, และคืนค่า TRUE ถ้า ch=‘m’ คำสั่ง: isupper(ch); การใช้งาน: คืนค่าเป็น TRUE (จริง) ถ้า ch มีค่าในช่วง A-Z ตัวอย่าง: c = isupper(ch); // คืนค่า TRUE ถ้า ch=‘M’ return false, และคืนค่า FALSE ถ้า ch=‘m’ คำสั่ง: isspace(ch); การใช้งาน: คืนค่า TRUE ถ้า ch คิอช่องว่างขาว (space, newline, tab ) ตัวอย่าง: c = isspace(ch); // คืนค่า TRUE ถ้า ch = ‘n’ คืนค่า FALSE ถ้า ch=‘m’ คำสั่ง: tolower(ch); การใช้งาน: คืนค่าตัวพิมพ์เล็กจากค่าอักษรในตัวแปร ch ถ้าเป็นไปได้ ตัวอย่าง: c = tolower(ch); // คืนค่า ‘m’ ให้ c ถ้า ch=‘M’ คำสั่ง: toupper(ch); การใช้งาน: คืนค่าตัวพิมพ์ใหญ่จากค่าอักษรในตัวแปร ch ถ้าเป็นไปได้ คำสั่ง: c = toupper(ch); // คืนค่า ‘M’ ให้ c ถ้า ch=‘m’
หน้าที่ 9 - โครงสร้างสตรักเจอร์
8. โครงสร้างสตรักเจอร์ (Structure) สตรักเจอร์ เป็นวิธีการเก็บตัวแปรหลากชนิดให้อยู่เป็นกลุ่มก้อนเดียวกัน ทำให้สามารถแยกโปรแกรมออกเป็นหน่วย (Modular Programming) ซึ่งแก้ไขได้ง่ายเพราะสามารถแยกฟังก์ชันและตัวแปรออกเป็นหน่วยๆ ซึ่งก็เป็นประโยชน์ในการสร้างฐานข้อมูลด้วย การตั้งต้นสร้างสตรักเจอร์ สามารถทำได้หลายรูปแบบดังตัวอย่างต่อไปนี้ 1) การใช้ คำสั่ง struct สร้างตัวแปรชนิด student_a ผ่านตัวแปร student struct student
{ 
   char *first; 
   char *last; 
   char SSN[9]; 
   float gpa; 
   char **classes; 
}; 
struct student student_a; 2) การใช้ คำสั่ง struct สร้างตัวแปรชนิด student_a โดยตรง struct
{ 
    char *first; 
    char *last; 
    char SSN[10]; 
    float gpa; 
    char **classes; 
} student_a; 
3) การใช้ คำสั่ง typedef struct เพื่อสร้างตัวแปรชนิด student_a ผ่านตัวแปร student typedef struct
{ 
    char *first; 
    char *last; 
    char SSN[9]; 
    float gpa; 
    char **classes; 
} student; 

student student_a;
การกำหนดชนิดตัวแปร ทำได้โดยใช้คำสั่ง typedef ตามหลักการใช้งานดังนี้ typedef type name (typedef ชื่อของชนิดตัวแปร ชื่อที่ใช้เรียกชนิดตัวแปรจริง) ตัวอย่าง:
typedef int INTEGER;
  INTEGER x;  /* x คือตัวแปรตระกูล INTEGER */

  typedef char *STRING;
  STRING sarray[10];  
/* sarray คือตารางอาเรย์ ของ char* ซึ่งเทียบได้กับการประกาศว่า 
char *sarray[10] */
ในโครงสร้างตัวแปรที่อยู่ในรูป structure นั้นประกอบด้วยตัวแปรที่เกี่ยวข้องในลักษณะเดียวกับตารางอาเรย์ แม้จะไม่ใช้ตัวแปรประเภทเดียวกัน โดยจะแบ่งตัวแปรออกเป็น field โดยที่กลุ่มตัวแปรใน structure จะถือว่าเป็นส่วนหนึ่งของหน่วยใหญ่หน่วยเดียวกันดังที่แสดงในภาพที่ 8.1 ส่วนการเปรียบเทียบความแตกต่างระหว่าง ตารางอาเรย์และตัวแปร struct ที่มีตัวแปรที่เป็นตารางอาเรย์ จะแสดงให้เห็นในภาพที่ 8.2
5542
การเรียกใช้งาน สตรักเจอร์ โดยปกติการสร้างสตรักเจอร์ ทำได้โดยใช้คำสั่ง typedef และ struct ซึ่งโครงสร้างภายในของสตรักเจอร์ จะประกอบด้วยตัวแปรต่างๆ ซึ่งแยกออกเป็น field ตัวแปรชนิดต่างๆ และในแต่ละ field จะมีการกำหนดพื้นที่หน่วยความจำ จนเพียงพอสำหรับแต่ละ field ดังตัวอย่างต่อไปนี้
typedef struct {
  Type1 FieldName1;
  Type2 FieldName2;
  Type3 FieldName3;
  /* as needed */
} VarName;
VarName คือชื่อชนิดตัวแปรสตรักเจอร์ทั้งหมด นี่คือตัวอย่างการประกาศใช้ตัวแปร struct ชนิด student_t เพื่อบันทึกข้อมูลนักเรียน พร้อมตัวอย่างการกำหนดตัวแปร ชนิด student_t ซึ่งสามารถทำได้อย่างตัวแปรทั่วไป เช่นเดียวกับ int float
#define   MAX_LEN  12      /*  Length of name  */
typedef   struct  {
   char      name[MAX_LEN];
   int      id;
   float     gpa;
   char major[10];
}  student_t;

student_t   s;
student_t  stu1, stu2, stu3;
การเข้าถึง ตัวแปร field ภายในตัวแปร struct ทำได้โดยการใช้ จุด (.)แล้วตามด้วยชื่อ field ดังตัวอย่างกรณีการเข้าถึงตัวแปร ชนิด DATE ที่จะแสดงให้เห็นดังต่อไปนี้ และผลที่ได้จะแสดงให้เห็นในภาพที่ 8.3 หลักการเข้าถึงตัวแปร struct: VarName.FieldName typedef struct
{
  int month, day, year;
} DATE;

void main() {
  DATE d1;

  d1.month = 12;
  d1.day = 2;
  d1.year = 1970;
}
5543

การติดตั้งไดรเวอร์ เครื่องปริ้น mp258 mp287 mp160 mp150 mp140 หรือตระกูล mp รุ่นอื่นๆ


การติดตั้งไดรเวอร์ เครื่องปริ้น mp258 mp287 mp160 mp150 mp140 หรือตระกูล mp รุ่นอื่นๆ

การติดตั้งไดรเวอร์ปริ๊นเตอร์ ของแคนนอนส่วนมากจะเหมือนๆ กัน คือติดตั้งไดรเวอร์ก่อนจากนั้นค่อยเปิดปริ๊นเตอร์หรือเสียบสาย USB นั่นเอง แต่ถ้าใครยังไม่มี driver canon รุ่นต่างๆ ก็หาดาวน์โหลดได้ในเว็บนี้โดยใช้ช่องค้นหาด้านขวามือครับ หรือดาวน์โหลด mp258  driver canon mp258
วิธีติดตั้ง driver mp258 mp287 mp160 mp150 mp140
วิธีการติดตั้งไดรเวอร์เครื่องปริ้นจริงๆ นั้นก็ไม่ได้ยากเย็นอะไร วิธีการในวิดีโอนี้คือ ในกรณีที่เราไม่มีแผ่นไดรเวอร์และต้องดาวน์โหลดไดรเวอร์มาติดตั้งนั่นเอง ลองดูตามวิดีโอด้านล่างนี้ ไม่ยากครับมือใหม่ด้านคอมพิวเตอร์ทำตามได้สบายๆ …


Read more: http://www.comfixclub.com/%e0%b8%95%e0%b8%b4%e0%b8%94%e0%b8%95%e0%b8%b1%e0%b9%89%e0%b8%87drivermp258-mp287-mp160-mp150-mp140/#ixzz2K0q9jiUD

วิธีติดตั้ง Windows 8


วิธีติดตั้ง Windows 8 แบบ Clean Install ลง Win 8 ง่ายๆไม่ง้อช่าง
ในการลงวินโดวส์นั้นหลายคนยังมีอาการกลัวอยู่ว่า เดียวจะลงผิดลงถูกทำให้ใช้ไม่ได้ จึงต้องพึ่งช่างตามร้านคอมพิวเตอร์ก็ต้องเสียเงินมากน้อยก็แล้วแต่ร้าน ผมจะมาบอกว่าความจริงแล้วลงวินโดวส์นั้นไม่ได้เป็นเรื่องยากอะไรสำหรับWindows 8 นั้นลงง่ายมากๆ ถึงจะมีขั้นตอนที่เพิ่มขึ้นมามากกว่า Windows 7 แต่คงไม่ยากเกินความสามารถของคุณๆ หรอกครับ ยิ่งถ้าเคยลง Windows 7 มาบ้างแล้วยิ่งเป็นการง่าย
วันนี้ผมจะมานำเสนอวิธีการลง Windows 8 แบบ Clean Install ก็คือแบบล้างเครื่องหรือฟอร์แมตฮาร์ดดิสก์ใหม่กันเลย....มาตามดูครับ
ในที่นี้ผมจะใช้วิธีการติดตั้งจากแผ่น DVD ของ Windows 8 นะครับ
1.ก่อนอื่นใส่แผ่นติดตั้งลงในเครื่องอ่านดีวีดีของคอมพิวเตอร์ ทำการบูตเครื่องให้ไปตั้งไบออสของเครื่องให้บูตจากแผ่นดีวีดีเป็นอันดับแรกซึ่งการเข้าไบออสนั้นส่วนมาก ถ้าเป็นคอมพิวเตอร์ตั้งโต๊ะก็จะกดปุ่ม Del ส่วนแลปทอปก็จะกดปุ่ม F2ให้ดูที่คู่มือของแต่ละเครื่องก็แล้วกัน
เมื่อเครื่องบูตขึ้นมาจนเห็นคำว่า Press any key to boot from CD or DVD... ให้กด ENTER เลยครับ
2.ปล่อยให้เครื่องทำงานไปจนได้จนปรากฎดังภาพ ให้คลิกเลือกรายการตามนี้
  • Language to install : English
  • Time and currency format : Thai(Thailand)
  • Keyboard or input method : ตัววินโดวส์จะเลือกให้เป็น Thai เพราะเห็นว่า Time and currency formatตั้งเป็น Thai ให้เราเลือกกลับมาเป็น US ก่อน เหตุผลเพราะเมื่อติดตั้งเสร็จหน้าล็อกออนเข้าระบบจะเป็นภาษาไทย เราอาจงงได้ในการกรอกชื่อผู้ใช้และพาสเวิร์ด
3.ในหน้าต่าง Windows Setup ให้คลิก Install now เพื่อเริ่มการติดตั้ง Windows 8
4.ในหน้าต่าง License terms คลิกถูก I accept the term license จากนั้นคลิก Next
5.ในหน้าต่าง Which type of installation do you want? ให้เลือกเป็น Custom: Install Windows only (advanced)
6.ในหน้าต่าง Where do you want to install Windows? ให้เลือกฮาร์ดดิสก์หรือพาร์ติชันที่ต้องการติดตั้ง (ในที่นี้เลือก Drive 0) เสร็จแล้วคลิก Next
ข้อควรจำในขั้นตอนนี้
  • ขั้นตอนนี้เราเลือก Drive ที่จะลง Windows8 ส่วนมาก จะลงใน Disk/Drive 0 นะครับ ก็คือ Drive C: ของWindows เรานั้นเอง ระวังให้ดีอย่าลงผิดไดร์ฟนะ ในกรณีที่มีพาร์ติชันมากกว่า 1 พาร์ติชัน
  • ในการ Format Windows ข้อมูลจะหายเฉพาะที่ Drive C นะครับ
สำหรับเครื่องที่มี Windows XP , Windows 7 แล้วจะลงใหม่เป็น Windows 8
1.ให้ทำการ Format Drive ที่เป็นวินโดวส์ตัวเก่าก่อน โดยทำการกด Drive options (advanced) จากนั้นเลือก ไดร์ฟของวินโดวส์เก่าแล้วคลิก Format... ย้ำอีกทีดูดีๆนะครับ ถ้าผิดไดร์ฟข้อมูลในไดร์ฟหายหมดนะ
2. จากนั้นก็เลือก Drive/disk ที่เรา Format ไปจากข้อที่ผ่านมา จากนั้นกด Next
สำหรับเครื่องที่เพิ่งซื้อมาใหม่หรือฮาร์ดดิสก์ลูกใหม่
1 ให้เราทำการกด Drive options จากนั้นเลือกฮาร์ดดิสก์แล้วคลิก New เพื่อทำการแบ่งพาร์ติชันวินโดวส์ให้แบ่งมาสัก80 -100 GB ก็พอ ( 1GB = 1024 MB)
2 จากนั้น ก็แบ่งส่วนที่เหลือไว้ให้กับ Drive D , E ตามความเหมาะสม
3 ต่อมาให้เลือกไดร์ฟที่จะให้ลงวินโดวส์ โดยทำการคลิกบน Drive/Disk แล้วคลิก Next
7.ระบบจะเริ่มทำการติดตั้ง Windows 8 โดยจะดำเนินการขั้นตอนต่างๆ ของวินโดวส์ตามนี้ Copying Windows files, Getting files ready for installation, Installing features, Installing updates และ Finishing upให้รอจนการติดตั้งแล้วเสร็จ ก็ประมาณ 15 - 20 นาที ขึ้นอยู่กับเครื่องว่าแรงขนาดไหน
8.เมื่อ Windows 8 ติดตั้งเรียบร้อย เครื่องจะรีสตาร์ท 1 ครั้ง
9.หลังจากทำการติดตั้งแล้วเสร็จ Windows จะทำการรีสตาร์ทเครื่อง 1-2 รอบ จากนั้นจะปรากฏหน้าต่างPersonalize ให้ทำการเลือกสีของ Background และกำหนดชื่อเครื่องคอมพิวเตอร์โดยใส่ชื่อที่ต้องการในช่อง PC name เสร็จแล้วคลิก Next
10.ขั้นตอนการ Settings ให้เราเลือก Use Express Settings เพื่อทำการตั้งค่าระบบแบบด่วน
11.ในหน้าต่าง Sign in to your PC ให้คลิก Sign in without a Microsoft account แล้วคลิก Next
** ในขั้นตอนนี้จะมีวิธีการ Sign in to your PC อยู่ 2 วิธี ได้แก่ Email Address และ Sign in without a Microsoft account สำหรับในที่นี้ผมขอให้เลือก Sign in without a Microsoft account เพราะสะดวกกว่า ส่วนEmail Address เราต้องต่ออินเตอร์เน็ตและต้องมีอีเมลของ outlook.com หรือ Hotmail.com อยู่ก่อนแล้ว ซึ่งเราสามารถสร้างได้ภายหลังที่เข้าใช้วินโดวส์แล้วก็ได้ **
12.หน้าต่างต่อมาให้คลิก Local account
13.ต่อมาให้กำหนดชื่อผู้ใช้ในช่อง User name แล้วกำหนดรหัสผ่านที่ต้องการ 2 ครั้ง ในช่อง Password และReenter password จากนั้นข้อความช่วยจำรหัสผ่านในช่อง Password hint แล้วคลิก Finish
14.ระบบจะทำการจัดเตรียมระบบตามการตั้งค่า
15.ระบบแนะนำการใช้งานเบื้องต้นจากหน้านี้ก็จะเข้าหน้า Lock on Screen
16.เมื่อมาถึงหน้า Lock on Screen คุณก็พร้อมใช้งาน Windows 8 ได้แล้ว
จบแล้วครับสำหรับการติดตั้ง Windows 8 แบบ Clean Install ผมคิดว่าคงไม่ยากเกินไปสำหรับผู้ที่ต้องการจะเรียนรู้ในติดตั้งระบบวินโดวส์ด้วยตนเอง ไม่ต้องไปง้อใครหรือเสียตังส์ให้กับช่างคอมพิวเตอร์

วิธีลง Windows 7

วิธีลง Windows 7 ละเอียดทุกขั้นตอนก่อนติดตั้ง Windows 7
          คอมพิวเตอร์ที่ใช้สำหรับลง Windows 7 ควรจะมีสเปคอยู่ในระดับปานกลาง แต่แนะนำว่าควรเป็นคอมพิวเตอร์รุ่นไม่เก่าจนเกินไปนัก และใช้การ์ดจอแบบ 3D ต่อไปนี้เป็นคุณสมบัติของเครื่องคอมพิวเตอร์ขั้นต่ำที่สามารถใช้งาน Windows 7 ได้อย่างราบรื่น
          - ซีพียู ความเร็วขั้นต่ำ 1 GHz (32 bit หรือ 64 bit ก็ได้)
          - แรม ขั้นต่ำ 1 GB
          - พื้นที่ว่าง ในฮาร์ดดิสก์ที่จะ ลง Windows 7 อย่างน้อย 16 GB
          - กราฟิกการ์ด มีหน่วยความจำขั้นต่ำ 128 MB และควรสนับสนุน DirectX9
          - ไดร์ฟ DVD-R/W สำหรับการลง Windows 7 ผ่านแผ่น DVD
          นอกจากคุณสมบัติข้างต้นแล้ว คุณสมบัติบางอย่างของ Windows 7 อาจต้องใช้อุปกรณ์พิเศษเพิ่มเติม เช่น การบันทึกรายการทีวี จะต้องมีการ์ดสำหรับการบันทึกภาพ การใช้งานระบบสัมผัส การเขียนด้วยลายมือ หน้าจอจะต้องรองรับระบบมัลติทัช เป็นต้น

วิธีลง Windows 7
          1.Restart และกำหนดให้เครื่องบูตจากแผ่น DVD โดยขั้นตอนการบูตของ Windows เริ่มต้นให้เรากดปุ่ม F2 หรือ Del แล้วแต่รุ่นของไบออสในคอมพิวเตอร์เครื่องนั้น ในที่นี้ยกตัวอย่างดังภาพด้านล่าง ซึ่งหลักการก็คือเมื่อเข้าไบออสได้แล้ว ให้ตั้งค่าบูตจากแผ่น CD/DVD เป็นอันดับแรก
          ** ส่วนมากเครื่อง PC จะกดปุ่ม Del
          ** โน๊ตบุ๊คส่วนใหญ่จะกดปุ่ม F2
                   - ในตัวอย่างนี้ให้กดปุ่มลูกศรที่คีย์บอร์ดเลื่อนลงมาเลือก Advanced BIOS Features
install-Windows-7-1

                   - ให้เลื่อนลงมาเลือกตรง First Boot Device กด Enter แล้วเลือกเป็น CD/DVD ROM
install-Windows-7-2

                   - เมื่อตั้งค่าเสร็จแล้วให้กดปุ่ม F10 บนคีย์บอร์ดแล้วพิมพ์ Y หลังจากนั้นกด Enter
install-Windows-7-3

          2.เริ่มขั้นตอนการลง Windows 7 จากแผ่น DVD สังเกตว่าเมื่อเครื่องเริ่มบูตจากแผ่นจะขึ้นข้อความดังภาพ ในขั้นตอนนี้ให้เรากดปุ่มใดๆ บนคีย์บอร์ดก็ได้เพื่อทำการบูต Windows
install-Windows-7-4
install-Windows-7-5
install-Windows-7-6

          3.เลือกภาษาที่ใช้ในระหว่างการลง
          4.เลือกประเทศ ในที่นี้เลือกประเทศ Thai
          5.เลือกวิธีจัดวางคีย์บอร์ดที่รองรับภาษาไทย จากนั้นคลิกปุ่ม Next
install-Windows-7-7

          6.คลิกปุ่ม Install now
install-Windows-7-8

          7.เลือกเวอร์ชันของ Windows 7 ที่ต้องการลง จากนั้นคลิกปุ่ม Next
install-Windows-7-9

          8.คลิก I Accept ยอมรับข้อตกลงเรื่องลิขสิทธิ์  แล้วคลิกปุ่ม Next
install-Windows-7-10

          9.คลิก Custom (Advanced)
install-Windows-7-11

** เรื่องเกี่ยวกับฟอร์แมตพาร์ติชันก่อนลง Windows 7 **
          ก่อนเข้าสู่การลง Windows 7 ขั้นตอนถัดไป หากไดร์ฟ หรือพาร์ติชันที่ต้องการลง Windows 7 เป็นไดร์ฟเก่าที่ยังคงมีข้อมูลเดิมอยู่ เราสามารถเลือกฟอร์แมตไดร์ฟนี้ก่อนได้ เพื่อล้างข้อมูลทั้งหมดบนไดร์ฟที่เลือก และเป็นการจัดระเบียบพื้นที่บนฮาร์ดดิสก์ใหม่ด้วย
           การฟอร์แมตพาร์ติชันนี้ เราสามารถเลือกใช้คำสั่งระหว่างขั้นตอนการ ลง Windows 7 ได้ทันที โดยในขั้นตอนการเลือกพาร์ติชันสำหรับลง Windows 7 ให้เราคลิกที่ Drive options (Advanced) และเข้าไปเลือกสั่งฟอร์แมตพาร์ติชันก่อนได้ ดังนี้
                   - เลือกพาร์ติชันสำหรับ ลง Windows 7 ที่จะฟอร์แมตก่อน
                   - คลิกที่ Drive options (Advanced)
install-Windows-7-13

                   - จะปรากฏคำสั่งสำหรับจัดการพาร์ติชัน ให้คลิกที่ Format เพื่อสั่งฟอร์แมตพาร์ติชันที่เลือก
นอกจากคำสั่ง Format แล้ว ในส่วนของ Drive options ยังมีคำสั่งอื่นๆ สำหรับจัดการพาร์ติชันที่เลือกอีก ดังต่อไปนี้
          Refresh : ให้โปรแกรมติดตั้งตรวจสอบพื้นที่พาร์ติชันใหม่อีกครั้ง
          Delete : ลบพาร์ติชันที่เลือกอยู่ ผลลัพธ์ที่ได้จะได้พาร์ติชันที่ไม่มีการจัดรูปแบบ (Unpartitioned space)
          New : เลือกสร้างพาร์ติชันใหม่ (ต้องมีพื้นที่พาร์ติชันที่ยังไม่มีการจัดรูปแบบอยู่ด้วย เพื่อดึงพื้นที่ไปใช้)
          Load Driver : โหลดไดรเวอร์ของอุปกรณ์ที่จำเป็นต้องใช้เพิ่มเติม เช่น ไดรเวอร์ฮาร์ดดิสก์ SATA รุ่นใหม่
          Extend : ขยายขนาดของพาร์ติชันที่เลือก
install-Windows-7-14

                   - แจ้งว่าข้อมูลบนไดร์ฟที่เลือกทั้งหมดจะถูกลบทิ้ง ให้เราคลิกปุ่ม OK เพื่อยืนยันการฟอร์แมต
install-Windows-7-15

                   - โปรแกรมติดตั้งจะทำการฟอร์แมตพาร์ติชัน ให้เรารอสักครู่

          10.เมื่อ Format เสร็จแล้ว ให้คลิกเลือกไดรฟ์ที่จะลง Windows ข้อสังเกตหลังจากเรา Format แล้วพื้นที่ไดรฟ์ในส่วนของ Total Size และ Free Space จะเท่ากัน
          11.คลิกปุ่ม Next
install-Windows-7-12

          12.ขั้นตอนนี้จะมีการก๊อบปี้ไฟล์ลงไดรฟ์ที่เราเลือกลง Windows 7
install-Windows-7-17

          13.บางครั้งอาจมีการ Restart เครื่อง
install-Windows-7-18

          14.จะพบหน้าต่างสำหรับการปรับแต่งครั้งแรกก่อนมีการใช้งาน ให้รอสักครู่
          15.เมื่อขั้นหน้าต่างดังภาพ ให้กรอกชื่อผู้ใช้ (User Name)
          16.กรอกชื่อเครื่องคอมพิวเตอร์ จากนั้นคลิกปุ่ม Next
install-Windows-7-19

          17.ตั้งรหัสผ่าน
          18.กรอกรหัสผ่านเดิมซ้ำอีกครั้ง
          19.กรอกข้อความที่ใช้ไขปริศนารหัสผ่านในกรณีลืมรหัสผ่าน จากนั้นคลิกปุ่ม Next
install-Windows-7-20

          20.กรอก Product Key จากนั้นคลิกปุ่ม Next
install-Windows-7-21

          21.คลิก User recommended
install-Windows-7-22

          22. ตั้งวันที่ และเวลาให้ถูกต้อง หลังจากนั้นคลิกปุ่ม Next
                    - Time zone UTC+07.00 Bangkok,Hanoi,Jakarta
install-Windows-7-23

          23.เสร็จสิ้นขั้นตอนการลง Windows 7
install-Windows-7-24
install-Windows-7-25

          เพียงเท่านี้เครื่องเราก็จะใช้ระบบปฏิบัติการ Windows 7 ได้แล้ว ซึ่งจากขั้นตอนการลง Windows 7 ดังกล่าวนั้น ผู้อ่านสามารถทำตามทีละขั้นตอนได้เลย ง่ายมากๆ :)

วันศุกร์ที่ 7 ธันวาคม พ.ศ. 2555

3G

3G คืออะไร

    3G หมายถึงรุ่นที่ 3 ของเทคโนโลยีโทรศัพท์เคลื่อนที่ (เซลลูลาร์) รุ่นที่ 3 นี้ ตามชื่อที่เรียกตามหลังสองรุ่นก่อนหน้านี้

เทคโนโลยี 1 จี เริ่มต้นในช่วงต้นทศวรรษ 1980 ประมาณปี พ.ศ.2523 ด้วยเครือข่ายโทรศัพท์เซลลูลาร์แอมป์ (AMPS ย่อจาก Advanced Mobile Phone) ที่รองรับเสียงแบบอะนาล๊อกบนแถบความถี่ 800 เมกกะเฮิร์ซ เหมือนกับการกระจายเสียงวิทยุทั่วไป
เทคโนโลยี 2 จี เกิดขึ้นในทศวรรษ 1990 ประมาณปี พ.ศ.2533 ผู้ให้บริการโทรศัพท์มือถือใช้เทคโนโลยีรองรับเสียงในระบบดิจิตอล ซึ่งมีสองเทคโนโลยี 1) เทคโนโลยี ซีดีเอ็มเอ (CDMA ย่อจาก Code Division Multiple Access) ที่สามารถเรียกได้มากถึง 64 สายต่อช่องบนแถบความถี่ 800 เมกกะเฮิร์ซ มีการใช้ในสหรัฐและแบบที่ฮัท์ชใช้อยู่ในประเทศไทย 2) เทคโนโลยีจีเอสเอ็ม (GSM ย่อจาก Global System for Mobile) ซึ่งสามารถเรียกได้ 8 สายต่อช่องสัญญาณ บนแถบความถี่ 800 ถึง 1800 เมกกะเฮิร์ซ
The International Telecommunications Union (ITU) กำหนด มาตรฐานโทรศัพท์เคลื่อนที่3จี คือ IMT-2000 เพื่ออำนวยการเติบโต เพิ่มแถบความกว้างความถี่ และสนับสนุนโปรแกรมประยุกต์หลากหลาย ตัวอย่าง GSM สามารถไม่เพียงเสียง แต่รวมถึงข้อมูลสวิตช์วงจรที่อัตราความเร็วสูงถึง 14.4 Kbps แต่สนับสนุนการประยกต์มัลติมีเดีย 3จีต้องส่งมอบข้อมูลสวิตช์แพคเกตด้วยประสิทธิภาพดี ที่ความเร็วสูงกว่า
อย่างไรก็ตาม ในช่วงยกระดับจาก 2 จี เป็น 3 จี ผู้ให้บริการโทรศัพท์ได้ปฏิรูปเครือข่าย พร้อมกับแผน “ปฏิวัติ” เครือข่ายโทรศัพท์เคลื่อนที่ใหม่ ซึ่งได้นำไปสู่ก่อตั้ง 3GPP (3rd Generation Partnership Project) และ 3GPP2 (3rd Generation Partnership Project 2)
3rd Generation Partnership Project (3GPP) ก่อตั้งในปี 1998 เพื่อพัฒนาเครือข่าย 3 จี จาก GSM เทคโนโลยีที่พัฒนาคือ
      - General Packet Radio Service (GPRS) เสนอความเร็วสูงถึง 114 กิโลบิตต่อวินาที
      - Enhanced Data Rates for Global Evolution (EDGE) เสนอความเร็วสูงถึง 384 กิโลบิตต่อวินาที
      - UMTS Wideband CDMA (WCDMA) เสนอความเร็วรับข้อมูลสูงถึง 1.92 เมกกะบิตต่อวินาที
      - High Speed Downlink Packet Access (HSDPA) เพิ่มความเร็วรับข้อมูลสูงถึง 14 เมกกะบิตต่อวินาที
      - LTE Evolved UMTS Terrestrial Radio Access (E-UTRA) มีเป้าหมายที่ 100 เมกกะบิตต่อวินาที

  GPRS มีให้ในปี 2543 ตามด้วย EDGE ในปี 2546 เทคโนโลยีนี้บางครั้งเรียกว่า 2.5 จี เพราะไม่ได้เสนออัตราข้อมูลหลายเมกะบิต (multi-megabit) EDGE ได้รับการแทนที่โดย HSDPA (และหุ้นส่วนอัพลิงค์ HSUPA) ตามรายงานของ 3GPP กล่าวว่า HSDPA มี 166 เครือข่ายใน 75 ประเทศเมื่อสิ้นปี 2550 LTE E-UTRA ซึ่งเป็นขั้นไปของ GSM จะสามารถนำมาใช้ได้ในปี 2551
องค์กรที่สอง 3rd Generation Partnership Project 2 (3GPP2) ได้รับการก่อตั้งเพื่อช่วยผู้ให้บริการโทรศัพท์อเมริกาเหนือและเอเซียในการปรับแปลง CDMA2000 ไปสู่ 3 จี เทคโนโลยีที่ 3GPP2 พัฒนาคือ
      - One Times Radio Transmission Technology (1xRTT) เสนอความเร็วสูงถึง 144 กิโลบิตต่อวินาที
      - Evolution – Data Optimized (EV-DO) เพิ่มความเร็วรับข้อมูลสูงถึง 2.4 เมกกะบิตต่อวินาที
      - EV-DO Rev. A เพิ่มความเร็วรับข้อมูลสูงถึง 3.1 เมกกะบิตต่อวินาที และลดซ่อนเร้นอยู่ภายใน
      - EV-DO Rev. B สามารถใช้ 2 ถึง 5 ช่อง แต่ละการรับข้อมูลสูงถึง 4.9 เมกกะบิตต่อวินาที
      - Ultra Mobile Broadband (UMB) ตั้งเป้าหมายให้ถึง 288 เมกกะบิตต่อวินาทีในการรับข้อมูล

1xRTT มีให้ในปี 2545 ตามด้วย EV-DO Rev. 0 เชิงพาณิชย์ในปี 2547 อีกครั้ง 1xRTT ได้รับการอ้างเป็น “2.5จี” เพราะสิ่งนี้รองรับขั้นการปรับแปลงไปสู่ EV-DO มาตรฐาน EV-DO ได้รับการขยายสองเท่า ซึ่ง Revision A ออกมาใช้ในปี 2549 และกำลังถูกแทนที่โดยผลิตภัณฑ์ที่ใช้ Revision B ที่เพิ่มอัตราข้อมูลโยการส่งผ่านหลายช่อง UMB ที่เป็นเทคโนโลยีต่อไปของ 3GPP2 อาจจะไม่แพร่หลาย เพราะโอเปอร์เรเตอร์ CDMA กำลังวางแผนปฏิรูป LTE แทน
ตามความจริง LTE และ UMB มักจะได้รับการเรียกว่า เทคโนโลยี 4จี (fourth generation) เพราะเพิ่มความเร็วดาวน์ลิงค์ตามลำดับของขนาด ป้ายนี้คือ มาก่อนกำหนดเล็กน้อยเพราะ การสร้าง “4จี” ยังไม่เป็นมาตรฐาน ITU กำลังพิจารณาคู่แข่ง สำหรับการสรุปในมาตรฐาน 4G IMT-Advanced รวมถึง LTE, UMB และ WiMAX II เป้าหมายของ 4จี รวมถึง อัตราข้อมูลอย่างน้อย 100 Mbps การส่งผ่าน OFDMA การส่งมอบแพคเกตสวิตช์ของเสียง ข้อมูล และมัลติมีเดียต่อเนื่องบนฐาน IP

วันพฤหัสบดีที่ 6 ธันวาคม พ.ศ. 2555

CPLD


การทำงานของ CPLD

CPLD เป็นคำย่อมาจาก Complex Programmable Logic Device หมายถึงเป็นชิพไอซีที่สามารถสร้างวงจรลอจิกทั้งแบบ Combination และ Sequential ได้โดยการออกแบบโดยใช้คอมพิวเตอร์ และโปรแกรมลงไปบนตัวชิพโดยใช้มาตรฐานการโปรแกรมแบบ JTAG Programmer
อุปกรณ์ที่มีลักษณะคล้ายกันนี้ได้แก่
GAL (GAL : Gate Array Logic) เป็นชิพที่ใช้โปรแกรมวงจรลอจิกได้เฉพาะวงจร Combination โปรแกรมโดยเครื่องโปรแกรมโดยเฉพาะ โปรแกรมได้เพียงครั้งเดียว หากผิดไม่สามารถแก้ไขได้ ขาอินพุท และเ อ้าท์พุทถูกกำหนดไว้ตายตัวไม่สามารถเปลี่ยนได้ มีจำนวนลอจิกเกต
น้อย ใช้แทนวงจรที่มีขนาดเล็กไม่ซับซ้อน
PAL (PAL : Programmable Array Logic) เป็นชิพที่ใช้โปแกรมสร้างวงจรลอจิกที่ซับซ้อนมากขึ้นกว่า GAL โดยมีทั้งตัว Logic gate ต่าง ๆ และ ตัว Flip – flopที่สามารถออกแบบวงจรที่ผสมระหว่าง Combination logic และ Sequential logic การโปรแกรมมีเครื่องมือที่สามารถออกแบบและโปรแกรมผ่านทางคอมพิวเตอร์ได้ ส่วนขา I/O ยังถูกบังคับไม่สามารถใช้สลับกันได้ แต่การโปรแกรมไม่สามารถทำซ้ำได้มากนัก
ส่วน CPLD เป็นชิพที่ใช้ออกแบบวงจรขนาดใหญ่ที่สามารถออกแบบโดยเขียนเป็นโปรแกรมภาษา HDL ได้ ใช้เทคโนโลยีการเก็บรักษาวงจรแบบ Flash ที่สามารถคงสถานะของวงจรที่ฝังอยู่ประมาณ 20 – 40 ปี สามารถโปรแกรมซ้ำได้ประมาณมากกว่า 10000 ครั้ง ขา I/O เป็นแบบเอนกประสงค์โดยสามารถกำหนดให้ เป็นอินพุท และเอ้าพุทแบบต่าง ๆ ได้ มีจำนวนลอจิกเกตที่สามารถกำหนดให้เป็นเกต อะไรก็ได้ เริ่มตั้งแต่ 800 ตัวและ Flip-flop 36 ตัว ไปจนถึง เป็นแสน ๆ เกต
และ Flip-flop หลายพันตัว ที่สามารถรองรับการออกแบบวงจรขนาดใหญ่ ๆ และซับซ้อนมาก ๆ ได้
FPGA (FPGA : Filled Programmable Gate Array) เป็นชิพที่ใช้ออกแบบวงจรที่มีขนาดใหญ่มาก ๆ และมีความซับซ้อนของระบบสูงมากเท่าที่มีอยู่ปัจจุบัน ที่ใช้ในการพัฒนาออกแบบหน่วยประมวลผล (CPU) ขนาดใหญ่ ๆ ได้ โดยมีจำนวนลอจิกเกตและ Flip-flop นับล้าน ๆ ตัว มีจำนวนขา I/O ตั้งแต่หลายสิบไปจนถึงหลายร้อยขา การโปรแกรมและการรักษาวงจรใช้เทคโนโลยีแบบ Volantine เช่นเดียวกับโครงสร้างหน่วยความจำ RAM คือต้องโปรแกรมแล้วต้องมีไฟเลี้ยงตัวชิพอยู่ตลอดเวลา หากไฟดับวงจรจะหายไปทันที ดังนั้นในการออกใช้งาน จะต้องมี Flash memory สำหรับเก็บค่าสถานะของวงจรต่อพ่วงอยู่เสมอ โดยขณะที่โปรแกรม เราต้องโปรแกรมค่า Config. ลงใน Flash ด้วย การทำงานคือ เมื่อเปิดไฟเลี้ยงตัวชิพ ข้อมูล Config.วงจรจาก Flash จะถูกโหลดมาสร้างเป็นวงจรตามที่โปรแกรมไว้และทำงานได้ทันที ด้วยเทคโนโลยีนี้ FPGA จึงสามารถใช้งานได้เหมือนกันกับ
2
CPLD และที่สำคัญ CPLD และ FPGA สามารถใช้โปรแกรมที่เป็นเครื่องมือในการพัฒนาออกแบบวงจรตัวเดียวกัน
ตัวอย่าง รายละเอียดคุณสมบัติของ CPLD ตระกูล XC9500 ของ XILINX
3
จากตัวอย่างคุณสมบัติ และตารางทั้งสอง ของ CPLD ส่วนที่เป็นสาระสำคัญที่ควรรู้เพื่อนำไปเป็นข้อมูลเบื้องต้นในการออกแบบได้แก่
1. CPLD สามารถใช้งานความถี่สูงถึง 125 MHz ใช้งานที่แรงเคลื่อน 5 V และ 3.3 V
2. ขา I/O สามารถขับกระแสได้ ถึง 24 mA ทั้ง Sink และ Source
3. CPLD แต่ละเบอร์สามาถเลือก จำนวน I/O ตาม Package ได้ ตามตารางใน Table 2
4. เราสามารถเลือกขนาดของ CPLD ได้ตามตารางใน Table 1 ซึ่งแต่ละเบอร์จะมีจำนวนลอจิกเกตใช้งาน (Usable Gates) และจำนวน Register หรือจำนวน Flip-flop ที่แตกต่างกัน
5. การเชื่อมต่อการใช้งานด้านอินพุท กับเอ้าพุท ที่มีขนาดแรงเคลื่อน 5 V เท่ากันตามรูป (a) และที่มีแรงเคลื่อน 3.3 V ตามรูป (b) จะต้องต่อไฟเลี้ยงขา VCCINT และ VCCIO ที่ค่าแตกต่างกัน
4
โครงสร้างทางสถาปัตยกรรมของ CPLD
ในชิพ CPLD ตระกูล XC9500 ของ XILINX ทุกตัวประกอบด้วยวงจรที่เป็นส่วนการทำงาน ได้แก่ Function Blocks (FBs) และ I/O Blocks (IOBs) ซึ่งทั้งสองส่วนจะถูกเชื่อมต่อกันภายในโดยการทำงานในส่วนของวงจรที่เรียกว่า Fast CONNECT switch matrix ซึ่งวงจรส่วนนี้เป็นลิขสิทธิ์Fเฉพาะของผู้ผลิต วงจรส่วนนี้จะทำงานโดยข้อมูลโปรแกรมที่มาจากส่วนวงจร In-System Programming Controller วงจรส่วน Fast CONNECT switch matrix จะทำงานร่วมกับ Function Blocks ทำให้เกิดวงจรลอจิกตามที่ได้ออกแบบและโปรแกรมเข้าไว้ ในชิพ CPLD แต่ละตัวจะมีFunction Block หลายชุด โดยแต่ละชุดจะมีสายสัญญาณการโปรแกรมลอจิกจาก Fast CONNECT switch matrix เป็นอินพุทจำนวน 36 เส้น และเอ้าพุทจำนวน 18 เส้น ในแต่ละ Function Block
ภายในจะประกอบด้วยวงจรส่วนที่เรียกว่า Macrocells จำนวน 18 ชุด ภายในวงจร Macrocell จะประกอบด้วยวงจรรีจิสเตอร์ หรือ ฟลิบ-ฟล็อบ ที่สามารถประกอบกันเป็นวงจรรีจิสเตอร์ หรือ เค้าเตอร์ได้ ส่วนวงจรในส่วนที่เรียกว่า I/O Blocks จะทำหน้าที่เป็นตัวเชื่อมต่อกับขา I/O ของตัวชิพโดย
สามารถโปรแกรมให้แต่ละขาเป็น Input / Output หรือ Bi-direction และสามารถกำหนด Slew rate
ได้ด้วย
รูปที่ 1 แสดงโครงสร้างของชิพ CPLD ตระกูล XC9500 ของ XILINX
5
โครงสร้างของ Function Block
แต่ละ Function Block ประกอบด้วย Macrocell จำนวน 18 ชุดโดยแต่ละชุดจะทำงานเป็นอิสระไม่ขึ้นต่อกัน วงจรส่วนนี้สามารถจะโปรแแกรมให้สร้างได้ทั้ง Combination Logic หรือ Sequential Logic วงจร Programmable AND-Array ทำหน้าที่นำเอาสายสัญญาณที่มาจาก Fast CONNECT switch matrix มาทำให้เป็นสัญญาณ True และ complement รวมเป็น 72 เส้นสัญญาณ
ส่งไปยังวงจร Product Term Allocators และต่อไปยัง Macrocell ทั้ง 18 ตัว ตามรูปที่ 2
รูปที่ 2 แสดงโครงสร้างของ Function Block
โครงสร้างของ Macrocell
ในแต่ละ Macrocell ที่อยู่ภายใน Function Block จะประกอบด้วยส่วนการทำงานที่เรียกว่า Product Term จำนวน 5 ชุดที่ต่อสัญญาณมาจาก AND-Array สำหรับใช้เป็นข้อมูลลอจิกปฐมภูมิ
(ได้แก่ OR และ XOR Gates) ที่จะนำมาสร้างเป็นวงจรลอจิกประเภท Combination หรือเป็นวงจรควบคุมทางของวงจร Register รวมทั้งสัญญาณ Clock, Set / Reset และสัญญาณ Enable ต่าง ๆ
ในส่วนของ Macrocell register โปรแกรมสามารถจะกำหนดให้เป็นฟลิบ-ฟล็อบแบบต่าง ๆ ได้ เช่น
D-Flip-flop, T-Flip-flop หรืออาจกำหนดให้เป็นตัวผ่าน กรณีที่เป็นวงจรประเภท Combination ใน
การกำหนดสัญญาณ Set/Reset ให้ฟลิบ-ฟล็อบ สามารถกำหนดให้เป็นได้ทั้งแบบ Synchronous และ
6
Asynchronous operation และเป็นได้ทั้ง Individual และ Global operation และการทำงานขณะเริ่มเปิดไฟเข้าเลี้ยงวงจร ฟลิบ-ฟล็อบ จะถูกกำหนดให้ผู้ใช้พร้อมจะโหลดข้อมูลเข้าได้ (หากไม่ได้กำหนดเป็นอย่างอื่น
รูปที่ 3 แสดงโครงสร้างภายในของ Macrocell ของ CPLD ตระกูล XC 9500
รูปที่ 4 แสดงสายสัญญาณ Global
ที่ต่อตรงเข้าไปยัง Macrocell
7
โครงสร้างของ Fast CONNECT Switch Matrix
วงจรของ Fast CONNECT Switch Matrix จะมีสายสัญญาณเชื่อมต่อไปยัง Function Block (FB) โดยใน Function Block หนึ่ง ๆ จะมีสายจาก Fast CONNECT Switch Matrix จำนวน 36 เส้น วงจร Fast CONNECT Switch Matrix จะมีลักษณะเป็นวงจร Wired-AND การทำงานของวงจรจะเป็นตัวป้อนกลับเข้าไปยังวงจรในส่วน Function Block เพื่อสร้างเป็นวงจรลอจิกเมื่อถูกโปรแกรม ตามที่ได้ออกแบบวงจรไว้
รูปที่ 5 แสดงการทำงานในส่วนของ Fast CONNECT Switch Matrix
โครงสร้างของวงจรในส่วนของ I/O Block
I/O Block (IOB) เป็นวงจรด่านสุดท้ายที่ต่อเชื่อมจาก Macrocell ไปยังขา I/O ของตัวชิพ วงจรในส่วนของ I/O Block จะประกอบด้วยส่วนสำคัญ 5 ส่วน คือ Input Buffer ทำหน้าที่รับและปรับสภาพสัญญาณลอจิกที่ป้อนเข้าที่ขา I/O ของ CPLD Output Buffer ทำหน้าที่ควบคุมการส่งค่า
8
สัญญาณลอจิกออกทางขา I/O ของ CPLD วงจรส่วนนี้สามารถควบคุมค่า Slew Rate และ ค่า Global Tri-state (GTS) และ Output Enable (OE)ที่ต่อสัญญาณควบคุมมาจาก Product Term ได้โดยตรง
ที่ขา I/O ยังมีวงจรควบคุม Pull-up Resistor ซึ่งต่ออยู่กับ VCCIO ซึ่งมีหน้าที่กำหนดให้ขา I/O เกิด
Pull-up ให้เป็นลอจิก High เพื่อป้องกันสัญญาณรบกวนขณะที่มีการโปรแกรมตัวชิพ และวงจร User-
Programmable Ground มีไว้เพื่อให้ผู้ใช้งานโปรแกรมให้ลงกราวด์ กรณีที่ขาI/Oไม่ได้ถูกใช้งาน
รูปที่ 6 รูปแสดงวงจรในส่วนของ I/O Block และ Global Tri-State
9
การโปรแกรมตัวชิพ CPLD
ชิพ CPLD ตระกูล XC9500 สามารถทำการโปรแกรมได้ในขณะมีไฟเลี้ยงวงจร และวงจรทำงานอยู่ได้ ซึ่งเรียกว่า In – System Programming โดยใช้มาตรฐาน Protocol JATAG แบบ 4 ขั้ว
เป็นไปตามมาตรฐาน IEEE 1149.1 Boundary-Scan (JTAG) โดยสามาถโปรแกรมซ้ำได้มากกว่า 10000 ครั้ง
ลำดับชั้นความปลอดภัยของการออกแบบ
ชิพ CPLD ตระกูล XC9500 สามารถป้องกันข้อมูลโปรแกรมไว้ได้อย่างสมบูรณ์ ทั้งอ่านและเขียน ซึ่งผู้ใช้สามารถกำหนดได้โดยการเซ็ตค่า read security bits และ write security bits ตาม
ตารางในรูปที่ 6 ผใช้สามรถกำหนดได้โดยขณะที่อยู่ใน JTAG Program ู้
รูปที่ 6 แสดงระดับการกำหนดระดับป้องกันข้อมูลโปรแกรมทั้งอ่านและเขียน
คุณสมบัติขณะเริ่มทำงาน ( Power- Up Characteristics )
คุณสมบัติขณะเริ่มทำงานของ CPLD ตระกูล XC9500 ที่ใช้แรงเคลื่อน 5 V เมื่อเริ่มจ่ายไฟเข้าเลี้ยงตัวชิพ CPLD วงจรภายในจะถูกควบคุมให้อยู่ในภาวะสงบจนแรงเคลื่อนมีระดับถึงระดับความปลอดภัย(Safe Level Voltage) ประมาณ 3.8 V ในระดับนี้ ค่า Pull-Up Resister จะถูกยกเลิก และ
รีจิสเตอร์ทุกตัวในวงจรจะถูกกำหนดค่าที่ตั้งไว้ตามที่โปรแกรมไว้(Initialized) เวลาในการใช้ในการเริ่มทำงานปรกติหลังจากเริ่มจ่ายไฟเลี้ยงจะใช้เวลาประมาณ 100 - 300 ไมโครวินาที ทั้งนี้ขึ้นอยู่กับขนาดหรือ เบอร์ชิพ โดยเริ่มตั้งแต่ XC9536 ไปจนถึง XC95288
10
รูปที่ 7 กราฟแสดงคุณสมบัติภาวะเริ่มทำงาน ( Power- Up Characteristics )
และภาวะการหยุดทำงาน
เครื่องมือที่ใช้ในการพัฒนาและออกแบบวงจร ( Development System Support)
ในการพัฒนาและออกแบบวงจรลอจิกที่จะใช้โปรแกรมลงตัวชิพ CPLD ตระกูล XC9500
เราใช้โปรแกรม XILINX Foundation และ XILINX Web Pack ซึ่งจะรองรับการออกแบบได้ทั้งการเขียนเป็นวงจร Schematic และการใช้โปรแกรมภาษา ABEL-HDL และ VHDL นอกนั้นยังรองรับการใช้ภาษา Verilog และการเขียนเป็น State Diagram อีกด้วย สำหรับในเอกสารเล่มนี้จะเน้นการใช้ภาษา ABEL-HDL เป็นหลักเนื่องจากเป็นภาษาที่มีโครงสร้างคล้ายกันกับภาษาปาสคาล และภาษาซี
ตัวอย่าง ภาษาที่ใช้ในการเขียนโปรแกรมเพื่อออกแบบวงจรลอจิก

ภาษา VHDL


ภาษา VHDL 

               ความซับซ้อนและขนาดของระบบดิจิตอลในปัจจุบันได้เพิ่มมากขึ้นทุกขณะ ส่งผลให้มีการนำคอมพิวเตอร์เพื่อช่วยใน การออกแบบหรือ CAD มาใช้ในขบวนการออกแบบฮาร์ดแวร์เพิ่มขึ้นเช่นกัน อีกทั้งอุปกรณ์และวิธีการ ออกแบบใหม่ๆ ก็ถูกพัฒนาขึ้นมาเพื่อช่วยอำนวยความสะดวกให้กับนักออกแบบมากขึ้นด้วย สำหรับภาษาบรรยายอุปกรณ์ฮาร์ดแวร์ (HDL : Hardware Description Language) ก็เป็นเครื่องมืออย่างหนึ่งที่ได้รับการพัฒนามาอย่างต่อเนื่อง เพื่อช่วยให้การปรับปรุงขบวนการออกแบบระบบดิจิตอลเป็นไปอย่างมีประสิทธิภาพ
การออกแบบระบบดิจิตอล
ในการออกแบบระบบดิจิตอล เริ่มตั้งแต่การกำหนดแนวความคิดเบื้องต้นจนกระทั่งได้ออกมาเป็นอุปกรณ์ฮาร์ดแวร์ ที่ใช้งานได้จะต้องผ่านขั้นตอนต่างๆ มากมาย และในแต่ละขั้นตอนผู้ออกแบบจะต้องตรวจสอบผลลัพธ์ในแต่ละขั้น ก่อนเข้าสู่กระบวนการออกแบบในขั้นต่อไป รูปที่ 5.1 แสดงขั้นตอนปกติที่ใช้ในการออกแบบระบบดิจิตอลทั่วไป ขั้น แรกผู้ออกแบบจะกำหนดแนวความคิดในการออกแบบแล้วทำการพัฒนาให้สามารถนำมาใช้ได้อย่างสมบรูณ์ ซึ่งภาย ในขั้นตอนนี้ผู้ออกแบบจำเป็นต้องสร้างรูปแบบระบบในเชิงพฤติกรรมขึ้นมาตรวจสอบซึ่งอาจจะเป็นผังงานแสดงแบบหรือ รหัสคำสั่งเทียม (Pseudo code) ก็ได้
รูปที่ 5.1 แสดงขั้นตอนการออกแบบระบบดิจิตอล
ขั้นตอนต่อไปเป็นการออกแบบระบบเส้นทางของข้อมูล ผู้ออกแบบจะกำหนดส่วนประกอบของรีจิสเตอร์และวงจรลอจิก ที่จำเป็นทั้งหมดเพื่อนำมาประกอบเป็นระบบที่สมบรูณ์ โดยแต่ละองค์ประกอบสามารถเชื่อมต่อกันด้วยบัสหนึ่งหรือสอง ทิศทาง (Unidirectional or Bidirectional Bus) ส่วนกระบวนการในการควบคุมการเคลื่อนย้ายข้อมูลระหว่าง รีจิสเตอร์และวงจรลอจิกจะขึ้นอยู่กับพฤติกรรมของระบบที่กำหนดไว้ดังรูปที่ 5.2
รูปที่ 5.2 การออกแบบระบบเส้นทางของข้อมูล
ขั้นตอนถัดมาเป็นการออกแบบวงจรลอจิก ซึ่งจะเกี่ยวข้องกับการนำเกทดิจิตอลพื้นฐานและฟลิปฟลอป (flip-flop) มาประกอบเป็นอุปกรณ์ย่อยต่างๆ เช่น รีจิสเตอร์เก็บข้อมูล บัสวงจรลอจิก และส่วนควบคุมฮาร์ดแวร์ ซึ่งผลลัพธ์ ที่ได้ในขั้นตอนนี้จะเป็นเครือข่ายของการโยงใยระหว่างเกทและ ฟลิปฟลอปนั่นเองการออกแบบในขั้นตอนถัดไป เป็นการเปลี่ยนเครือข่ายการโยงใยที่ได้จากขั้นตอนที่แล้วให้เป็นลำดับของทรานซิสเตอร์ (Transistor List) และ Layout ซึ่งขั้นตอนนี้จะเกี่ยวข้องโดยตรงกับการจัดวางทรานซิสเตอร์หรือไลบรารีเซลล์เพื่อ แทนเกทและฟลิปฟลอปต่างๆและในขั้นตอนสุดท้ายจะเป็นการส่งระบบที่ออกแบบไว้ไปทำการเจือสารที่โรงงานเพื่อผลิตออกมาเป็น วงจรรวมในที่สุด
ประวัติความเป็นมาของภาษา VHDL
VHDL ย่อมาจากคำว่า VHSIC Hardware Description Language (VHSIC : Very High Speed Integrated Circuit) เป็นภาษาโปรแกรมระดับสูง (High Level Language) ที่ใช้สำหรับการออกแบบฮาร์ด แวร์ในระบบดิจิตอล ตัวของภาษาสามารถบรรยายพฤติกรรมการทำงานในรูปของลำดับชั้น (Hierarchy) และ สามารถเขียนได้หลายรูปแบบ ด้วยเหตุผลนี้จึงทำให้ภาษา VHDL เป็นเครื่องมือที่ใช้ออกแบบตั้งแต่ขั้นตอนบนสุด คือ แนวความคิดที่จะแก้ปัญหา ลงไปทีละขั้นจนถึงขั้นตอนของการสร้างวงจรจริง และตัวภาษาก็เปิดโอกาสให้วิศวกร ได้พัฒนาและจำลองการทำงานของรูปแบบฟังก์ชันการทำงานของวงจรอย่างสังเขป โดยยังไม่ต้องคำนึงถึงรายละเอียดเกี่ยวกับโครงสร้างวงจรจริง นอกจากนั้น VHDL ยังเป็นภาษาที่สนับสนุนลักษณะต่างๆ ของระบบดิจิตอลที่มี ความซับซ้อนได้ทั้งหมด ดังนั้น VHDL จึงเป็นภาษาที่น่าสนใจในการศึกษาและนำไปใช้งานเป็นอย่างยิ่ง วิวัฒนาการของภาษา VHDL เริ่มต้นประมาณปี ค.ศ. 1981 เมื่อกระทรวงกลาโหมสหรัฐอเมริกา หรือ DoD (Department of Defense) ได้พยายามปรับปรุงอุปกรณ์อิเล็กทรอนิกส์และคอมพิวเตอร์ที่ใช้ในกิจการทางทหาร ให้มีความทันสมัยมากขึ้น ประกอบกับเทคโนโลยีทางด้านไมโครอิเล็กทรอนิกส์มีการพัฒนาไปอย่างรวดเร็วดังจะเห็นได้ จากการนำวงจรดิจิตอลหลายๆ วงจรมาทำการผลิตอยู่บนแผ่นซิลิกอนที่มีพื้นที่เพียง 1 - 2 ตารางเซนติเมตรเท่านั้น ซึ่ง เป็นผลให้ประสิทธิภาพในการทำงานของวงจรสูงขึ้นตลอดจนความน่าเชื่อถือ ในการทำงานและความคงทนต่อสภาพ แวดล้อมสูง แต่เนื่องจากในขณะนั้นขั้นตอนของการออกแบบ การผลิต และการตรวจสอบวงจรต้นแบบ เป็นขบวนการที่ ต้องใช้วิศวกร และเวลาในดำเนินการมาก ฉะนั้นทาง DoD จึงจัดตั้งโครงการขึ้นมาเพื่อศึกษาวิธีการที่ช่วยในการพัฒนา วงจรอิเล็กทรอนิกส์ โดยเฉพาะอย่างยิ่งวงจรระบบดิจิตอล ให้สามารถนำไปผลิตได้เร็วขึ้น ซึ่งโครงการดังกล่าวมีชื่อว่า "Very High Speed Integrated Circuits" หรือ VHSIC โดยในระยะแรกนั้นโครงการนี้ถือเป็นความลับทาง ด้านความมั่งคงของประเทศ และอยู่ภายใต้ความควบคุมดูแลของ United States International Traffic and Arms Regulations (ITAR) สำหรับมาตรฐานของภาษาที่ใช้บรรยาย พฤติกรรมวงจรหรือฮาร์ดแวร์ของระบบ สำหรับโครงการ VHSIC ที่ DoDได้ให้ไว้สามารถสรุปได้ดังนี้
- ต้องเป็นภาษาที่นำไปเขียนรูปแบบระบบดิจิตอล และมีคุณสมบัติที่สามารถเข้าใจได้ทั้งมนุษย์และเครื่อง คอมพิวเตอร์โดยไม่ต้องมีการแปลหรือเปลี่ยนแปลงอีก
- สามารถนำไปใช้เป็นเอกสารประกอบโครงการได้
- ต้องเป็นภาษาที่เขียนขึ้นสำหรับใช้จำลองการทำงานของวงจร
ฉะนั้นภาษาดังกล่าวนี้จึงจัดเป็นภาษาโปรแกรมระดับสูง เช่นเดียวกับภาษาปาสคาล หรือภาษาซี ซึ่งในทางวิศวกรรม ภาษาที่ใช้ในการออกแบบฮาร์ดแวร์นี้เรียกว่า "Hardware Description Language" หรือ HDL

ในตอนเริ่มแรกนั้น DoD ได้มอบหมายให้บริษัทไอบีเอ็ม เท็กซัสอินสตูเมนท์ และอินเตอร์เมทริกซ์ เป็นผู้ศึกษาและพัฒนา โครงการ ซึ่งการดำเนินงานเป็นไปอย่างต่อเนื่อง จนกระทั่งในปี ค.ศ.1985 ทาง ITAR ได้ยกเลิกข้อจำกัดในการถ่ายทอด เทคโนโลยีทางทหารออกจากโครงการนี้ ดังนั้นภาษา VHDL จึงเริ่มเป็นที่รู้จักกันโดยทั่วไป และประมาณปี ค.ศ. 1987 IEEE ได้ทำการกำหนดมาตรฐานของภาษานี้เป็น IEEE 1076-1987 และมีชื่อเรียกว่า VHDL ซึ่งมาตรฐานนี้ได้รับ การปรับปรุงจนเป็นมาตรฐาน IEEE 1076-1993 หรือ VHDL 1993 เนื่องจากในขณะนั้น DoD เป็นลูกค้ารายใหญ่ ของอุตสาหกรรมอิเล็กทรอนิกส์และคอมพิวเตอร์ ดังนั้นจึงมีผู้รับโครงการต่างๆ จาก DoD ไปดำเนินการวิจัยและพัฒนา เป็นจำนวนมาก และเพื่อให้ทุกโครงการอยู่ในมาตรฐานเดียวกันหมด ดังนั้นทาง DoD จึงได้กำหนดว่า ทุกๆ โครงการต้อง เขียนอยู่ในรูปของภาษา VHDLเท่านั้น ซึ่งทำให้ DoD สามารถนำโครงการเหล่านี้ไปจำลองกับเครื่องคอมพิวเตอร์ได้ หลายๆระบบ
ข้อกำหนด
DoD ได้ตั้งข้อกำหนดสำหรับภาษา VHDL ในเดือนมกราคมปี ค.ศ.1983 ไว้ดังนี้
1. ลักษณะทั่วไป
DoD ได้กำหนดให้ VHDL เป็นภาษาสำหรับการออกแบบและบรรยายของฮาร์ดแวร์ ซึ่งหมายถึงความสามารถ ในการอธิบายและออกแบบในระดับสูง การจำลอง (Simulation) การสังเคราะห์ (Synthesis) และการทดสอบ (Testing) นอกจากนั้น VHDL ยังถูกกำหนดไว้สำหรับการบรรยายฮาร์ดแวร์ตั้งแต่ระดับบนซึ่งก็คือระบบจนถึง ระดับเกทอีกด้วย เนื่องจากในการทำงานของระบบดิจิตอลนั้น ทุกๆ องค์ประกอบภายในระบบไม่ว่าเล็กหรือใหญ่ จะทำงานไปพร้อมๆ กัน ซึ่งในเรื่องของความพร้อมเพรียงในการทำงานนี้ก็ถือเป็นข้อกำหนดที่สำคัญอย่างหนึ่งของ VHDL ด้วยเช่นกัน (สำหรับในภาษาที่ใช้ในการบรรยายฮาร์ดแวร์นั้นความพร้อมเพรียงจะหมายถึงทุกๆ คำสั่ง องค์ประกอบ เกทหรือวงจรลอจิกจะถูกนำมาปฏิบัติทั้งหมด ดังนั้นในที่สุดแล้วก็จะดูเหมือนว่าได้มีการปฏิบัติไป พร้อมๆ กัน)
2. สนับสนุนการออกแบบแบบลำดับขั้น
การออกแบบแบบลำดับขั้นเป็นลักษณะที่สำคัญอย่างหนึ่งสำหรับการออกแบบระบบที่มีหลายๆ ระดับ โดยในการ ออกแบบจะประกอบด้วยส่วนการบรรยายการเชื่อมต่อ และส่วนการบรรยายหน้าที่การทำงาน ซึ่งหน้าที่การทำงาน ของระบบสามารถกำหนดได้ด้วยตัวเอง หรืออาจถูกกำหนดโดยโครงสร้างที่ประกอบด้วยองค์ประกอบย่อยๆ ลง ไปได้เช่นกัน แต่ที่ระดับล่างสุด องค์ประกอบต้องถูกบรรยายหน้าที่การทำงานด้วยตัวมันเอง และไม่สามารถกำหนด การทำงานโดยลักษณะแบบโครงสร้างได้
3. ไลบรารี 
VHDL ได้สนับสนุนการมีไลบรารีเพื่อระบบการจัดการที่ดี ผู้ออกแบบสามารถกำหนดลักษณะและการทำงานของ อุปกรณ์พื้นฐานไว้ในระบบไลบรารี หรือจะใช้ไลบรารีที่ระบบได้จัดเตรียมไว้แล้วก็ได้ โมเดลและการบรรยายที่ถูก ต้องควรจัดเก็บไว้ในไลบรารีหลังจากที่ได้ผ่านการคอมไพล์เรียบร้อยแล้วเพื่อให้ผู้ออกแบบคนอื่นๆ สามารถนำไป ใช้ได้ด้วย
4. ลำดับคำสั่ง 
แม้ว่าการปฏิบัติคำสั่งหรือกระบวนการโดยพร้อมเพรียงกันจะเป็นคุณสมบัติที่สำคัญของ VHDL ก็ตาม ตัวภาษา เองก็ยังมีการจัดเตรียมลักษณะการควบคุมแบบลำดับคำสั่งไว้ให้ด้วย เมื่อผู้ออกแบบได้กำหนดหน้าที่และองค์ประกอบ ที่ทำงานพร้อมกันของระบบไว้เรียบร้อยแล้ว ผู้ออกแบบยังสามารถบรรยายหน้าที่การทำงานซึ่งเป็นรายละเอียดภายใน ของแต่ละองค์ประกอบได้ในลักษณะเดียวกับการเขียนโปรแกรมที่ประกอบด้วยโครงสร้างแบบ case, if - then - else และ loop ทั่วๆ ไปได้ การบรรยายแบบลำดับคำสั่งทำให้การออกแบบหน้าที่การทำงานของอุปกรณ์กระทำได้ สะดวกและง่ายขึ้น อย่างไรก็ตามโครงสร้างทั้งหมดของ VHDL ก็ยังคงเป็นการทำงานแบบพร้อมเพรียงกันเช่นเดิม
5. การกำหนดคุณสมบัติ
นอกจากการกำหนดอินพุทและเอาท์พุทแล้ว เงื่อนไขอื่นๆ ก็มีผลต่อการปฏิบัติหน้าที่ของอุปกรณ์ฮาร์ดแวร์ด้วยเช่นกัน โดยสิ่งนี้รวมถึงสภาพแวดล้อมและลักษณะทางกายภาพของอุปกรณ์นั้นๆ ด้วย ซึ่งภาษาสำหรับการออกแบบที่ดีควร ให้ผู้ออกแบบกำหนดคุณสมบัติของอุปกรณ์ที่ใช้ได้ด้วย เช่น สามารถกำหนดขนาด ลักษณะทางกายภาพเวลา โหลด และเงื่อนไขทางสภาพแวดล้อมอื่นๆ ซึ่งความสามารถในการกำหนดคุณสมบัตินี้ก็เป็นส่วนหนึ่งที่มีอยู่ในภาษา VHDL ด้วยเช่นกัน
6. ชนิดของข้อมูล 
VHDL สามารถกำหนดชนิดของข้อมูลไม่เพียงแต่ชนิด BIT และ BOOLEAN เท่านั้น แต่ยังสามารถกำหนดชนิด ของข้อมูลเป็นจำนวนเต็ม จำนวนจริง จุดทศนิยม และชนิดลำดับการนับ (Enumerate Type) หรือแม้แต่ชนิดของ ข้อมูลที่ผู้ออกแบบกำหนดขึ้นมาเองก็ได้
7. โปรแกรมย่อย 
ความสามารถในการใช้ฟังก์ชันและโพรซีเจอร์ (Procedure) ก็เป็นข้อกำหนดอีกอย่างหนึ่งใน VHDL ซึ่งผู้ออกแบบ สามารถนำโปรแกรมย่อยมาใช้ในการเปลี่ยนแปลงชนิดของข้อมูล การกำหนดหน่วยของลอจิก การกำหนดตัวกระทำต่างๆ หรือหน้าที่อื่นๆ ตามที่ต้องการได้เช่นเดียวกับการเขียนโปรแกรมทั่วไป
8. การควบคุมเวลา 
VHDL อนุญาตให้ผู้ออกแบบสามารถกำหนดเวลาในการส่งผ่านข้อมูลหรือสัญญาณได้ตามต้องการ การตรวจสอบ การออกแบบเกทหรือการหน่วงเวลาก็สามารถกระทำได้โดยการกำหนดช่วงเวลาที่แน่นอนหรือกำหนดให้มีการรอคอย เหตุการณ์ (Event) นอกจากนี้ก็ยังสามารถกำหนดรูปแบบของสัญญาณนาฬิกาได้อีกด้วย
9. การกำหนดแบบโครงสร้าง 
การกำหนดโครงสร้างขององค์ประกอบต่างๆ สามารถกระทำได้ในทุกระดับของการออกแบบ โดยการกำหนดโครง สร้างขององค์ประกอบร่วมที่เกิดจากองค์ประกอบย่อยซึ่งแตกต่างกันหรือ เหมือนกันก็เป็นข้อกำหนดอย่างหนึ่งของ VHDL เช่นกัน