โหมดการส่งผ่านค่าสู่พารามิเตอร์ (Parameter passing mode) ในการเขียนโปรแกรมภาษาใดๆก็ตาม เมื่อมีการสร้างฟังก์ชั่น ก็มักจะมีการส่งผ่านค่าเข้าสู่พารามิเตอร์ของฟังก์ชั่น การส่งผ่านค่านั้นโดยพื้นฐานจะมี 3 ลักษณะหรือโหมดการทำงานในการส่งผ่านค่าสู่พารามิเตอร์
1. in mode พารามิเตอร์ของฟังก์ชั่นรับค่าเข้าเพียงอย่างเดียว
2. out mode พารามิเตอร์ของฟังก์ชั่นไม่รับค่าเข้าแต่มีการส่งค่ากลับไปยังเออร์กูเมนต์ (ตัวแปรที่ส่งค่ามายังพารามิเตอร์ของฟังก์ชั่น)
3. inout mode พารามิเตอร์ของฟังก์ชั่นรับค่าเข้าและส่งค่ากลับไปยังเออร์กูเมนต์
ฟังก์ชั่นหนึ่งๆ อาจมีหลายพารามิเตอร์ และแต่ละพารามิเตอร์อาจทำงานด้วยโหมดที่แตกต่างกันก็ได้
ภาษาการโปรแกรมหนึ่งๆ เลือกออกแบบโหมดในการส่งผ่านค่าสู่พารามิเตอร์ที่แตกต่างกัน โหมดที่สร้างปัญหาได้มากที่สุดคือโหมด inout mode จะได้ยกตัวอย่างต่อไป
ที่บรรยายมานี้ยังไม่เกี่ยวข้องกับการส่งพารามิเตอร์ Passing by value, Passing by reference ขออธิบายการทำงานของพารามิเตอร์ในแต่ละโหมดก่อน
ในหลักการการโปรแกรม Actual parameter คือค่าจริงที่จะถูกส่งให้กับพารามิเตอร์ในฟังก์ชั่น หรือ Formal parameter ซึ่ง Formal parameter พารามิเตอร์ที่ประกาศในฟังก์ชัน
ภาษาการโปรแกรมอาจสนับสนุนทั้ง 3 โหมด
int a = 5, b = 10, c = 15;
myfunction(a, b, &c);
....
void myfunction(int x, int y, int *z){
x = x +10;
y = y + 5;
*z = *z + 20;
printf("%d %d %d", x, y, *z);
}
จากโค้ดด้านบนพารามิเตอร์ x และ y ทำงานในโหมด in mode ส่วน z ทำงานในโหมด inout mode เพราะการแก้ไขค่าที่พอยน์เตอร์ z ชี้อยู่จะถูกนำไปสำเนาให้กับ Actual parameter c ซึ่งมีค่าเท่ากับ 35 ส่วน a และ b ยังคงมีค่าเท่ากับ 5 และ 10 ตามลำดับ
สมมติให้โค้ดมาตามนี้
int a = 10, b = 20;
myanotherfunc(&a, &a);
....void myfunction(int *x, int *y){
*x = *x +10;
*y = *y + 5;
printf("%d %d ", x, y);
}
จะเห็นว่า Actual parameter คือ a ส่วน Formal parameter คือพอยน์เตอร์ x และ y ซึ่งชี้ไปยังตำแหน่งในเมมโมรีตำแหน่งเดียวกัน และ Formal parameter x และ y ทำงานใน inout mode ซึ่งจะรับค่าเข้าและส่งกลับ
คำถามคือถ้าหากมีการส่ง Actual parameter เข้าสู่ฟังก์ชั่น ผลลัพธ์ที่จะถูกส่งกลับคืออะไร ?
หากโปรแกรมเมอร์พิจารณาดูตามโค้ด ก็อาจจะตอบว่า 20 หรือ 15
พิจารณาการใช้งานเมมโมรีกับพอยน์เตอร์ พารามิเตอร์ในฟังก์ชั่นจะถูกจองพื้นที่ในส่วนของ x และ y แต่สำเนาค่าจากตำแหน่งของตัวแปร a ซึ่งมีค่าเท่ากับ 10 (ภาพบน) ถ้าการจับคู่ของ Actual และ Formal parameter จากซ้ายไปขวา (ภาพบนซ้าย) พารามิเตอร์ y จะอยู่ top of stack แล้วเมื่อมีการส่งค่ากลับหลังจากประเมินผลนิพจน์ ค่าของพารามิเตอร์ x จะถูกส่งไปทีหลัง ซึ่งจะทำให้ a มีค่าเท่ากับ 20
ในทางกลับกัน ถ้าการจับคู่ทำจากขวาไปซ้าย พารามิเตอร์ x จะอยู่ top of stack แล้ว a จะมีค่าเป็น 15 เนื่องจากพารามิเตอร์ y จะถูกส่งไปทีหลัง (ภาพบนขวา)
ในภาษาการโปรแกรมที่มีการออกแบบ จะกำหนดลักษณะการส่งค่าเออร์กูเมนต์สู่พารามิเตอร์ เป็นลักษณะต่างๆ เช่น
- Pass-by-value มีการทำสำเนาค่าของ Actual parameter ให้กับ Formal parameter หรือเป็นการส่งค่าแบบ in mode
- Pass-by-result ไม่มีการสำเนาค่าของ Actual parameter ให้กับ Formal parameter แต่มีการรีเทิร์นค่ากลับจาก Formal parameter ให้กับ Actual parameter หรือเป็นการส่งค่าแบบ out mode การส่งลักษณะนี้มีในภาษา C#
- Pass-by-value-result มีการทำสำเนาค่าจาก Actual parameter ให้กับ Formal parameter และมีการส่งค่ากลับจาก Formal parameter ให้กับ Actual parameter หรือเป็นการส่งในลักษณะ inout mode (ดังตัวอย่างด้านบน)
- Pass-by-reference ไม่มีการสำเนาค่าของ Actual parameter ให้กับ Formal parameter แต่ส่ง Access path (ตำแหน่งของ Actual) ให้กับ Formal parameter ซึ่งจะเกิดปัญหา Aliasing เมื่อระหว่างการทำงานภายในฟังก์ชั่นมีการอ้างอิง Nonlocal variable (ตัวแปรที่อยู่นอกฟังก์ชั่น) ในภาษา C++ มีการใช้งานในลักษณะนี้ เช่น void fun(int &first, int &second) เป็นการประกาศพารามิเตอร์ในลักษณะ inout mode ซึ่งสามารถเรียกฟังก์ชั่นเช่น fun (a, b) ซึ่งตัวแปร first และ second จะอ้างอิงตำแหน่งในเมมโมรีของ a และ b โดยไม่มีการสำเนาค่าไว้ในเมมโมรีของฟังก์ชั่น
- Pass-by-name มีการส่งผ่านค่าในลักษณะ inout mode แต่ไม่เกี่ยวข้องกับลำดับการจับคู่ของ Actual parameter และ Formal parameter ขึ้นกับการ execute นิพจน์ในฟังก์ชั่น การทำงานในลักษณะนี้มีภาษาการโปรแกรมไม่มากนักที่สนับสนุน
โดยสรุป
ในการใช้งาน inout parameter passing mode นั้น จำเป็นที่จะต้องพิจารณาลำดับในการเข้าคู่ของ Actual parameter และ Formal parameter เนื่องจากจะสัมพันธ์กับการรีเทิร์นค่ากลับ ซึ่งการรีเทิร์นค่ากลับนั้นพิจารณาจาก Stack ของ function
แบบฝึกหัด
1. ถ้ากำหนดการส่งค่าเข้าสู่ฟังก์ชั่น
fun(list[i], list[j])
void fun(int &first, int &second){
..
}
เป็นแบบ Pass-by-reference โดย i และ j มีค่าเท่ากัน จะเกิดปัญหา Aliasing หรือไม่?
2. ถ้ากำหนด
fun1(list[i], list)
แบบฝึกหัด
1. ถ้ากำหนดการส่งค่าเข้าสู่ฟังก์ชั่น
fun(list[i], list[j])
void fun(int &first, int &second){
..
}
เป็นแบบ Pass-by-reference โดย i และ j มีค่าเท่ากัน จะเกิดปัญหา Aliasing หรือไม่?
2. ถ้ากำหนด
fun1(list[i], list)
void fun(int &first, int &second){
..
}
..
}
first และ second จะเป็น Alias หรือไม่ ?
ตามหาความรู้เกี่ยวกับ programing language ภาษาไทยมานาน ขอบคุณมากๆครับ สำหรับความรู้ เป็นแรงใจให้ครับ
ReplyDeleteตามหาความรู้เกี่ยวกับ programing language ภาษาไทยมานาน ขอบคุณมากๆครับ สำหรับความรู้ เป็นแรงใจให้ครับ
ReplyDeleteไม่นึกว่าจะมีคนอ่าน ถูกผิดบอกได้นะคะส่วนใหญ่มาจาก Robesta ขอบคุณค่ะ
ReplyDelete