ในภาษาโปรแกรมมิ่งหลายๆภาษามีความสามารถในการจัดการกับ Pointer ซึ่งทำให้เราสามารถเขียนโปรแกรมได้ง่ายขึ้น แต่ก่อนที่จะเข้าใจเรื่องนี้ได้ มันก็ก็อาจจะเป็นเรื่องน่าปวดหัวอยู่เหมือนกันเวลาที่จะต้องยุ่งกับเจ้า Pointer เหล่านี้
//ไม่ใช่ Pointer แบบนี้นะ
ในบทความนี้จะขออธิบายการใช้งานต่างๆโดยใช้ภาษา C เป็นตัวอย่าง ถ้าใครเขียนภาษานี้อยู่จะได้เข้าใจได้ไม่ยาก แต่ถ้าใครเขียนภาษาอื่นก็ยังคงอ่านได้เหมือนกัน เรื่อง Pointer นี้รู้และเข้าใจเอาไว้เป็นประโยชน์ในการเขียนโค้ดในอนาคตแน่นอน มาเริ่มดูไปทีละขั้นกันเลยดีกว่า
Address – ข้อมูลต้องมีที่อยู่
ต้องเริ่มต้นกันก่อนว่าทุกๆค่าที่เก็บในตัวแปรเวลาเราเขียนเป็นโค้ดนั้น มันต้องมีที่อยู่ใน memory เพื่อใช้ตอนที่รันโปรแกรม ซึ่งการจะเก็บค่าต่างๆและรู้ว่าค่าอะไรอยู่ตรงไหนได้ ในมุมมองของคอมพิวเตอร์จำเป็นจะต้องมี “ที่อยู่” หรือก็คือ “address” ให้แต่ละข้อมูล อย่างเช่นเรามีโค้ดที่สร้างตัวแปรเอาไว้ เราสามารถดู address ของแต่ละตัวแปรได้ง่ายๆด้วยการเติมเครื่องหมาย ampersand (&) เอาไว้ข้างหน้าตัวแปร ลองดูจากตัวอย่างโค้ดด้านล่างนี้
#include <stdio.h>
int main() {
int myNum = 9;
char myString[] = "Hello";
printf("Address of myNum: %p\n", &myNum); //Address of myNum: 0x7ffc615ac4ec
printf("Address of myString: %p\n", &myString); //Address of myString: 0x7ffc615ac4f2
return 0;
}
Pointer – คอยชี้ทาง
เรารู้ว่า address เป็นที่อยู่ของข้อมูลจริงๆใน memory ซึ่งการที่ตัวแปรที่เราตั้งชื่อขึ้นมาจะไปเชื่องโยงกับ address ได้ เบื้องหลังการทำงานนั้นจะมีตัวชี้ทางตอนที่โปรแกรมทำงานว่า ตัวแปรที่เจออยู่ในโค้ดตอนนี้ต้องไปดึงข้อมูลมาจากที่ไหน ซึ่งตัวชี้เป้านี้ก็คือ Pointer ของเรานั่นเอง
สร้าง Pointer
เราสามารถสร้างตัวแปรเพื่อเก็บ ตัวชี้ ของตัวแปรต่างๆได้ด้วยการใส่เครื่องหมาย star (*) หรือเครื่องหมายดอกจัน เติมไว้ข้างหน้าของตัวแปรที่จะให้เป็น ตัวชี้ แบบนี้
int * myPointer;
int* myPointer;
int *myPointer;
ทั้งสามแบบนี้ใช้งานได้ไม่ต่างกันแล้วแต่ความชอบของแต่ละคนเลย ซึ่งตัวแปรที่เราสร้างมานั้นชื่อ myPointer เฉยๆนะ ไม่ใช่ *myPointer
กำหนดค่าให้ Pointer
ค่าที่ ตัวชี้ เก็บก็คือ address ใน memory ดังนั้นเราจึงไม่สามารถประกาศค่าขึ้นมาลอยๆได้ แต่ต้องนำเอา address ที่ถูกใช้งานจริงๆมากำหนดให้ เช่น
int myNum = 9;
int * myPointer = &myNum;
printf("myNum address: %p\n", &myNum); //myNum address: 0x7fff95b91884
printf("myPointer value: %p\n", myPointer); //myPointer value: 0x7fff95b91884
address ของ myNum และค่าของ myPointer เป็นค่าเดียวกันแล้วคือ 0x7fff95b91884
อ่านค่าจาก Address
ในตอนนี้เราก็มีตัวแปรที่เป็น ตัวชี้ เก็บค่า address ของตัวแปรธรรมดาๆไว้แล้ว เราสามารถอ่านค่าที่อยู่ใน ตัวชี้ ได้ด้วย เพราะว่าในเมื่อเรารู้ address แล้วเราก็ต้องดูข้อมูลข้างในได้ด้วยสิ
ถ้าเป็นตัวแปรธรรมดาอย่าง myNum เราก็แค่าเรียกชื่อตัวแปรโปรแกรมก็จะไปดึงค่าที่เราเก็บจริงๆออกมาให้ทันที แต่พอเป็น pointer ที่เก็บ address เราแค่ต้องเพิ่มดอกจันเข้าไปหน้าตัวแปรในที่นี้ก็คือ myPointer แบบนี้
int myNum = 9;
int * myPointer = &myNum;
printf("%d", *myPointer); //9
เปลี่ยนค่าที่ Pointer ชี้อยู่
ถ้าแค่อ่านค่าที่ ตัวชี้ ชี้อยู่ได้อย่างเดียวหลายคนคงสงสัยว่าจะใช้ไปให้ยุ่งยากทำไม ในเมื่อตัวแปรธรรมดาก็ใช้งานได้แล้ว ไม่ต้องเขียนโค้ดอะไรให้วุ่นวาย แต่ว่าความสามารถของเจ้า ตัวชี้ นั้นยังไม่หมดแค่นี้ เราสามารถเปลี่ยนค่าตัวแปรที่มันชี้อยู่ผ่านทางได้โดยตรงด้วยด้วย ลองดูจากโค้ดด้านล่างนี้ประกอบได้เลย
int myNum = 9;
int * myPointer = &myNum;
printf("myNum: %d\n", myNum); //myNum: 9
*myPointer = 88;
printf("myNum: %d\n", myNum); //myNum: 88
myNum เริ่มต้นมามีค่า 9 ส่วน myPointer เป็น pointer ที่ชี้ myNum อยู่ พอเราเปลี่ยนค่าที่ myPointer ชี้อยู่ให้เป็น 88 แล้วลอง print ตัวแปร myNum ออกมาอีกทีก็จะเห็นว่ากลายเป็น 88 แล้วโดยที่เราไม่ต้องแตะ myNum เลยด้วยซ้ำ
เราใช้ Pointer จริงๆได้ยังไงบ้าง
การที่เราสามารถเปลี่ยนหรือใช้ค่าจาก ตัวชี้ ได้ทำให้เอาไปประยุกต์ในการเขียนโค้ดได้หลายๆแบบ อย่างเช่นการที่เราส่งค่าไปให้ฟังก์ชันต่างๆ แทนที่เราจะส่งเป็น value แบบปกติ แต่เราเปลี่ยนเป็นส่ง ตัวชี้เข้าไปแทน ฟังก์ชันนั้นก็จะสามารถเปลี่ยนค่าที่ เก็บอยู่ใน address ได้โดยตรง โดยที่ไม่จำเป็นจะต้อง return กลับออกมาเพื่อกำหนดให้กับตัวแปร เพื่อความเข้าใจง่ายดูโค้ดด้านล่างนี้ประกอบคำอธิบายได้เลย
#include <stdio.h>
void addFive(int * number) {
* number += 5;
}
int main() {
int myNum = 9;
int * myPointer = &myNum;
printf("myNum (before): %d\n", myNum);
addFive(myPointer);
printf("myNum (after): %d\n", myNum);
return 0;
}
ผลลัพธ์
myNum (before): 9
myNum (after): 14
จากโค้ดเราส่ง pointer ที่ชี้ address ของ myNum เข้าไปในฟังก์ชัน addFive ซึ่งในฟังก์ชัน addFive ก็ทำการกำหนดค่าใหม่ใส่ลงไปใน address ของ argument ที่ได้รับเข้ามาและจบการทำงานฟังก์ชัน โดยไม่ได้ return ค่าอะไรออกไป แต่ค่าของ myNum ก็ถูกเปลี่ยนเรียบร้อยแล้ว
Pointer เป็นสิ่งที่ภาษาคอมพิวเตอร์หลายๆภาษาใช้ในการทำงานเบื้องหลัง ซึ่งความแตกต่างในแต่ละภาษาก็จะเป้นความสามารถในการรองรับการจัดการกับ pointer เหล่านี้ที่ไม่เหมือนกัน อาจจะเป็น syntax หรือข้อจำกัดของแต่ละภาษาก็ต้องลองศึกษากันดู ถ้าเข้าใจว่า Pointer คืออะไรแล้ว การเขียนโปรแกรมจะสนุกขึ้นอย่างแน่นอนครับ
ขอบคุณข้อมูลอ้างอิงจาก