15. การเขียนฟังก์ชันเบื้องต้น

 การเขียนฟังก์ชันเบื้องต้น

การเขียนฟังก์ชันเป็นการรวมกลุ่มของโค้ดที่ทำหน้าที่เฉพาะอย่างเข้าไว้ด้วยกัน เช่น ฟังก์ชันสำหรับคำนวณค่าที่จอดรถ อาจจะประกอบขึ้นจากโค้ด 10 บรรทัด เป็นต้น วิธีการผ่านค่าไปยังฟังก์ชัน (function arguments/parameters) ฟังก์ชันที่ส่งค่ากลับมา เช่น ฟังก์ชันสำหรับคำนวณหาพื้นที่สี่เหลี่ยมผืนผ้าจะส่งค่ากลับมาเป็นตัวเลขแบบ double ฟังก์ชันที่ไม่มีการส่งค่ากลับมา (void function) เช่น ฟังก์ชันที่ใช้แสดงตารางสูตรคูณออกทางหน้าจอ




 


ตัวอย่างโปรแกรม

#include <iostream>
#include <vector>

using namespace std;


int main_old() {
    double weight, height;
    cout << "enter weight and height: ";
    cin >> weight >> height;
    double bmi = weight / (height * height);
    cout << "BMI = " << bmi << endl;
    vector<string> category{"Obese L4", "Obese L3", "Obese L2", "Obese L1", "Normal", "Low"};
    double v[]{40, 35, 30, 25, 18.5, 0};
    for (int i = 0; i < category.size(); ++i) {
        if (bmi > v[i]) {
            cout << "BMI category: " << category[i] << endl;
            break;
        }
    }
    return 0;
}

double bodyMassIndex(double weight, double height) {
    return weight / (height * height);
}

string bmiCategory(double bmi) {
    vector<string> category{"Obese L4", "Obese L3", "Obese L2", "Obese L1", "Normal", "Low"};
    double v[]{40, 35, 30, 25, 18.5, 0};
    for (int i = 0; i < category.size(); ++i) {
        if (bmi > v[i]) {
            return category[i];
        }
    }
}

int main() {
    double weight, height;
    cout << "enter weight and height: ";
    cin >> weight >> height;
    double bmi = bodyMassIndex(weight, height);
    cout << "BMI = " << bmi << endl;
    cout << "Category " << bmiCategory(bmi) << endl;
    return 0;
}


========================================================================

ฟังก์ชัน

type name ( parameter1, parameter2, ... )
{
    statements
}
  • type เป็นประเภทของฟังก์ชันสำหรับการส่งค่ากลับ ประเภทของฟังก์ชันนั้นจะเป็นเหมือนประเภทของตัวแปร เช่น Integer, Floating, Double หรือแบบอ็อบเจ็ค ประเภทแบบ void หมายความว่าฟังก์ชันไม่มีค่าที่ต้องส่งกลับ
  • name นั้นเป็นชื่อของฟังก์ชันที่เราสร้างขึ้น มันมีวิธีการตั้งคือโดยการใช้กฏแบบเดียวกันกับการตั้งชื่อตัวแปร มันสามารถประกอบไปด้วยตัวอักษร ตัวเลข และ Underscore (_) แต่ไม่สามารถเริ่มต้นด้วยตัวเลข
  • Parameters เป็นเซ็ตของตัวแปรที่ถูกส่งเข้ามายังฟังก์ชัน ฟังก์ชันสามารถมีหรือไม่มีพารามีเตอร์ก็ได้ ขึ้นกับวัตถุประสงค์ของมัน
  • Statement คือโค้ดของโปรแกรมที่จะทำงานและให้ค่าผลลัพธ์ของฟังก์ชัน

การประกาศฟังก์ชัน

เพื่อประกาศฟังก์ชันในภาษา C++ คุณจำเป็นต้องทำตามรูปแบบของมัน มาดูตัวอย่าง
#include <iostream>

