สำนักวิชาเทคโนโลยีสารสนเทศและการสื่อสาร Unit 8 Functions กนกวรรธน์ เซี่ยงเจ็น สำนักวิชาเทคโนโลยีสารสนเทศและการสื่อสาร มหาวิทยาลัยนเรศวร วิทยาเขตสารสนเทศพะเยา
School of Information and Communication Technology, NU PYO เนื้อหา บทนำ นิยามของฟังก์ชัน ประเภทของฟังก์ชัน การประกาศเพื่อใช้งานฟังก์ชัน การระบุ Function Prototypes การส่งข้อมูลให้กับฟังก์ชันเพื่อประมวลผล (Argument) Pass by Value Pass by Reference School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO เนื้อหา การ Pass by Value การ Pass by Reference การส่ง อาร์เรย์ ให้กับฟังก์ชัน การส่ง Pointer ให้กับฟังก์ชัน การส่งข้อมูลออกจากฟังก์ชัน (Return) การ Recursion ขอบเขตของตัวแปร (Scope) Global Local สรุป School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO บทนำ นิสิตได้ทราบไปแล้วว่า การเขียนโปรแกรมนั้นมีองค์ประกอบอยู่หลายอย่าง บางอย่างระบบก็ได้สร้างเตรียมไว้ให้ หรือไม่เราก็ต้องสร้างขึ้นมาเอง อย่างไรก็ดี นิสิตอาจไม่ทราบว่า ณ ขณะที่เราเขียนโปรแกรมนั้น เราได้ใช้งาน ฟังก์ชัน (Function) ของระบบ โดยไม่รู้ตัว เช่น main, printf, scanf, toupper, tolower โดยที่บางฟังก์ชัน หากนิสิตไม่ทราบว่าระบบมีการจัดเตรียมไว้ให้ นิสิตก็สามารถสร้างขึ้นมาเองได้ เช่น toupper หรือ tolower เป็นต้น School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO นิยามของฟังก์ชัน ฟังก์ชัน คือ โมดูล (Module) ที่เราสร้างขึ้นมาเพื่อทำงานอย่างใด อย่างหนึ่ง โดยเราอาจจำเป็นต้องมีการส่งข้อมูล ให้กับฟังก์ชัน เพื่อให้ฟังก์ชันประมวลผล แล้วส่งค่าผลลัพธ์ กลับออกมาเพียง 1 ค่าเท่านั้น เมื่อฟังก์ชันทำงานเสร็จสิ้นแล้ว ลักษณะเด่นของฟังก์ชัน คือ เมื่อประมวลผลฟังก์ชันเสร็จ จะสามารถส่งค่ากลับออกมาจากฟังก์ชันได้เพียง 1 ค่าเท่านั้น หากนิสิตต้องการให้ฟังก์ชัน ส่งค่ากลับออกมา มากกว่า 1 ค่านิสิตจำเป็นที่จะต้องใช้ Pointer โดยส่งข้อมูลให้กับฟังก์ชันแบบ Pass by Reference School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO ประเภทของฟังก์ชัน ฟังก์ชัน มีอยู่ 2 ประเภท ประกอบด้วย System Function เป็นฟังก์ชันที่ระบบมีให้เราอยู่แล้ว เช่น printf, scanf, clrscr, toupper, tolower เป็นต้น เพียงแต่ว่าเราต้องมีการ include header file เข้ามาเพื่ออ้างอิง User-Defined Function เป็นฟังก์ชันที่เราสร้างขึ้นมาเอง เพื่อใช้งาน หรือเพื่อแบ่งส่วนของงานออกมาเป็นโมดูล เพื่อให้โปรแกรมเมอร์แยกส่วนกันพัฒนา จากนั้นค่อยนำมารวมกันในภายหลัง โดยฟังก์ชันประเภทนี้ อาจจำเป็นต้องประกาศ function prototype ให้กับโปรแกรมทราบ เนื่องจากว่า ฟังก์ชันที่เราสร้างขึ้นมาเองนั้น ไม่ได้มีอยู่ใน header file ของภาษาซีนั้นเอง School of Information and Communication Technology, NU PYO
การประกาศเพื่อใช้งานฟังก์ชัน data-type func-name(type1 arg1, type2 arg2,..., typen argn){ . . . [ return (variable-name); ] } คำอธิบาย data-type ชนิดของข้อมูลที่จะถูกส่งกลับ(Return)ออกมาจากฟังก์ชัน เมื่อฟังก์ชันนั้น ทำงานเสร็จสิ้น func-name ชื่อของฟังก์ชัน (อย่าให้ซ้ำกับ คำสงวน หรือ ฟังก์ชันที่มีอยู่อยู่แล้วใน header file) type1, ... , n ชนิดข้อมูลของตัวแปร arg ที่จะถูกส่งเข้าไปในฟังก์ชัน School of Information and Communication Technology, NU PYO
การประกาศเพื่อใช้งานฟังก์ชัน data-type func-name(type1 arg1, type2 arg2,..., typen argn){ . . . [ return (variable-name); ] } คำอธิบาย arg1, ... , n ชื่อของตัวแปรที่เราต้องการส่งเข้าไปในฟังก์ชัน (Argument) return คำสั่งที่ใช้สำหรับส่งผลลัพธ์ออกจากฟังก์ชัน จะมีหรือไม่มีก็ได้ หากไม่มีการ return ต้องระบุ data-type func-name เป็น void func-name variable-name ชื่อตัวแปร หรือข้อมูลที่ถูกส่งออกมาจากฟังก์ชัน โดยมักจะมีชนิดเดียวกับ data-type ของ func-name School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example โปรแกรมสำหรับแปลงตัวอักษรพิมพ์เล็ก ให้เป็นพิมพ์ใหญ่ รับข้อมูลจากคีย์บอร์ดเข้ามาเป็นอักษรพิมพ์เล็ก 1 ตัวเก็บไว้ในตัวแปรชื่อ lower จากนั้น ส่งตัวอักษรข้างต้นไปให้กับฟังก์ชัน lower_to_uppper เพื่อเปลี่ยนให้อักษรพิมพ์เล็กข้างต้น กลายเป็นอักษรตัวพิมพ์ใหญ่ (result) ส่งผลลัพธ์ที่ได้กลับมาจากฟังก์ชัน นำค่าผลลัพธ์ที่ได้จากข้อ 2 มาเก็บไว้ในตัวแปรชื่อ upper จากนั้น แสดงตัวอักษรพิมพ์ที่ได้สามารถแปลงออกมาได้ School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example #include <stdio.h> char lower_to_upper(char input){ char result; result = (input >= ‘a’ && input <= ‘z’) ? (‘A’ + input - ‘a’) : input; return (result); } void main(){ char lower, upper; printf(“Please enter a lowercase character :”); scanf(“%c”, &lower); upper = lower_to_upper(lower); printf(“\n The uppercase equivalent is %c \n\n”, upper); ต้องมีคำสั่ง return (result) เพื่อส่งผลลัพธ์กลับออกไป ให้นิสิตสังเกตว่า ชนิดข้อมูลของตัวแปร result จะเป็นชนิดเดียวกับ ด้านหน้าของฟังก์ชัน lower_to_upper คือ char เหมือนกัน School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example char lower_to_upper(char input){ char result; if (input >= ‘a’ && input <= ‘z’) result = (‘A’ + input - ‘a’); else result = input return (result); } char lower_to_upper(char input){ if (input >= ‘a’ && input <= ‘z’) return (‘A’ + input - ‘a’); else return (input); } School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำถาม-คำตอบ คำถาม: นิสิตต้องการสร้างฟังก์ชันเพื่อใช้งาน แต่ว่าไม่ต้องการส่งค่ากลับออกมาจากฟังก์ชัน จะสามารถทำได้หรือไม่? คำตอบ: สามารถทำได้ โดยนิสิตใช้คำสำคัญว่า void ซึ่งหมายถึงไม่มีการระบุ ตัวอย่างใกล้ตัวเช่น void main() นิสิตจะสังเกตว่า ในฟังก์ชัน main() จะไม่มีการส่งค่ากลับ School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example float SUM(int a, float b){ float result = 0; result = a + b; return (result); } void main(void){ int x=2; float y=3.7, answer; answer = SUM(x, y); printf(“A+B = %f”, answer); void SUM(int a, float b){ float result = 0; result = a + b; printf(“A+B = %f”, result); } void main( ){ int x=2; float y=3.7, answer; SUM(x, y); 1 2 School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำอธิบาย float SUM(int a, float b){ float result = 0; result = a + b; return (result); } void main(void){ int x=2; float y=3.7, answer; answer = SUM(x, y); printf(“A+B = %f”, answer); จากตัวอย่างนิสิตจะเห็นได้ว่า ฟังก์ชัน main ไม่มีการส่งค่ากลับเนื่องจากระบุ void เอาไว้ โปรแกรมเรียกใช้งานฟังก์ชัน SUM โดยส่ง x ที่มีตำแหน่งตรงกับ a และ y ที่มีตำแหน่งตรงกับ b วิธีการนี้เรียกว่า Pass by Value เป็นการส่งค่าไปให้ฟังก์ชัน เมื่อประมวลผลเสร็จ จะมีการส่งค่ากลับโดยใช้คำสั่ง return result กลับออกมา แล้วแสดงผลลัพธ์ทางจอภาพ (สังเกตว่า ชนิดข้อมูลของ result จะตรงกับชนิดข้อมูลของฟังก์ชัน SUM คือ float) 1 School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำอธิบาย void SUM(int a, float b){ float result = 0; result = a + b; printf(“A+B = %f”, result); } void main( ){ int x=2; float y=3.7, answer; SUM(x, y); // SUM(int a, float b) จากตัวอย่างนิสิตจะเห็นได้ว่า ฟังก์ชัน main ไม่มีการส่งค่ากลับเนื่องจากระบุ void เอาไว้ โปรแกรมเรียกใช้งานฟังก์ชัน SUM โดยส่ง x ที่มีตำแหน่งตรงกับ a และ y ที่มีตำแหน่งตรงกับ b วิธีการนี้เรียกว่า Pass by Value เป็นการส่งค่าไปให้ฟังก์ชัน เมื่อประมวลผลเสร็จ จะไม่มีการส่งค่ากลับโดยใช้คำสั่ง return เนื่องจากเราประกาศให้ฟังก์ชัน SUM มีชนิดเป็น void แต่จะมีการพิมพ์ผลลัพธ์ในฟังก์ชัน SUM เลย ซึ่งก็ให้ผลลัพธ์เหมือนกับตัวอย่างที่ 1 2 School of Information and Communication Technology, NU PYO
การระบุ Function Prototypes ในการเขียนโปรแกรม ที่เรามีฟังก์ชันที่สร้างขึ้นเอง เราจำเป็นต้องมีการบอกให้กับโปรแกรม (main) ทราบว่าจะมีการเรียกใช้งานฟังก์ชันเหล่านี้ จากโปรแกรม ดังนั้น เราจึงต้องมีการประกาศ Function Prototypes ให้กับโปรแกรมทราบ ก่อนการใช้งาน เหมือนกับ ถ้านิสิตจะใช้คำสั่ง clrscr นิสิตก็ต้องมีการ include <conio.h> เข้ามา สรุปง่ายๆ คือ เป็นการประกาศให้โปรแกรม main ทราบว่าเรามีการสร้างฟังก์ชันขึ้นมาใช้งานเอง เพิ่มเติมจากที่ include เข้ามาจาก header file นั้นเอง โปรแกรมจะได้รู้จักและไม่ error School of Information and Communication Technology, NU PYO
การระบุ Function Prototypes data-type func-name(type1 arg1, type2 arg2,..., typen argn); คำอธิบาย data-type ชนิดของข้อมูลที่จะถูกส่งกลับออกมาจากฟังก์ชัน เมื่อฟังก์ชันนั้น ทำงานเสร็จสิ้น func-name ชื่อของฟังก์ชัน (อย่าให้ซ้ำกับ คำสงวน หรือ ฟังก์ชันที่มีอยู่อยู่แล้วใน header file) type1, ... , n ชนิดข้อมูลของตัวแปร arg ที่จะถูกส่งเข้าไปในฟังก์ชัน arg1, ... , n ชื่อของตัวแปรที่เราต้องการส่งเข้าไปในฟังก์ชัน (Argument) School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example ตัวอย่างโปรแกรม factorial 1! = 1 2! = 2 * (1)! = 2 * 1 3! = 3 * (2)! = 3 * 2 * 1 4! = 4 * (3)! = 4 * 3 * 2 * 1 n! = n * (n - 1)! School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example long int factorial(int n){ int i; long int result = 1; if(n>1) for(i=2; i <= n; i++) result = result * i; return (result); } void main(void){ int x; long int answer; printf(“\nx = ”); scanf(“%d”, &x); answer = factorial(x); printf(“n! = %ld”, answer); long int factorial(int n); // function prototype void main(void){ int x; long int answer; printf(“\nx = ”); scanf(“%d”, &x); answer = factorial(x); printf(“n! = %ld”, answer); } long int factorial(int n){ int i; long int result = 1; if(n>1) for(i=2; i <= n; i++) result = result * i; return (result); 1 2 School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำอธิบาย long int factorial(int n){ int i; long int result = 1; if(n>1) for(i=2; i <= n; i++) result = result * i; return (result); } void main(void){ int x; long int answer; printf(“\nx = ”); scanf(“%d”, &x); answer = factorial(x); printf(“n! = %ld”, answer); โปรแกรมการหาค่า factorial โดยเราสร้างฟังก์ชัน ชื่อ factorial(int n) ขึ้นมาเพื่อรับค่า n แล้วคำนวณเพื่อให้ได้ผลลัพธ์เป็นเลขจำนวนเต็มบวก โปรแกรมนี้ไม่ได้มีการประกาศ Function Prototype เนื่องจากมีการประกาศฟังก์ชันไว้ก่อนหน้า ทำให้ main program สามารถรู้จักฟังก์ชันได้โดยไม่ต้องประกาศ Function Prototype 1 School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำอธิบาย long int factorial(int n); // function prototype void main(void){ int x; long int answer; printf(“\nx = ”); scanf(“%d”, &x); answer = factorial(x); printf(“n! = %ld”, answer); } long int factorial(int n){ int i; long int result = 1; if(n>1) for(i=2; i <= n; i++) result = result * i; return (result); โปรแกรมการหาค่า factorial โดยเราสร้างฟังก์ชัน ชื่อ factorial(int n) ขึ้นมาเพื่อรับค่า n แล้วคำนวณเพื่อให้ได้ผลลัพธ์เป็นเลขจำนวนเต็มบวก โปรแกรมนี้ต้องมีการประกาศ Function Prototype เนื่องจากไม่มีการประกาศฟังก์ชันไว้ก่อนหน้า ทำให้ main program ไม่สามารถรู้จักได้ฟังก์ชัน factorial ได้ ต้องประกาศ Function Prototype เนื่องจากฟังก์ชัน factorial จริงๆ อยู่ด้านล่าง main 2 School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำถาม-คำตอบ คำถาม: ฟังก์ชันสามารถส่งค่ากลับมาได้เพียง 1 ค่าเท่านั้น หากเราต้องการให้ฟังก์ชันส่งค่ากลับออกมา มากกว่า 1 ค่าจะสามารถทำได้หรือไม่ อย่างไร? คำตอบ: นิสิตสามารถทำได้ โดยการประยุกต์ความรู้ที่ได้จากบทที่ 7 Pointers โดยข้อมูลที่เราส่งให้กับฟังก์ชันจะถูกเรียกว่าการ Pass by Reference School of Information and Communication Technology, NU PYO
การส่งข้อมูลให้กับฟังก์ชันเพื่อประมวลผล (Argument) Pass by Value Pass by Reference การส่งข้อมูลทั้ง 2 แบบ เหมือนหรือต่างกันอย่างไร? School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO คำถาม-คำตอบ คำถาม: การส่งข้อมูลทั้ง 2 แบบ เหมือนหรือต่างกันอย่างไร? คำตอบ: การส่งข้อมูลทั้ง 2 แบบมีความเหมือนกัน แต่แตกต่างกันที่จำนวนผลลัพธ์ที่ส่งกลับออกจากฟังก์ชันไม่เหมือนกัน การ Pass by Value ส่งผลลัพธ์กลับออกมาได้เพียงแค่ 1 ข้อมูล Argument ที่ส่งไปให้ฟังก์ชัน ถ้ามีการเปลี่ยนแปลงค่าในฟังก์ชัน จะไม่ส่งผลกระทบต่อตัวต้นฉบับที่ส่งไป การ Pass by Reference ส่งผลลัพธ์กลับออกมาได้มากกว่า 1 ข้อมูล. Argument ที่ส่งไปให้ฟังก์ชัน ถ้ามีการเปลี่ยนแปลงค่าในฟังก์ชัน จะส่งผลกระทบต่อตัวต้นฉบับที่ส่งไป School of Information and Communication Technology, NU PYO
Pass by Value vs. Reference เปรียบเทียบ Pass by Value Pass by Reference รูปแบบข้อมูล (Argument) ที่ส่งให้ฟังก์ชัน ส่งข้อมูลสำเนา อ้างอิงค่า (Value) ส่งข้อมูลตัวจริง อ้างอิงที่อยู่ (Address) ค่าที่สามารถส่งกลับ(return) ออกมาจากฟังก์ชัน 0 ถึง 1 0 ถึงจำนวน Argument + 1 ผลกระทบเมื่อมีการเปลี่ยนแปลง Argument ระหว่างประมวลผลภายในฟังก์ชัน ต่อตัวแปรต้นฉบับ ไม่มี มี การประกาศ Argument int x int &x, int y[ ] , int *z School of Information and Communication Technology, NU PYO
โดยที่ฟังก์ชันทั่วๆ ไปที่เราใช้งานก็มักจะใช้วิธีการนี้ Pass by Value เป็นการส่งข้อมูล(Argument) ให้กับฟังก์ชันเพื่อประมวลผล โดย Argument ที่ส่งไปจะไม่มีผลกระทบเมื่อ ฟังก์ชันรับค่าแบบ Pass by Value ก็จะคัดลอก เอาเฉพาะข้อมูลที่จัดเก็บในตัวแปรนั้นๆ ไป เหมือนเราถ่ายเอกสาร ถ้าเราทำลายสำเนาต้นฉบับก็จะไม่ได้รับผลกระทบใดๆ หรือการที่เราให้เพื่อนลอกการบ้าน ต้นฉบับก็เหมือนเดิม วิธีการนี้เรียกว่า Pass by Value โดยที่ฟังก์ชันทั่วๆ ไปที่เราใช้งานก็มักจะใช้วิธีการนี้ School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example: Pass by Value float SUM(int a, float b){ float result; result = a + b; a = 0; b = 0; return (result); } void main(void){ int x=2; float y=3.7, answer; printf(“Before pass by value: x=%d, y=%f”, x, y); answer = SUM(x, y); printf(“A+B = %f”, answer); printf(“\nAfter pass by value: x=%d, y=%f”, x, y); ให้นิสิตสังเกตการส่งข้อมูล (Argument) ไปให้กับฟังก์ชัน SUM(int a, float b) เป็นการส่งอาร์กิวเมนต์แบบ Pass by Value เนื่องจากว่าค่าของตัวแปรที่ส่งเข้าไป คือ answer = SUM(x, y) เมื่อมีการประมวลผลในฟังก์ชัน มีการเปลี่ยนแปลงค่า a, b ซึ่งเป็นสำเนาของ x, y ตามลำดับ แต่เมื่อเราแสดงผลลัพธ์ก่อน และหลังการเรียกใช้งานฟังก์ชัน ก็จะพบว่าค่า x, y ไม่มีการเปลี่ยนแปลง ทั้งๆ ที่ในฟังก์ชัน SUM มีการระบุให้ a, b เป็น 0 ภายหลังจากที่ได้นำมาหาผลรวมแล้ว สังเกตว่ามีการเปลี่ยนค่า a, b หลังจากการหาผลรวม ซึ่ง a, b เป็นตัวแทนค่าของ x, y ในรูปแบบ ที่เป็นสำเนา จึงทำให้ต้นฉบับ ไม่ได้รับผลกระทบจากการเปลี่ยน แปลงดังกล่าว ทำให้ x, y ยังมีค่า เป็น 2, 3.7 ตามเดิม ไม่ใช่ 0, 0 Before pass by value : x=2, y=3.700000 A+B = 5.700000 After pass by value: x=2, y=3.700000 School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Pass by Reference เป็นการส่งข้อมูล(Argument) ให้กับฟังก์ชันเพื่อประมวลผล โดย Argument ที่ส่งไปจะมีผลกระทบเมื่อ ฟังก์ชันรับค่าแบบ Pass by Reference เนื่องจากเป็นส่งตัวจริง (Address) ของตัวแปรไป ถ้าเราทำลายต้นฉบับก็จะได้รับผลกระทบด้วย หรือการที่เราให้เพื่อนลอกการบ้าน แต่เพื่อนเอาต้นฉบับของเราไปแก้ไขรหัสประจำตัว กับชื่อ การบ้านนั้นก็จะไม่ใช่ของเราอีกต่อไป วิธีการนี้เรียกว่า Pass by Reference School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Pass by Reference รูปแบบของการ Pass by Reference ตัวแปรทั่วไป Pointer อาร์เรย์ (Array) Structure (บทที่ 9) School of Information and Communication Technology, NU PYO
Example: Pass by Reference float SUM(int &a, float &b){ float result; result = a + b; a = 0; b = 0; return (result); } void main(void){ int x=2; float y=3.7, answer; printf(“Before pass by reference: x=%d, y=%f”, x, y); answer = SUM(x, y); printf(“A+B = %f”, answer); printf(“\nAfter pass by reference : x=%d, y=%f”, x, y); ให้นิสิตสังเกตการส่งข้อมูล (Argument) ไปให้กับฟังก์ชัน SUM(int &a, float &b) เป็นการส่งอาร์กิวเมนต์แบบ Pass by Reference เนื่องจากว่าค่าของตัวแปรที่ส่งเข้าไป คือ answer = SUM(x, y) เมื่อมีการประมวลผลในฟังก์ชัน มีการเปลี่ยนแปลงค่า a, b ซึ่งเป็นต้นฉบับของ x, y ตามลำดับ เมื่อเราแสดงผลลัพธ์ก่อน และหลังการเรียกใช้งานฟังก์ชัน ก็จะพบว่าค่า x, y มีการเปลี่ยนแปลง เพราะว่าในฟังก์ชัน SUM มีการระบุให้ a, b เป็น 0 ภายหลังจากที่ได้นำมาหาผลรวมแล้ว สังเกตว่ามีการเปลี่ยนค่า a, b หลังจากการหาผลรวม ซึ่ง a, b เป็นตัวแทนค่าของ x, y ในรูปแบบ ที่เป็นต้นฉบับ จึงทำให้ต้นฉบับ ได้รับผลกระทบจากการเปลี่ยน แปลงดังกล่าว ทำให้ x, y ยังมีค่า เป็น 0, 0 เมื่อแสดงผลออกมา Before pass by reference : x=2, y=3.700000 A+B = 5.700000 After pass by reference: x=0, y=0 School of Information and Communication Technology, NU PYO
Pass by Value vs. Reference x y 2 3.7 x y 2 3.7 float SUM1(int a, float b){ float result; result = a + b; a = 0; b = 0; return (result); } void main(void){ int x=2; float y=3.7, answer; printf(“Before pass by value: x=%d, y=%f”, x, y); answer = SUM1(x, y); printf(“A+B = %f”, answer); printf(“\nAfter pass by value: x=%d, y=%f”, x, y); float SUM2(int &a, float &b){ float result; result = a + b; a = 0; b = 0; return (result); } void main(void){ int x=2; float y=3.7, answer; printf(“Before pass by reference: x=%d, y=%f”, x, y); answer = SUM2(x, y); printf(“A+B = %f”, answer); printf(“\nAfter pass by reference : x=%d, y=%f”, x, y); a b 2 3.7 a b 2 3.7 2 2 3 3 a b a b x y 2 3.7 x y 1 1 4 4 Before pass by value : x=2, y=3.700000 A+B = 5.700000 After pass by value: x=2, y=3.700000 Before pass by reference : x=2, y=3.700000 A+B = 5.700000 After pass by reference: x=0, y=0 School of Information and Communication Technology, NU PYO
Pass by Reference : ตัวแปรทั่วไป x y 2 3.7 float MULTIPLY(int &a, float b){ float result; result = a * b; a = 0; b = 0; return (result); } void main(void){ int x=2; float y=3.7, answer; printf(“Before pass by reference: x=%d, y=%f”, x, y); answer = MULTIPLY (x, y); printf(“A*B = %f”, answer); printf(“\nAfter pass by reference : x=%d, y=%f”, x, y); จากโปรแกรมตัวอย่าง สามารถอธิบายขั้นตอน ดังนี้ กำหนดค่าเริ่มต้นให้ตัวแปร x=2, y=3.7 โปรแกรมมีการเรียกใช้งานฟังก์ชัน MULTIPLY(x, y) ตอนส่งค่าจะมีการส่งค่า &a = x, b = y โดย x ถูกส่งไปแบบ by reference และ y ถูกส่งไปแบบ by value ระหว่างที่โปรแกรมเรียกใช้งานฟังก์ชัน MULTIPLY ได้มีการเปลี่ยนแปลงค่าของ a = 0, b = 0 ซึ่งการเปลี่ยนแปลงค่าครั้งนี้ จะมีผลกระทบกับ x, y ก็ต่อเมื่อมีการส่งค่าแบบ by reference นั้นก็คือ x แต่ y ส่งค่าแบบ by value จึงไม่ได้รับผลกระทบ เมื่อแสดงค่าผลลัพธ์หลังจากใช้งานฟังก์ชัน MULTIPLY เสร็จ จะเห็นได้ว่า x จะมีค่าเปลี่ยนไปx = 2 เป็น x = 0 แต่ว่าค่าของ y จะยังเป็น 3.7 เท่าเดิม a b 2 3.7 2 3 a b x y 3.7 1 4 Before pass by reference : x=2, y=3.700000 A+B = 7.400000 After pass by reference: x=0, y=3.7 School of Information and Communication Technology, NU PYO
Pass by Reference : Pointer การส่งข้อมูล Pointer ให้กับฟังก์ชัน (อาร์กิวเมนต์: Argument) เพื่อประมวลผล โดยเป็นการส่ง Address เข้าไปในฟังก์ชัน ข้อสังเกต การส่ง Pointer เป็นอาร์กิวเมนต์ให้ฟังก์ชัน ก็เป็นการ Pass by Reference โดยอัตโนมัติ เมื่อมีการเปลี่ยนแปลงค่าอาร์กิวเมนต์ในฟังก์ชัน ต้นฉบับของอาร์เรย์ก็จะมีการเปลี่ยนแปลงไปด้วย School of Information and Communication Technology, NU PYO
Pass by Reference : Pointer x y 2 3.7 float SUM(int *a, float b){ float result; result = *(a) + b; *(a) = 0; b = 0; return (result); } void main(void){ int x=2; float y=3.7, answer; printf(“Before pass by reference: x=%d, y=%f”, x, y); answer = SUM (&x, y); printf(“A+B = %f”, answer); printf(“\nAfter pass by reference : x=%d, y=%f”, x, y); จากโปรแกรมตัวอย่าง สามารถอธิบายขั้นตอน ดังนี้ กำหนดค่าเริ่มต้นให้ตัวแปร x=2, y=3.7 โปรแกรมมีการเรียกใช้งานฟังก์ชัน SUM(&x, y) ตอนส่งค่าจะมีการส่งค่า *a = &x, b = y โดย x ถูกส่งไปแบบ by reference และ y ถูกส่งไปแบบ by value ระหว่างที่โปรแกรมเรียกใช้งานฟังก์ชัน SUM ได้มีการเปลี่ยนแปลงค่าของ *(a) = 0, b = 0 ซึ่งการเปลี่ยนแปลงค่าครั้งนี้ จะมีผลกระทบกับ x, y ก็ต่อเมื่อมีการส่งค่าแบบ by reference นั้นก็คือ x แต่ y ส่งค่าแบบ by value จึงไม่ได้รับผลกระทบ เมื่อแสดงค่าผลลัพธ์หลังจากใช้งานฟังก์ชัน SUM เสร็จ จะเห็นได้ว่า x จะมีค่าเปลี่ยนไปx = 2 เป็น x = 0 แต่ว่าค่าของ y จะยังเป็น 3.7 เท่าเดิม a b 2 3.7 2 3 a b x y 3.7 1 4 Before pass by reference : x=2, y=3.700000 A+B = 5.400000 After pass by reference: x=0, y=3.7 School of Information and Communication Technology, NU PYO
Pass by Reference : Array การส่งข้อมูลอาร์เรย์ให้กับฟังก์ชัน (อาร์กิวเมนต์: Argument) เพื่อประมวลผล โดยเป็นการส่ง Address แรกของอาร์เรย์เข้าไปในฟังก์ชัน คล้ายการส่ง Pointer เข้าไป ข้อสังเกต การส่งอาร์เรย์เป็นอาร์กิวเมนต์ให้ฟังก์ชัน ก็เป็นการ Pass by Reference โดยอัตโนมัติ เมื่อมีการเปลี่ยนแปลงค่าอาร์กิวเมนต์ในฟังก์ชัน ต้นฉบับของอาร์เรย์ก็จะมีการเปลี่ยนแปลงไปด้วย School of Information and Communication Technology, NU PYO
ตัวอย่างโปรแกรม (เรียงลำดับตัวเลข) 3 #include <stdio.h> #define MAX 5 // function prototype void bubble_sort(int X[ ]); void main(){ int i; int data[MAX] = {10,2,1,5,8}; bubble_sort( data );// call function for(i=0; i<MAX; i++){ printf(“%d, ”, data[ i ]); } // end for i } // end main void bubble_sort(int X[ ]){ int i, j, temp; for(i=0; i<MAX; i++){ for(j=i+1; j<MAX; j++){ if(X[ j ] < X[ i ]){ // swap temp = X[ i ]; X[ i ] = X[ j ]; X[ j ] = temp; } // end if } // end for j } // end for i } // end function 1 2 ผลลัพธ์ที่ได้ 1, 2, 5, 8, 10, School of Information and Communication Technology, NU PYO
คำอธิบาย Pass by Reference : Array ประกาศ Prototype ของ void bubble_sort(int X[ ]); เรียกใช้งาน ฟังก์ชัน bubble_sort(data); คือ ส่งอาร์เรย์ชื่อ data ไปให้ฟังก์ชัน bubble_sort ประมวลผล โปรแกรมจะแทนอาร์เรย์ data ที่ส่งไป ด้วยอาร์เรย์ X จากนั้นทำการเรียงลำดับข้อมูลจากมากไปน้อย เสมือนเป็นการเรียงลำดับข้อมูลจากอาร์เรย์ต้นฉบับของ data คำถาม: นิสิตจะสังเกตได้ว่า ฟังก์ชันนี้ไม่มีการ return ค่าเนื่องจากเราใช้ void แต่ทำไมเวลาเราแสดงผลข้อมูล data หลังจากเรียกใช้งานฟังก์ชัน bubble_sort แล้วข้อมูลจึงมีการเรียงลำดับ คำตอบ: เพราะว่าการส่งข้อมูลเป็นอาร์กิวเมนต์ ก็คือการส่งต้นฉบับไปให้ฟังก์ชัน ดังนั้นการเรียงลำดับข้อมูลที่เกิดขึ้นในฟังก์ชัน ก็เสมือนหนึ่งมีการเปลี่ยนแปลงข้อมูลในต้นฉบับด้วย เพราะว่าเป็นการ Pass by Reference School of Information and Communication Technology, NU PYO
การส่งข้อมูลออกจากฟังก์ชัน (Return) การส่งค่ากลับออกมาจากฟังก์ชันมี 3 วิธี ไม่ต้องการส่งค่ากลับออกมาเลย ตอนประกาศฟังก์ชันก็ให้ใช้คำว่า void เช่น void main() เป็นต้น ต้องการให้ส่งค่ากลับออกมา 1 ค่า ตอนประกาศฟังก์ชันก็ให้ระบุชนิดข้อมูลที่ต้องการส่งออกมาจากฟังก์ชัน เช่น float SUM(x, y) โดยที่นิสิตจะต้องมีคำสั่งในบรรทัดสุดท้ายของฟังก์ชัน SUM ให้มีการ return ค่าข้อมูลกลับออกมาเป็นชนิดเดียวกับที่ระบุไว้ คือ float ต้องการให้ส่งค่ากลับออกมา มากกว่า 1 ค่าก็ให้เขียนโปรแกรมโดยอ้างอิงแบบ Pass by Reference School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO การ Recursion การ Recursion คือ การประมวลผลที่มีการเรียกฟังก์ชันซ้อนฟังก์ชันตัวเดิม (Loop) โดยให้ทำงานไปเรื่อยๆ จนกว่าเงื่อนไขจะเป็นจริง แต่มีข้อควรระวังก็คือ ถ้าเงื่อนไขในการจบการทำงานของ Recursion ไม่ถูกต้องก็จะมีการวนทำงานแบบอนันต์ (Infinity Loop) จนกว่าเครื่องจะแฮงค์ School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example: Recursion ตัวอย่างโปรแกรม factorial 1! = 1 2! = 2 * (1)! = 2 * 1 3! = 3 * (2)! = 3 * 2 * 1 4! = 4 * (3)! = 4 * 3 * 2 * 1 n! = n * (n - 1)! School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO Example: Recursion long int factorial(int n); void main(void){ int x; long int answer; printf(“\nx = ”); scanf(“%d”, &x); answer = factorial(x); printf(“n! = %ld”, answer); } long int factorial(int n){ int i; long int result = 1; if(n>1) for(i=2; i <= n; i++) result = result * i; return (result); long int factorial(int n); void main(void){ int x; long int answer; printf(“\nx = ”); scanf(“%d”, &x); answer = factorial(x); printf(“n! = %ld”, answer); } long int factorial(int n){ if(n <= 1) return (1); else return (n * factorial(n-1)); 1 2 สังเกตว่า จะมีการเรียกฟังก์ชัน factorial ซ้อน factorial เรียกว่า Recursion School of Information and Communication Technology, NU PYO
ขอบเขตของตัวแปร (Scope) อาจกล่าวสรุปได้ว่า โปรแกรมที่เราเขียนขึ้นด้วยภาษาซีนั้นจะประกอบขึ้นมาจากการ รวมกันของฟังก์ชัน (Function) ย่อยๆ โดยที่โปรแกรมจะเริ่มการทำงานที่ main() โดยที่ในแต่ละฟังก์ชัน นิสิตจะสังเกตได้ว่า เรามีการประกาศตัวแปร นิสิตเคยสงสัยหรือไม่ว่า เราจำเป็นต้องประกาศตัวแปร ที่มีชื่อแตกต่างกัน สำหรับแต่ละฟังก์ชันหรือไม่ เช่น int x ใน main() int x ใน SUM() คือ ตัวแปรเดียวกันหรือไม่ ดังนั้น ขอบเขตของตัวแปร คือคำตอบ School of Information and Communication Technology, NU PYO
ขอบเขตของตัวแปร (Scope) ขอบเขตของตัวแปร มี 2 แบบ ตัวแปรแบบ Global คือ ตัวแปรที่เราประกาศขึ้นมา เพื่อให้ฟังก์ชันอื่น ๆ สามารถเรียกใช้งานตัวแปรนี้ได้ด้วย ตัวแปรแบบ Local คือ ตัวแปรที่เราประกาศขึ้นมา เพื่อใช้ภายในฟังก์ชันของตัวเองเท่านั้น School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO สรุป ฟังก์ชัน เป็นส่วนสำคัญของโปรแกรม หากเรามองว่าโปรแกรม คือรถยนต์ เราก็จะประกอบด้วยฟังก์ชันหลายอย่างเพื่อให้มีองค์ประกอบเป็นรถยนต์ โดยแตกงานเป็นส่วนย่อย โดยที่แต่ละส่วนก็ทำหน้าที่ของตัวเองไป เช่น เครื่องยนต์ คือ ฟังก์ชันในสร้างพลังงานขับเคลื่อนให้รถยนต์ พวงมาลัย คือ ฟังก์ชันในการกำหนดทิศทางของรถยนต์ คันเร่ง คือ ฟังก์ชันในการเพิ่มความเร็วให้กับรถยนต์ เบรก คือ ฟังก์ชันในการลดความเร็วของรถยนต์ อย่างไรก็ดี มนุษย์ คือ ฟังก์ชันที่สำคัญที่สุดในการที่จะประกอบ และควบคุมรถยนต์ให้สามารถทำงานได้ตามความต้องการ เหมือนกับการที่เรารู้ว่า เมื่อต้องการหยุดรถ ต้องเหยียบเบรก ไม่ใช่คันเร่ง School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO สรุป ลักษณะเด่นของฟังก์ชัน คือ เป็นโมดูลที่ใช้ทำงานอะไรบางอย่าง โดยจะรับข้อมูล (Argument) เข้าไปเพื่อทำงาน ได้ดังนี้คือ ไม่ส่งข้อมูลเข้าไปในฟังก์ชันเลย (void) เช่น ฟังก์ชัน clrscr(void); ส่งข้อมูลเข้าไปเป็นตัวสำเนา a, b เข้าไป (Pass by Value) เช่น SUM(a, b); ส่งข้อมูลที่เป็นต้นฉบับ a แต่ส่งสำเนา b เข้าไป (Pass by Reference) เช่น SUM(&a, b); โดยจำนวนข้อมูล(Argument) ที่จะส่งให้ฟังก์ชัน เพื่อประมวลผล จะต้องระบุตามรูปแบบที่เราได้กำหนดไว้ตอนประกาศฟังก์ชัน School of Information and Communication Technology, NU PYO
School of Information and Communication Technology, NU PYO สรุป ลักษณะเด่นของฟังก์ชัน คือ เมื่อทำงานเสร็จฟังก์ชันสามารถส่งค่าผลลัพธ์กลับมา (Return) ได้ดังนี้ ไม่ส่งค่าอะไรกลับออกมาเลย (void) ส่งค่ากลับออกมา 1 ค่า (return & Pass by Value) ส่งค่ากลับออกมา มากกว่า 1 ค่า (return & Pass by Reference) โดยที่ปกติฟังก์ชัน มักจะมีการส่งค่ากลับออกมา 1 ค่า การประกาศ Function Prototype จะต้องทำ ก็ต่อเมื่อมีการเขียนตัว(body) ของฟังก์ชันไว้ ต่อท้ายจาก main หากเขียนตัว(body)ของฟังก์ชันไว้ก่อน main ก็ไม่จำเป็นต้องเขียน Function Prototype School of Information and Communication Technology, NU PYO