ฟังก์ชัน
Author: Pakin Olanraktham & njoop
ฟังก์ชันคืออะไร
Function (ฟังก์ชัน) คือกลุ่มของคำสั่งที่เรานำมารวมกันไว้ เพื่อให้สามารถเรียกใช้งานได้เมื่อต้องการ
หนึ่งในฟังก์ชันที่เห็นได้บ่อยที่สุด ก็คือ main() โดยฟังก์ชันนี้จะเป็นจุดเริ่มต้นของโปรแกรม
ประโยชน์หลักๆ ในการเขียนฟังก์ชัน คือเราไม่จำเป็นต้องเขียนโค้ดซ้ำๆ หลายครั้ง สามารถเขียนครั้งเดียวแล้วเรียกใช้กี่ครั้งก็ได้ ตามที่ต้องการ
ฟังก์ชัน สามารถประกาศได้ ดังนี้
#include <stdio.h>
void hello() {
printf("Hello!\n");
}
int main() {
hello(); // เรียกใช้ฟังก์ชัน
}
// output คือ Hello!
โดยในตัวอย่างได้ทำการประกาศฟังก์ชันชื่อ hello เมื่อทำการเรียกใช้ hello() จะรันคำสั่งภายใน นั่นก็คือ printf("Hello!\n") นั่นเอง
สามารถเรียกใช้ฟังก์ชันหลายๆ ครั้งได้ เช่น
#include <stdio.h>
void hello() {
printf("Hello!\n");
}
int main() {
hello();
hello();
hello();
}
/*
output คือ
Hello!
Hello!
Hello!
*/
โครงสร้างของฟังก์ชัน
แน่นอนว่า ฟังก์ชันสามารถรับค่าเข้าไปประมวลผล และคืนค่าออกมาได้ ลองดูโครงสร้างฟังก์ชันดังต่อไปนี้
return_type function_name(parameter1, parameter2, ...) {
// คำสั่งต่าง ๆ
return value; // ส่งค่ากลับ (ถ้ามี)
}
- return_type คือ ชนิดข้อมูลที่ฟังก์ชันจะส่งค่ากลับ เช่น
int,float,char,void - function_name คือ ชื่อฟังก์ชัน (ตั้งชื่อได้เอง แต่ห้ามซ้ำกับชื่อที่สงวนไว้ เช่น
main) - parameter คือ ตัวแปรที่ส่งเข้ามาให้ฟังก์ชันทำงาน (จะไม่มีหรือมีกี่ค่าก็ได้)
- value คือ ค่าที่ส่งกลับออกไป (ถ้า
voidไม่จำเป็นต้องใช้return)
นี่เป็นฟังก์ชันตัวอย่าง หากต้องการแสดงผลรวมของเลข 2 เลขที่ใส่เข้าไป เราไม่จำเป็นต้องมีค่าส่งกลับ (return) จึงประกาศเป็นชนิด void แต่ต้องมี parameter นั่นก็คือเลขที่ต้องการใส่เข้าไป
#include <stdio.h>
// มี parameter แต่ไม่มี return
void printSum(int a, int b) {
printf("%d + %d = %d\n", a, b, a+b);
}
int main() {
printSum(5, 7); // output คือ "5 + 7 = 12"
}
หมายเหตุ: ค่าที่เราใส่ไปในฟังก์ชัน เช่น 5, 7 ใน printSum(5, 7) จะเรียกว่า อาร์กิวเมนต์ (argument)
แต่ถ้าเกิดต้องการนำค่าผลรวมไปใช้ด้วย จำเป็นต้องมีทั้ง return และ parameter เช่น
#include <stdio.h>
// มี parameter และมี return
int add(int x, int y) {
return x+y;
}
int main() {
int result = add(10, 20); // สามารถนำค่านี้ไปใช้ต่อได้
printf("%d\n", result); // output คือ 30
}
ตัวอย่าง
โค้ดด้านล่าง จะเป็นสรุปวิธีการเขียนของฟังก์ชันแต่ละชนิด
#include <stdio.h>
// ไม่มี parameter และไม่มี return
void hello() {
printf("Hello!\n");
}
// มี parameter แต่ไม่มี return
void printSum(int a, int b) {
printf("%d + %d = %d\n", a, b, a+b);
}
// ไม่มี parameter แต่มี return
int getNum() {
return 42;
}
// มี parameter และมี return
int add(int x, int y) {
return x+y;
}
int main() {
// เรียกใช้แต่ละฟังก์ชัน
hello(); // output คือ "Hello!"
printSum(5, 7); // output คือ "5 + 7 = 12"
int num = getNum();
printf("%d\n", num); // output คือ 42
int result = add(10, 20);
printf("%d\n", result); // output คือ 30
}
การใช้ return เพื่อหยุดการทำงานของฟังก์ชัน
คำสั่ง return เป็นคำสั่งที่ใช้ในการคืนค่าในฟังก์ชัน (ถ้ามี) แต่หลังจากนั้นจะหยุดการทำงานของฟังก์ชันไปเลย ดังนั้น เราสามารถใช้ return เป็นการหยุดฟังก์ชันไปในตัวได้
พิจารณาโค้ดตัวอย่างต่อไปนี้
void checkAge(int age) {
if(age < 18) {
printf("Not allowed\n");
return; // หยุดการทำงานของฟังก์ชันไปในตัว
}
printf("Allowed\n");
}
ฟังก์ชัน 2 ฟังก์ชันนี้จะแสดงผลลัพธ์เหมือนกัน
โจทย์ตัวอย่าง
จงเขียนฟังก์ชันเพื่อคำนวณพื้นที่สามเหลี่ยมสูง H ฐานยาว B (H และ B เป็นจำนวนเต็ม) โดยคืนค่าออกมาเป็นทศนิยม 2 ตำแหน่ง
เฉลย
#include <stdio.h>
float triangle_area(int H, int B) { // ประกาศฟังก์ชัน ชื่อว่า "triangle_area" ซึ่งรับค่าเป็นจำนวนเต็ม 2 ตัว และคืนค่าออกมาเป็นทศนิยม
return ((float) H) * B / 2; // เปลี่ยน H ให้เป็นทศนิยมก่อน เพื่อที่จะได้คำตอบออกมาเป็นทศนิยม แล้วนำไปเข้าสูตร พื้นที่ = 1/2 * ฐาน * สูง
}
int main() {
printf("%.2f\n", triangle_area(5, 10)); // จะได้ output ออกมาเป็น 25.00
}
ขอบเขตของตัวแปร
ตัวแปรในภาษา C/C++ จะมีขอบเขตที่สามารถใช้งานได้ (เรียกว่า scope)
เช่น ตัวแปรที่ถูกประกาศใช้ใน if จะสามารถใช้ได้แค่ใน if เท่านั้น ไม่สามารถใช้นอก if ได้
#include <stdio.h>
int main() {
int x = 5;
if(x == 5) {
int y = 2;
}
printf("%d", y) // compile error
}
สังเกตว่า printf จะไม่สามารถคอมไพล์ได้ เพราะตัวแปร y ไม่สามารถใช้นอก if ได้
สามารถเขียนโค้ดข้างบนให้คอมไฟล์ผ่านได้ดังนี้
#include <stdio.h>
int main() {
int x = 5, y;
if(x == 5) {
y = 2;
}
printf("%d", y); // output คือ 2
}
ในทำนองเดียวกัน ตัวแปรที่ถูกประกาศภายในฟังก์ชัน จะใช้งานได้แค่ในฟังก์ชันที่ตัวแปรถูกประกาศเท่านั้น
ตัวแปรประเภท global
เราสามารถประกาศตัวแปรไว้ข้างนอกฟังก์ชันใดๆ ได้ โดยตัวแปรนี้ (เรียกว่า ตัวแปรประเภท global) ทุกฟังก์ชัน จะสามารถเข้าถึงได้ สามารถเปลี่ยนแปลงค่าได้ เช่น
#include <stdio.h>
int count = 0;
void increase_count() {
count = count + 1; // เพิ่มค่า count ด้วย 1
}
int main() {
increase_count(); // count = 0 + 1 = 1
increase_count(); // count = 1 + 1 = 2
increase_count(); // count = 2 + 1 = 3
printf("%d\n", count); // output จะได้ 3
}
การประกาศฟังก์ชัน
การประกาศฟังก์ชัน สามารถแบ่งได้เป็น 2 วิธี คือ
- ประกาศก่อนใช้งาน
- ประกาศหลังใช้งาน
ในตัวอย่างด้านบน ได้ทำการประกาศฟังก์ชันไว้ก่อนฟังก์ชัน main() ซึ่งถือเป็นการประกาศก่อนใช้งาน
ถ้าเกิดต้องการประกาศหลัง main() จำเป็นต้องประกาศ prototype ไว้ก่อน แล้วค่อยเขียนฟังก์ชันทีหลัง เช่น
#include <stdio.h>
int add(int, int);
int main() {
printf("%d", add(1, 2)); // output คือ 3
}
int add(int x, int y) {
return x+y;
}
prototype เป็นเหมือนประโยคที่บอกข้อมูลต่างๆ เกี่ยวกับฟังก์ชัน เช่น ชื่อ พารามีเตอร์ โดยไม่จำเป็นต้องบอกทั้งฟังก์ชัน แต่เป็นข้อมูลคร่าวๆ ให้โปรแกรมรู้ว่ามีฟังก์ชันนี้อยู่ โดยในโค้ดด้านบน int add(int, int); เป็น prototype แบบหนึ่ง
ถ้าเกิดประกาศฟังก์ชันหลัง main() และไม่ประกาศ prototype โปรแกรมจะ compile error
Recursive Function
Recursive Function คือฟังก์ชันที่ เรียกใช้งานตัวเอง ภายในฟังก์ชันเดียวกัน ใช้เมื่อปัญหาสามารถแบ่งออกเป็นปัญหาย่อยๆ ที่มีลักษณะเหมือนกัน
return_type function_name(parameters) {
if (เงื่อนไขหยุดทำงาน) // base case หรือกรณีฐาน
return ค่าบางอย่าง;
else
return function_name(ค่าที่เล็กลง); // recursive case
}
- Base case คือ เงื่อนไขหยุด recursion (สำคัญมาก ถ้าไม่มีก็จะวนไม่รู้จบ)
- Recursive case ส่วนที่ฟังก์ชันเรียกตัวเอง
ตัวอย่าง
ต้องการหาค่า factorial(n) เมื่อ n เป็นจำนวนเต็มที่ไม่ติดลบ
#include <stdio.h>
int factorial(int n) {
if (n == 0) return 1; // base case คือ เมื่อ n เป็น 0 ให้คืนค่า 1
return n * factorial(n - 1); // recursive case คือ เมื่อ n > 0 ให้คืนค่า n * factorial(n-1) [จาก n! = n * (n-1)!]
}
int main() {
int num = 5;
printf("%d! = %d\n", num, factorial(num)); // จะได้ output คือ "5! = 120"
return 0;
}
ในโค้ดด้านบน สมมติว่าเราเรียกใช้ factorial(5) สามารถมองเป็นแผนภาพได้ดังนี้
factorial(5)
= 5 * factorial(4)
= 5 * 4 * factorial(3)
= 5 * 4 * 3 * factorial(2)
= 5 * 4 * 3 * 2 * factorial(1)
= 5 * 4 * 3 * 2 * 1 * factorial(0) // ไม่เรียกฟังก์ชันต่อ เพราะคำสั่ง if (n == 0) return 1;
= 5 * 4 * 3 * 2 * 1 * 1
= 120
ข้อควรระวัง
ข้อผิดพลาดที่พบเห็นได้บ่อย เวลาเขียน recursive นั่นก็คือ ลืมใส่กรณีฐาน หรือ base case ซึ่งอาจทำให้โปรแกรมรันไปเรื่อยๆ โดยไม่รู้จบ เช่นโค้ดดังนี้
#include <stdio.h>
int factorial(int n) {
return n * factorial(n - 1);
}
int main() {
int num = 5;
printf("%d! = %d\n", num, factorial(num));
return 0;
}
หากลองรัน จะพบว่า โค้ดนี้จะไม่แสดงผลใดๆ และเกิดข้อผิดพลาดระหว่างการทำงาน
| Problem | Source | Difficulty | Solution |
|---|---|---|---|
| Perket | PROG | ? | View |
Built-in Fucntion
| Source | Resources |
|---|---|
| CPP Reference | อ่านฟังก์ชันต่างๆ ได้เพิ่มที่นี่ |
ในภาษา C เรามีฟังก์ชันสำเร็จรูป ที่สามารถนำมาใช้ได้ โดยที่เราไม่ต้องเขียนฟังก์ชันเอง ซึ่งก่อนจะใช้ เราต้อง import Library นั้นๆ มาก่อน โดย Library ที่ใช้หลักๆ ได้แก่
stdio.h (Input/Output)
ซึ่งก็คือ Library ซึ่งมีฟังก์ชันสำหรับการนำเข้า ส่งออก ข้อมูลต่างๆ ที่เราเคยใช้กันอยู่แล้ว เช่น
scanf("%d", &x);printf("%d\n", x);
stdlib.h (Commonly Used Functions)
| Source | Resources |
|---|---|
| W3Schools | อ่านเพิ่มเติม |
เป็น Library ที่มีฟังก์ชั่นที่พบได้บ่อยๆ เช่น
abs(x)คืนค่าสัมบูรณ์ของจำนวนเต็ม (ชนิดint) เช่นabs(-5)จะได้5(ถ้าเป็นทศนิยมให้ใช้fabsซึ่งอยู่ในmath.h)atoi(str)แปลงสตริงเป็นจำนวนเต็ม (int)atof(str)แปลงสตริงเป็นทศนิยมแบบdoubleatoll(str)แปลงสตริงเป็นจำนวนเต็มแบบlong longqsort(base, n, size, compar)ฟังก์ชันสำหรับเรียงลำดับ ซึ่งเราต้องส่ง pointer ของอาเรย์ จำนวนสมาชิก ขนาดของแต่ละสมาชิก และฟังก์ชันเปรียบเทียบ
ตัวอย่างการใช้งานเบื้องต้น
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("abs(-12) = %d\n", abs(-12)); // 12
char a[] = "123";
char b[] = "3.14159";
char c[] = "900000000000";
int ai = atoi(a); // 123
double bd = atof(b); // 3.141590
long long cll = atoll(c); // 900000000000
printf("ai=%d bd=%.2f cll=%lld\n", ai, bd, cll);
}
การใช้ qsort
รูปแบบการใช้งาน
void qsort(
void *base, // ตำแหน่งเริ่มอาเรย์
size_t nitems, // จำนวนสมาชิก
size_t size, // ขนาดของหนึ่งสมาชิก เช่น sizeof(int)
int (*compar)(const void *, const void *) // ฟังก์ชันเปรียบเทียบ
);
ฟังก์ชันเปรียบเทียบต้องคืนค่า:
< 0ถ้า a ควรมาก่อน b= 0ถ้าเท่ากัน (ลำดับไม่สำคัญ)> 0ถ้า a ควรมาหลัง b
โจทย์
จงเรียงอาเรย์จำนวนเต็มจากน้อยไปมาก แล้วจากมากไปน้อย
เฉลย
#include <stdio.h>
#include <stdlib.h>
int cmp_asc(const void *p1, const void *p2) {
int a = *(const int*)p1;
int b = *(const int*)p2;
return a - b; // น้อยไปมาก
}
int cmp_desc(const void *p1, const void *p2) {
int a = *(const int*)p1;
int b = *(const int*)p2;
return b - a; // มากไปน้อย (สลับลำดับ)
}
int main() {
int asc[] = {5, 2, 9, 1, 5, 6};
int desc[] = {5, 2, 9, 1, 5, 6};
int n = sizeof(asc)/sizeof(asc[0]);
qsort(asc, n, sizeof(int), cmp_asc);
qsort(desc, n, sizeof(int), cmp_desc);
printf("Ascending : ");
for(int i=0;i<n;i++) printf("%d ", asc[i]);
printf("\n");
printf("Descending: ");
for(int i=0;i<n;i++) printf("%d ", desc[i]);
printf("\n");
}
/*
ผลลัพธ์
Ascending : 1 2 5 5 6 9
Descending: 9 6 5 5 2 1
*/
stbool.h (Boolean Function)
ซึ่งก็คือ Library ซึ่งเพิ่มชนิดข้อมูล bool สามารถเก็บได้แค่ 2 ค่า false กับ true โดยมีขนาด 1 ไบต์
bool a = 0;a = true;if(a) //do something
math.h (Math Functions)
| Source | Resources |
|---|---|
| CPP Reference | อ่านเพิ่มเติม |
เป็น Library ที่มีฟังก์ชันทางคณิตศาสตร์อยู่ เช่น
sqrt(x)หารากที่สองpow(x, y)คำนวณเลขยกกำลัง \(x^y\)fabs(x)หาค่าสัมบูรณ์ \(|x|\)fmin(x, y),fmax(x, y)หาค่าน้อยสุด/มากสุด ตามลำดับM_PIเป็นค่าคงที่ของ PI ทศนิยม 36 ตำแหน่ง
โดยที่ฟังก์ชันข้างต้นทั้งหมด จะคืนค่าออกมาเป็น float และ parameter ของฟังก์ชัน สามารถใส่ได้ทั้ง int และ float (x, y อาจเป็น int หรือ float ก็ได้)
#include <stdio.h>
#include <math.h>
int main() {
printf("%.2f\n", fmin(5, 108)); // 5.00
printf("%.2f\n", pow(2, 10)); // 1024.00
printf("%.2f\n", sqrt(2)); // 1.41
printf("%.2f\n", fabs(-728)); // 728.00
}
ctype.h (Char Functions)
| Source | Resources |
|---|---|
| W3Schools | อ่านเพิ่มเติม |
เป็น Library ซึ่งมีฟังก์ชันสำหรับการทำงานเกี่ยวกับ char เช่น
islower(c)/isupper(c)เป็นการตรวจสอบว่า c เป็นตัวอักษรพิมพ์เล็ก / พิมพ์ใหญ่ไหมtolower(c)/toupper(c)เป็นการเปลี่ยน c ให้เป็นตัวอักษรพิมพ์เล็ก / พิมพ์ใหญ่isalpha(c)เป็นการตรวจสอบว่า c เป็นตัวอักษรภาษาอังกฤษไหมisdigit(c)เป็นการตรวจสอบว่า c เป็นเลขไหม
#include <stdio.h>
#include <ctype.h>
int main() {
char c = 'A';
if(islower(c))
printf("Lower! ");
else
printf("Upper! ");
printf("%c",tolower(c));
//จะได้ Upper a
}
string.h (String Functions)
เป็น Library ซึ่งมีฟังก์ชันสำหรับการทำงานเกี่ยวกับ string
strlen(s)หาความยาว string (จะนับจากตัวแรกจนถึง '\0' ไม่ได้นับความยาวของ Array เช่นchar str[5] = "IJK";จะคืนค่า 3)strcmp(a, b)เป็นการเทียบสตริง- หาก a มาก่อน b ตามลำดับพจนานุกรม จะคืนค่าที่น้อยกว่า 0
- หาก a เหมือนกับ b (เป็น string เดียวกัน) จะคืนค่า 0
- หาก a มาหลัง b ตามลำดับพจนานุกรม จะคืนค่าที่มากกว่า 0
strcpy(dest, src)คือการ copy string ของ src ไปใส่ dest เช่น
strcat(dest, src)คือการนำ string ของ src ไปต่อกับ dest เช่น