using namespace std;

int sum(int x, int y)
{
    int z = x + y;
    return z;
}

int main()
{
    int a = 3;
    int b = 5;
    cout << "a + b = " << sum(a, b);
    return 0;
}
ในตัวอย่าง เราได้สร้างฟังก์ชันเพื่อหาผลรวมของตัวแปร 2 ตัว โดยประเภทของฟังก์ชันนั้นจะเป็น int นั่นหมายความว่าฟังก์ชันจะส่งค่ากลับเป็นข้อมูลแบบ Integer และชื่อของฟังก์ชันคือ sum และมีพารามิเตอร์สองตัว ดังนั้น เราสามารถเรียกใช้ฟังก์ชัน โดยการใช้ชื่อของมัน และส่งพารามิเตอร์ไปเหมือนที่เราได้ประกาศในฟังก์ชัน เมื่อฟังก์ชันถูกเรียกใช้ มันจะประมวลผลคำสั่งในฟังก์ชัน และจะใช้คำสั่ง return เพื่อส่งค่ากลับมายังจุดเรียกฟังก์ชัน
ในโปรแกรมของเรา จะต้องได้ 8 เป็นค่าส่งกลับ ข้างล่างนี้เป็นผลลัพธ์ของโปรแกรม
a + b = 8

Function parameters

เหมือนที่กล่าวไว้ก่อนหน้า ฟังก์ชันพารามิเตอร์เป็นเซ็ตของตัวแปรหรืออ็อบเจ็คที่ส่งไปยังฟังก์ชัน ประเภทของพารามิเตอร์นั้นเป็นตัวแปรหรือออบเจ็ค และฟังก์ชันสามารถมีหรือไม่มีพารามิเตอร์ก็ได้ มาดูตัวอย่างของการใช้ฟังก์ชันพารามิเตอร์
// Function without parameter
float getPI()
{
    return 3.14;
}

// Function with three parameters
int findVolume(float width, float long, float height)
{
    float volume = width * long * height;
    return volume;
}

// Function with difference parameter types
void printData(string name, int age)
{
    cout << "Hi, " << name << endl;
    cout << "Your age is " << age << endl;
}
ในตัวอย่าง เป็นการประกาศฟังก์ชันพร้อมกับพารามิเตอร์ของมัน โดยฟังก์ชัน getPI() เป็นฟังก์ชันที่ไม่มีพารามิเตอร์ ฟังก์ชัน findVolume() เป็นฟังก์ชันที่มีพารามิเตอร์สามตัว และฟังก์ชัน printData() เป็นฟังก์ชันที่มีพารามิเตอร์สองตัว ฟังก์ชันเหล่านี้สามารถมีหรือไม่มีการส่งค่ากลับก็ได้ (return)

Function arguments

ฟังก์ชันอาร์กิวเมนต์คือเซ็ตของตัวแปรที่ส่งไปยังฟังก์ชัน อาร์กิวเมนต์จะต้องตรงกันกับฟังก์ชันพารามิเตอร์และเรียงไปตามลำดับที่ได้ประกาศไว้ มาดูสามตัวอย่างเกี่ยวกับฟังก์ชันอากิวเม้นต์
printData("Marcus", 14);
ฟังก์ชัน printData มีสองพารามิเตอร์ และประเภทอาร์กิวเมนต์ของมันคือ string และ int ตามลำดับ ในการที่จะส่งอาร์กิวเมนต์ไปยังฟังก์ชัน อาร์กิวเมนต์ตัวแรกจะต้องเป็น string ด้วย และตัวที่สองจะต้องเป็น int เช่นกัน

การส่งค่ากลับ return

