สมัครเรียนโทร. 085-350-7540 , 084-88-00-255 , ntprintf@gmail.com


อะไรคือข้อแตกต่างของ Pass by Reference กับ Pass by Value กันนะ?

 

หนึ่งในเรื่องปราบเซียนที่คนเข้าใจผิดกันมากมายคือเรื่อง Pass by Reference กับ Pass by Value ครับ ก่อนอื่นต้องขออนุญาตบอกก่อนว่าเรื่องนี้ไม่เหมาะกับมือใหม่ เพราะอ่านแล้วอาจจะปวดหัวและหมดกำลังใจในการเรียนได้ ดังนั้นถ้าท่านอ่านแล้วไม่เข้าใจก็ไม่ต้องกังวลไปครับ ผู้ที่ลงเรียนกับทาง EPT ขอให้ลองย้อนมาอ่านอีกครั้งหลังเรียนและทำการบ้านจบเรื่อง OOP จะทำให้เข้าใจมากขึ้น ส่วนผู้ที่ไม่ได้เรียนกับทางเรานั้น ผมก็ไม่รู้จะแนะนำอย่างไรดีเพราะแต่ละสถาบันเนื้อหาที่เรียนจะหนักเบาไม่เท่ากับแม้จะชื่อหัวข้อเหมือนกันก็ตาม ดังนั้นหากท่านอ่านแล้วไม่เข้าใจขอแนะนำให้ลงคอร์ส เรียนเขียนโปรแกรมภาษา JAVA (J103) หรือถ้าอยากเรียนแบบยาว ๆ สะใจเพื่อทำงานด้านโปรแกรมเมอร์ก็ขอแนะนำคอร์ส SET B ภาษา Java (SET-B-J) เรียนจบแล้วเทพแน่นอนครับ

เมื่อจบคำนำให้กำลังใจไปแล้ว ตอนนี้ก็มาเข้าเรื่องกันดีกว่าครับ สำหรับผู้เรียนที่เรียนกับทาง EPT นั้น โดยทั่วไปผมจะสอนโดยมองในมุมของของสิ่งของหรือ Object ที่ถูกส่ง ไม่ใช่มองในมุมมองของตัวแปรเนื่องจากจะเข้าใจง่ายสำหรับมือใหม่ และสามารถนำความเข้าใจนี้ไปประยุกต์ใช้ได้แทบทุกภาษา นั่นคือจะสอนด้วยนิยามตามที่กำหนดไว้ในทฤษฎี Computer Science ดังนี้

  • Pass by Value คือ การส่งค่า (value) เป็น argument ของฟังก์ชัน ดังนั้นค่าที่ทำในฟังก์ชันจึงไม่ส่งผลต่อตัวแปรนอกฟังก์ชัน
  • Pass by Reference คือ การส่งตัวแปร (variable) เป็น argument ของฟังก์ชัน ดังนั้นตัวแปรที่มีการดำเนินการใด ๆ ในฟังก์ชันจะส่งผลให้ตัวแปรนอกฟังก์ชันมีการเปลี่ยนแปลงด้วย

เมื่ออ่านมาถึงตรงนี้น่าจะยังไม่มีใครงงใช่ไหมครับ ทีนี้เราจะมาเข้าถึงปัญหากันครับ ขอย้ำอีกครั้งว่าถ้าอ่านแล้วงงไม่ต้องตกใจหรือหมดกำลังใจในการเรียนนะครับ มันเป็นแค่เรื่องของคำนิยามและภาษาต่างชาติเท่านั้น ไม่ได้ส่งผลใด ๆ ต่อการเขียนโปรแกรมของเราเลยถ้าเรามีความเข้าใจโปรแกรมมิ่งพื้นฐานตามที่ผมสอนอยู่แล้ว เพียงแต่ผู้ที่จะสอบ Certification จะต้องระวังหน่อยครับ โดยต้องใช้นิยามดังที่จะกล่าวถึงต่อไปนี้แทน

