Function
Function คือการรวมกลุ่มคำสั่งที่ทำงานหนึ่งอย่างไว้ภายใต้ชื่อเดียว แล้วเรียกใช้ซ้ำได้ ช่วยให้โค้ดสั้นลง อ่านง่าย และแก้ bug ที่เดียวได้ผลทุกที่ที่เรียกใช้
ฟังก์ชันสำเร็จรูป
หลัง #include <bits/stdc++.h> จะมีฟังก์ชันให้ใช้มากมาย
ที่ใช้บ่อยคือ
cout << abs(-5) << '\n'; // 5
cout << sqrt(64.0) << '\n'; // 8
cout << pow(2, 10) << '\n'; // 1024 (คืนค่าเป็น double)
cout << log2(64) << '\n'; // 6
cout << gcd(12, 18) << '\n'; // 6 (C++17)
cout << lcm(4, 6) << '\n'; // 12 (C++17)
ระวัง: pow และ sqrt คืนค่าเป็น
double ซึ่งอาจคลาดเคลื่อนเล็กน้อย เช่น
(int)pow(10, 2) อาจได้ 99 บางเครื่อง
ถ้าต้องการยกกำลังจำนวนเต็มให้เขียน loop คูณเอง หรือใช้ fast exponentiation ในบท
Divide and Conquer
เขียนฟังก์ชันเอง
ฟังก์ชันหนึ่งประกอบด้วย
ชนิดของค่าที่คืน (return type) ถ้าไม่คืนค่าใช้
voidชื่อฟังก์ชัน
parameters ที่รับเข้ามา
ชุดคำสั่ง (body) และ
return
#include <bits/stdc++.h>
using namespace std;
int addition(int a, int b) {
return a + b;
}
void greet(string name) { // void: ไม่คืนค่า
cout << "Hello " << name << '\n';
}
int main() {
int z = addition(5, 3);
cout << "The result is " << z << '\n'; // The result is 8
greet("POSN"); // Hello POSN
}
ฟังก์ชันต้องถูกประกาศ ก่อน จุดที่เรียกใช้ จึงมักเขียนไว้เหนือ
main
เทียบกับฟังก์ชันทางคณิตศาสตร์
ฟังก์ชัน f(x) = x^{2} + 1 ในคณิตศาสตร์เขียนเป็น C++ ได้ตรง ๆ โดยต้องระบุชนิดของ x และผลลัพธ์เพิ่ม
long long f(long long x) {
return x * x + 1;
}
ต่างจากคณิตศาสตร์ตรงที่ฟังก์ชันใน C++ อาจทำงานอื่นด้วย เช่น พิมพ์ผลหรือแก้ไขตัวแปร global (เรียกว่า side effect)
Pass by value และ pass by reference
ปกติ parameter จะ คัดลอกค่า เข้ามา (pass by value)
การแก้ไขในฟังก์ชันจึงไม่กระทบตัวแปรต้นฉบับ ถ้าต้องการแก้ตัวแปรต้นฉบับ ให้ใส่
& หน้าชื่อ parameter (pass by reference)
void swapByValue(int a, int b) {
int c = a; a = b; b = c; // สลับแค่สำเนา
}
void swapByRef(int &a, int &b) {
int c = a; a = b; b = c; // สลับตัวแปรต้นฉบับ
}
int main() {
int x = 0, y = 1;
swapByValue(x, y);
cout << x << ' ' << y << '\n'; // 0 1
swapByRef(x, y);
cout << x << ' ' << y << '\n'; // 1 0
}
ส่ง vector และ string ด้วย reference
การส่ง vector แบบ by value จะคัดลอกทั้งก้อนทุกครั้งที่เรียก
ซึ่งใช้เวลา O(n) ถ้าเรียกบ่อย (เช่น ใน
recursion) จะ TLE ได้ ให้ส่งด้วย const &
เมื่อไม่ต้องการแก้ไข
long long total(const vector<int> &v) { // ไม่คัดลอก และห้ามแก้ v
long long s = 0;
for (int x : v) s += x;
return s;
}
Scope ของตัวแปร
Local variable ประกาศใน function หรือใน
{ }ใช้ได้เฉพาะในบล็อกนั้นGlobal variable ประกาศนอกทุก function ใช้ได้ทุกที่ และมีค่าเริ่มต้นเป็น 0
int g; // global
int addition(int a, int b) {
int r = a + b; // r เป็น local ของ addition
g = b; // แก้ global ได้
return r;
}
int main() {
int z = addition(5, 3);
cout << "z is " << z << '\n'; // z is 8
cout << "g is " << g << '\n'; // g is 3
// cout << r; // error: 'r' was not declared in this scope
}
ในการแข่งขันนิยมใช้ global สำหรับ array ขนาดใหญ่และข้อมูลที่หลายฟังก์ชันใช้ร่วมกัน เช่น กราฟ
ตัวอย่าง
ระยะทางระหว่างสองจุด
ระยะทางแบบยุคลิด (Euclidean) ระหว่าง A\left( x_{1},y_{1} \right) และ B\left( x_{2},y_{2} \right) คือ \sqrt{\left( x_{1} - x_{2} \right)^{2} + \left( y_{1} - y_{2} \right)^{2}}
double dist(double x1, double y1, double x2, double y2) {
return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}
ระยะทางแบบ Manhattan
ระยะเมื่อเดินได้แค่แนวตั้งและแนวนอน เช่น เดินตามถนนที่ตัดเป็นตาราง: |x_{1} - x_{2}| + |y_{1} - y_{2}|
long long manhattan(long long x1, long long y1, long long x2, long long y2) {
return abs(x1 - x2) + abs(y1 - y2);
}
ลำดับที่นิยามจากพจน์ก่อนหน้า
ถ้า a_{1} = 2 และ a_{n} = a_{n - 1} + 2n จะเขียนฟังก์ชันหาพจน์ถัดไปจากพจน์ก่อนหน้าได้
long long nextTerm(long long prev, int n) { // คืน a_n เมื่อรู้ a_(n-1)
return prev + 2LL * n;
}
int main() {
long long a = 2; // a_1
for (int n = 2; n <= 5; n++) {
a = nextTerm(a, n);
cout << a << ' '; // 6 12 20 30
}
}
ข้อผิดพลาดที่พบบ่อย
ลืม
returnในฟังก์ชันที่ไม่ใช่void: compile ผ่านแค่ warning แต่ค่าที่ได้เป็นขยะ (undefined behavior) ให้ compile ด้วย-Wallเสมอคาดว่าแก้ค่า parameter แล้วต้นฉบับจะเปลี่ยน แต่ลืมใส่
&ส่ง vector ขนาดใหญ่ by value ในฟังก์ชันที่ถูกเรียกบ่อย
ใช้
powกับจำนวนเต็ม แล้วได้ค่าคลาดเคลื่อน
โจทย์ฝึกฝน (Practice Problems)
ลองทำโจทย์เหล่านี้จาก CSES Problem Set เพื่อฝึกใช้ทักษะจากบทนี้ โดยเริ่มจากโจทย์ที่ง่ายที่สุดก่อน
โจทย์เพิ่มเติม: CSES Problem Set และ programming.in.th