การส่งค่ากลับจะใช้คำสั่ง return มันเป็นผลลัพธ์ของฟังก์ชันเพื่อที่จะส่งกลับไปยังจุดเรียกเมื่อสิ้นสุดการทำงานของฟังก์ชัน ประเภทตัวแปรที่ส่งกลับจะต้องตรงกันกับประเภทของฟังก์ชัน และบางฟังก์ชันอาจจะไม่มีการส่งค่ากลับ ซึ่งเป็นฟังก์ชันที่มีการกำหนดประเภทการใช้งานเป็น void
หลังจากที่คุณได้เข้าใจในส่วนประกอบของฟังก์ชันแล้ว ต่อไปมาดูตัวอย่างการใช้ฟังก์ชันในการเขียนโปรแกรมในภาษา C++ เราจะเขียนเกมเดาตัวเลขลับ โดยในโปรแกรมของเราจะใช้ฟังก์ชันประเภทต่างๆ นีเป็นโค้ดของโปรแกรม
#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

void welcomeText();
void puts(string);
int getGuessNumber();

int main()
{
    //initialize random seed:
    srand(time(NULL));

    bool is_gameover = false;
    int guess, secret;
    int guessed = 0;

    // display welcome text
    welcomeText();

    // generate secret number:
    secret = rand() % 10 + 1;
    puts("Secret number has been chosen");

    do
    {
        guess = getGuessNumber();
        guessed++;
        if (secret < guess)
            puts("The secret number is lower");
        else if(secret > guess)
            puts("The secret number is higher");

    }
    while (secret != guess);

    puts("Congratulations!");
    cout << "The secret number is " << secret << endl;
    cout << "You made " << guessed << " guess";
    cout << (guessed != 1 ? "es" : "") << endl;

    return 0;
}

void puts(string str)
{
    cout << str << endl;
}

void welcomeText()
{
    puts("###Welcome to guessing number game###");
}

int getGuessNumber()
{
    int guess;
    cout << "Guess the number (1 to 10): ";
    cin >> guess;
    return guess;
}
ในตัวอย่าง เป็นโปรแกรมของเกมเดาตัวเลข ผู้เล่นต้องทำการสุ่มตัวเลขให้ถูกต้องโดยให้ได้จำนวนครั้งที่น้อยที่สุด ในตอนแรกโปรแกรมจะทำการสุ่มตัวเลขลับไว้ในตัวแปร secret และเราเรียกใช้ฟังก์ชัน welcomeText() สำหรับแสดงข้อความต้อนรับ และในฟังก์ชันนี้ได้เรียกใช้ฟังก์ชัน puts() สำหรับส่งข้อความไปแสดงผลอีกครั้ง
guess = getGuessNumber();
guessed++;
ในคำสั่ง do while loop เป็นส่วนของการเล่นเกมได้เริ่มต้นขึ้น โดยเกมจะถามตัวเลขที่ผู้เล่นต้องการเดาที่มีค่าระหว่าง 1 - 10 โดยเราจะเรียกใช้ฟังก์ชัน getGuessNumber() สำหรับบอกผู้ใช้และส่งค่าเลขที่ผู้เล่นเดากลับมายังตัวแปร guess ทุกๆ ครั้งที่มีการเดาตัวเลขแล้ว เราเพิ่มค่าตัวแปร guessed ว่าได้ทำการเดาไปแล้วกี่ครั้ง
do
{
    guess = getGuessNumber();
    guessed++;
    if (secret < guess)
        puts("The secret number is lower");
    else if(secret > guess)
        puts("The secret number is higher");

}
while (secret != guess);
###Welcome to guessing number game###
Secret number has been chosen
Guess the number (1 to 10): 5
The secret number is lower
Guess the number (1 to 10): 2
The secret number is higher
Guess the number (1 to 10): 4
The secret number is lower
Guess the number (1 to 10): 3
Congratulations!
The secret number is 3
You made 4 guesses
นี่เป็นผลลัพธ์การทำงานของโปรแกรม โดยเราได้เล่นเกมและทำตามการเดาตัวเลข 5, 2, 4 และ 3 ตามลำดับ ซึ่งเดาไป 4 ครั้ง
จากในตัวอย่างของโปรแกรมเดาตัวเลข คุณจะเห็นว่าเราได้ใช้ฟังก์ชันในรูปแบบต่างๆ และมีสิ่งหนึ่งที่คุณสามารถสังเกตุได้ในการประกาศฟังก์ชันคือ เราได้ทำการประกาศส่วนหัวของฟังก์ชันทั้งหมดไว้ก่อนฟังก์ชัน main() ซึ่งในการทำแบบนี้เป็นอีกทางเลือก และเป็นวิธีปฏิบัติที่ดีที่จะบอกให้คอมไพเลอร์ทราบว่าเรามีฟังก์ชันอะไรบ้าง
void welcomeText();
void puts(string);
int getGuessNumber();
และหากคุณไม่ประกาศส่วนหัวของฟังก์ชันแบบนี้ ในภาษา C++ นั้นคุณจะไม่สามารถคอมไพล์โปรแกรมของคุณได้ และในตัวอย่างเราได้ใช้ฟังก์ชันเพื่อสร้าง random seed จากเวลาในคำสั่ง srand(time(NULL)) เพื่อทำให้โปรแกรมของเราสุ่มเลขได้ดีที่สุด