สรุปย่อ ๆ ของแต่ละภาษา

ก่อนอื่นจะเริ่มอธิบายขอให้อ่านสรุปของแต่ละภาษานี้ก่อนครับ

  • Java รองรับเฉพาะ Pass by Value เท่านั้น เอ๊ะ! หลายคนอาจจะเริ่มตกใจ ใจเย็น ๆ เรื่องนี้เดี๋ยวจะอธิบายด้านล่างครับ
  • C# รองรับ Pass by Value และ Pass by Reference (แต่ต้องใช้คีย์เวิร์ด ref)
  • C++ รองรับ Pass by Value และ Pass by Reference 

การส่งพารามิเตอร์ในภาษา Java และ C#

ที่เราเรียนกันเราพูดว่า ตัวแปรแบบ reference type จะ pass by value โดยอัตโนมัติ แต่การ pass ตัวแปรที่เป็น reference type ไปยังฟังก์ชันสามารถมองได้เป็น การ pass by value เช่นกันถ้ามองเฉพาะตัวแปรนั้น ๆ ที่เป็น pointer ไม่ใช่มองถึง Object ที่ pointer นั้นชี้อยู่ ดังเช่นตัวอย่าง Code ต่อไปนี้

static void Change(int[] pArray)
{
        pArray[0] = 888;  // This change affects the original element.
        pArray = new int[5] {-3, -1, -2, -3, -4};   // This change is local.
        System.Console.WriteLine("Inside the method, : {0}", pArray[0]);
}

static void Main()
{
        int[] arr = {1, 4, 5};
        System.Console.WriteLine("Inside Main, before : {0}", arr [0]);

        Change(arr);
        System.Console.WriteLine("Inside Main, after : {0}", arr [0]);
}

/* Output:
    Inside Main, before c: 1
    Inside the method, : -3
    Inside Main, after : 888
*/

ใน Code ด้านบน มีการแก้ไขค่าใน method 2 อย่างคือ แก้ค่าใน Array และการแก้ให้ pArray ไปชี้ object ใหม่เลย ซึ่งหนังสือบางเล่มจะมองว่า ในเมื่อการแก้ให้ pArray ไปชี้ Object ใหม่เป็นการแก้ค่า "Value" ของ pArray จึงเรียกว่า เป็นการ pass by value ของตัวแปรแบบ reference type โดยมองว่าตัวแปร pArray (ที่เป็น parameter)เป็น Copy ของ ตัวแปร arr ใน Main คำพูดที่ถูกต้องแต่ชวนงงคือ

"หากไม่กำหนดอะไรเพิ่มเติม C#/Java จะ pass by value เสมอ (มองในมุมของตัวแปร) เรียกว่า pass the reference by value"

แต่ที่เราเรียนเรามองในมุมมองของ Object ที่ตัวแปรนั้น ๆ ชี้อยู่จึงเป็นการ pass by reference ของ Object นั้น  ดังนั้นตัวแปร reference type หากมีการส่งค่าให้กับ method จะมีการ pass by reference โดยอัตโนมัติมองในมุมของ Object เพราะที่เราสอนเรามองในมุมของของ Object นั้นเอง (ซึ่งหนังสือบางเล่มจะมองในมุมมองของตัวแปร) ซึ่งขัดกับมุมมองของตำราบางเล่ม

ลองดูคนดังพูดเรื่องนี้อย่างไร

1. มุมมองของ James Gosling คิดว่าการส่ง reference type ให้ Oject เรียกว่า pass the reference by value

Some people will say incorrectly that objects are passed "by reference." In programming language design, 
the term pass by reference properly means that when an argument is passed to a function, 
the invoked function gets a reference to the original value, not a copy of its value. If the function modifies its parameter,
 the value in the calling code will be changed because the argument and parameter use the same slot in memory.... 
The Java programming language does not pass objects by reference; it passes object references by value. 
Because two copies of the same reference refer to the same actual object, 
changes made through one reference variable are visible through the other. 
There is exactly one parameter passing mode -- pass by value -- 
and that helps keep things simple. 
-- James Gosling, et al., The Java Programming Language, 4th Edition