Passing by reference and Passing by value

ในตัวอย่างทั้งหมดที่คุณได้เรียนไปในบทนี้นั้นเป็นการใช้งานฟังก์ชันโดยวิธี Passing by value นี่จะทำให้โปรแกรมต้องคัดลอกค่าใหม่ที่ใช้ในฟังก์ชัน ในภาษา C++ มีวิธีการเรียกใช้งานฟังก์ชันอีกแบบหนึ่งที่เรียกว่า Passing by reference สิ่งที่แตกต่างจากแบบเดิมคือเราจะส่งที่อยู่หน่วยความจำของตัวแปรไปแทน เรามักจะใช้วิธีนี้กับข้อมูลที่มีขนาดมากๆ ที่ต้องส่งไปยังฟังก์ชัน เช่น อาเรย์ หรือโปรแกรมที่ต้องการประสิทธิภาพมาก มาดูตัวอย่างของข้อแตกต่างระหว่าง Passing by reference และ Passing by value ในภาษา C++
#include <iostream>

using namespace std;

void swapByVal(int, int);
void swapByRef(int&, int&);

int main()
{
    int x = 1, y = 5;

    cout << "Passing by value" << endl;
    cout << "Before swap: x = " << x << ", y = " << y << endl;
    swapByVal(x, y);
    cout << "After swap: x = " << x << ", y = " << y << endl;

    cout << "Passing by reference" << endl;
    cout << "Before swap: x = " << x << ", y = " << y << endl;
    swapByRef(x, y);
    cout << "After swap: x = " << x << ", y = " << y << endl;

    return 0;
}

void swapByVal(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}

void swapByRef(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}
ในตัวอย่าง เป็นโปรแกรมในการสลับตัวเลข ซึ่งเราได้สร้างฟังก์ชันมาสองเวอร์ชันคือ ฟังก์ชัน swapByVal() เป็นฟังก์ชันที่มีพารามิเตอร์เป็นแบบ Passing by value และฟังก์ชัน swapByRef() เป็นฟังก์ชันที่มีพารามิเตอร์เป็นแบบ Passing by reference และเราทำการทดสอบเรียกใช้งานฟังก์ชันทั้งสอง
void swapByRef(int &a, int &b)
{
    int temp = a;
    a = b;
    b = temp;
}
ในการส่งพารามิเตอร์แบบ Passing by reference นั้นเราจะต้องประกาศพารามิเตอร์ในฟังก์ชันโดย ใส่เครื่องหมาย & ที่หน้าของตัวแปร เมื่อคุณส่งค่ามายังฟังก์ชัน ตัวแปรในฟังก์ชันจะใช้ที่อยู่กับตัวแปรที่อยู่นอกฟังก์ชัน นั่นทำให้เมื่อตัวแปร a และ b ในฟังก์ชันเปลี่ยนเป็นอะไรก็ตาม ตัวแปร x และ y ก็จะเปลี่ยนเป็นค่าเหมือนกัน เพราะว่าพวกเขามีที่อยู่ของหน่วยความจำร่วมกัน
Passing by value
Before swap: x = 1, y = 5
After swap: x = 1, y = 5
Passing by reference
Before swap: x = 1, y = 5
After swap: x = 5, y = 1
นี่เป็นผลลัพธ์การทำงานของโปรแกรมในการส่งพารามิเตอร์แบบ Passing by reference เข้าไปยังฟังก์ชัน
ในการใช้งานวิธินี้มันมีประสิทธิภาพมากเพราะว่าช่วยลดเวลาในการคัดลอกข้อมูลในฟังก์ชันออกไปทำให้โปรแกรมทำงานได้เร็วมากขึ้น แต่อย่างไรก็ตามในการใช้วิธี Passing by reference นั้นก็ขึ้นกับปัญหาของคุณ ไม่ทุกโปรแกรมที่จะสามารถใช้มันได้เสมอ ยกตัวอย่างเช่น ถ้าหากคุณต้องการรักษาค่าเดิมของตัวแปร x และ y ในฟังก์ชัน main() คุณก็ไม่ควรใช้วิธีนี้
แนวคิด Passing by reference ยังถูกนำไปใช้กับการเขียนโปรแกรมเชิงวัตถุในภาษาต่างๆ นั่นคือเมื่อคุณส่งออบเจ็คไปยังฟังก์ชันนั้นจะเป็นการส่งที่อยู่ของออบเจ็คไปแทน อย่างไรก็ตามในบทนี้เราไม่ได้ครอบคลุมในเรื่องนี้
ในบทนี้ คุณได้ทำความรู้จักและเรียนรู้วิธีการสร้างและใช้งานฟังก์ชันในภาษา C++ เราได้แนะนำให้คุณรู้จักกับฟังก์ชันประเภทต่างๆ และรู้จักพารามิเตอร์และอากิวเมนต์ของฟังก์ชัน ฟังก์ชันที่มีการส่งค่าและไม่มีการส่งค่ากลับ นอกจากนี้คุณยังเข้าใจในการเรียกใช้ฟังก์ชันแบบ Passing by reference
****************************************************************************************************************************************************************************************************

เราสามารถแบ่งฟังก์ชันใน C++ ได้เป็น 2 ประเภทได้แก่
1. ฟังก์ชันที่อยู่ใน standard library ของ C++ เราจะเรียกฟังก์ชันพวกนี้ว่า built-in function
2. ฟังก์ชันที่เราสร้างขึ้นมาเพื่อที่จะใช้งานเอง เราจะเรียกฟังก์ชันพวกนี้ว่า user defined function
สำหรับพวก built-in function นั้นเราสามารถเรียกใช้ได้โดยการ import library ที่มีฟังก์ชันนั้นๆเขามาในโปรแกรมของเรา ตัวอย่างเช่น ถ้าเราต้องการใช้ฟังก์ชันทางคณิตศาสตร์ เช่นพวก sin, cos, tan, exponential, log ซึ่งฟังก์ชันเหล่านี้อยู่ใน library ที่ชื่อว่า cmath ใน C++ เราสามารถเขียนคำสั่งได้ดังตัวอย่างนี้
เมื่อทำการรันจะได้ผลลัพธ์ดังนี้ครับ
สำหรับฟังก์ชันทางคณิตศาสตร์ทั้งหมดที่อยู่ใน C++ เราสามารถดูได้ที่ http://www.cplusplus.com/reference/clibrary/cmath/
ส่วนฟังก์ชันประเภท user defined function มีโครงสร้างการเขียนแบบนี้ครับ
ชนิดข้อมูลของข้อมูลที่ต้องการ return ชื่อฟังก์ชัน (ตัวแปร input)
{
ชุดคำสั่งต่างๆภายในฟังก์ชัน
}
เช่นสมมติว่าเราต้องการสร้างฟังก์ชันที่ เมื่อใส่ตัวเลขลงไปจะให้ผลลัพธ์เป็นกำลังสองของตัวเลขที่เราจะใส่ไป เราสามารถเขียนโค้ดได้ดังนี้