2. มุมมองของ Microsoft ก็มีในแนวทางเดียวกัน

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/passing-reference-type-parameters

 

สำหรับเรื่องนิยามที่ผมสอนในคอร์สอาจใช้คำพูดที่ผิดจากคนทั่วไป แต่ไม่ได้สอนผิดในหลักการที่สำคัญ 
กรุณาดู https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value  เถียงกันยาวเหยียด ถึงแม้ใน link จะเป็น JAVA แต่ก็หลักการเดียวกันกับของ C# ครับ

ลองมาดูรูปบางส่วน (credit ตาม link ด้านบน)

  • pass the reference by referencepass reference by value
  • pass the reference by valuepass_reference_by_value

สรุปอีกครั้งก็คือในคอร์สจะนิยามโดยมองในมุมของ Object ที่ส่ง แต่ในมุมมองของ microsoft และ James Gosling มองในมุมของตัวแปร ดังนั้นผู้เรียนที่จะสอบ Certification ระวังเรื่องนี้ดีดีนะครับ ต้องใช้นิยามตามของเขา ที่ผมสอนอาจจะใช้คำไม่ถูก(เพราะมองในมุมของ Object ) แต่หลักการเดียวกันครับ

การส่งพารามิเตอร์ในภาษา C++

ภาษา C++ นี้ มีทั้ง Pass by Value และ Pass by Reference ซึ่งตรงตามนิยามที่ผมสอนในคอร์ส ดังนั้นมาดูตัวอย่าง Code pass by reference เพื่อเปรียบเทียบกับของ Java/C# กันครับ (ที่มา https://www.ibm.com/docs/en/zos/2.4.0?topic=calls-pass-by-reference-c-only)

#include <stdio.h>

void swapnum(int &i, int &j) {
  int temp = i;
  i = j;
  j = temp;
}

int main(void) {
  int a = 10;
  int b = 20;

  swapnum(a, b);
  printf("A is %d and B is %d\n", a, b);
  return 0;
}

เมื่อเรียกฟังก์ชัน swapnum() ค่าของตัวแปร a และ b จะเปลี่ยนไปด้วยเนื่องจากเป็นการ pass by reference ดังนั้นจะได้ผลลัพธ์ดังนี้

A is 20 and B is 10

 


Tag ที่น่าสนใจ: java c# vb.net python c c++ machine_learning web database oop cloud aws ios android


บทความนี้อาจจะมีที่ผิด กรุณาตรวจสอบก่อนใช้

หากมีข้อผิดพลาด/ต้องการพูดคุยเพิ่มเติมเกี่ยวกับบทความนี้ กรุณาแจ้งที่ http://m.me/Expert.Programming.Tutor

ไม่อยากอ่าน Tutorial อยากมาเรียนเลยทำอย่างไร?

สมัครเรียน ONLINE ได้ทันทีที่ https://elearn.expert-programming-tutor.com

หรือติดต่อ

085-350-7540 (DTAC)
084-88-00-255 (AIS)
026-111-618
หรือทาง EMAIL: NTPRINTF@GMAIL.COM

แผนที่ ที่ตั้งของอาคารของเรา

แผนผังการเรียนเขียนโปรแกรม

Link อื่นๆ

Allow sites to save and read cookie data.
Cookies are small pieces of data created by sites you visit. They make your online experience easier by saving browsing information. We use cookies to improve your experience on our website. By browsing this website, you agree to our use of cookies.

Copyright (c) 2013 expert-programming-tutor.com. All rights reserved. | 085-350-7540 | 084-88-00-255 | ntprintf@gmail.com

ติดต่อเราได้ที่

085-350-7540 (DTAC)
084-88-00-255 (AIS)
026-111-618
หรือทาง EMAIL: NTPRINTF@GMAIL.COM
แผนที่ ที่ตั้งของอาคารของเรา