การทำงานของฟังก์ชันจะสิ้นสุดที่คำสั่ง return เสมอ คือ สมมติว่าฟังก์ชันเรามีคำสั่ง return หลายๆที่ ถ้าฟังก์ชันของเราพบคำสั่ง return ที่ไหนมันจะทำการการ return ค่าแล้วออกจากฟังก์ชันทันที เช่น
ขอให้สังเกตว่าเมื่อเราใส่เลข 12 ลงไป มันจะเข้าเงื่อนไขของ if แล้วก็จะเจอคำสั่ง return 10; พอเจอคำสั่ง return ปุ๊บ มันจะทำการ return ค่า พร้อมออกจากฟังก์ชันทันที
ตัวแปรที่ต่างๆที่อยู่ในฟังก์ชัน เป็น local varible นะครับ ไม่สามารถเรียกใช้ภายในฟังก์ชันได้ ถ้าเราใช้ตัวแปรในฟังก์ชันซ้ำกับตัวแปรภายนอกฟังก์ชัน ก็ไม่มีผลกระทบใดๆต่อตัวแปรภายนอกฟังก์ชันทั้งสิ้น เช่น
สังเกตนะครับว่า การเปลี่ยนแปลงของค่า x ภายในฟังก์ชัน square ไม่ส่งผลใดๆกับตัวแปร x ที่อยู่ภายนอกฟังก์ชันทั้งสิ้น
ทีนี้สมมติว่าเราต้องการให้การเปลี่ยนแปลงมีผลกับตัวแปร x ภายนอกด้วย ใน C++ ก็อนุญาตให้เราทำได้ด้วยครับ โดยการใส่เครื่องหมาย & หน้าตัวแปรที่เราต้องการให้มีผล เช่น ถ้าเราเปลี่ยนแปลงบรรทัดที่ 5 เป็นดังนี้
เราจะได้ผลลัพธ์ของการรันเป็น
จะสังเกตว่าค่า x ภายนอกฟังก์ชันมีการเปลี่ยนแปลงเป็น 64 ตาม x ที่อยู่ในฟังก์ชันด้วยครับ
ทีนี้ในบางครั้งเราอาจจะต้องการสร้างฟังก์ชันซึ่งมีลักษณะที่ว่า เมื่อฟังก์ชันจบการทำงานแล้ว ไม่ต้องให้มัน return ค่าใดๆกลับมา เราสามารถทำได้โดยการเขียนคำว่า void นำหน้าฟังก์ชันดังตัวอย่างต่อไปนี้ครับ
ต่อไปจะเป็นตัวอย่างสุดท้ายของ blog นี้นะครับ สมมติว่าเราต้องการสร้างฟังก์ชันเพื่อทำการสลับค่าตัวแปร 2 ตัว สมมติว่าเราเขียนโค้ดแบบนี้
เมื่อทำการรันเราจะเห็นว่า a และ b มันสลับค่าเฉพาะในฟังก์ชันเท่านั้นดังรูป
ถ้าเราต้องการให้มันสลับที่กันภายนอกด้วยเราจะเปลี่ยนแปลงบรรทัดที่ 5 ดังนี้
ซึ่งเราจะได้ผลลัพธ์ของรันรันเป็น

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++