พอยน์เตอร์
พอยน์เตอร์ เป็นตัวแปรที่ใช้เก็บตำแหน่งที่อยู่ของตัวแปร การใช้พอยน์เตอร์ เราสามารถเข้าถึงข้อมูลที่เราต้องการได้โดยตรงโดยการใช้ชื่อของตัวแปร และมันมีประโยชน์มากในการเขียนโปรแกรมด้วยภาษาที่สามารถจัดการหน่วยความจำได้ง่าย เช่น ภาษา C และภาษา C++
มีเครื่องหมายประมาณ 2-3 อันที่คุณจะต้องรู้เกี่ยวกับพอยน์เตอร์:
- Address-of operator (&)
- Dereference operator (*)
- Declaration operator (*)
Address-of operator (&)
การใช้เครื่องหมาย ampersand (&) นำหน้าชื่อของตัวแปรจะส่งค่าที่อยู่ของหน่วยความจำกลับมา ที่อยู่ของหน่วยความจำนั้นสามารถได้มาในตอนที่โปรแกรมรันเท่านั้น มันบอกได้ว่าตัวแปรนั้นอยู่ที่ไหนในหน่วยความจำ สำหรับตัวอย่าง:
&myNumber;
คำสั่งนี้จะส่งค่าที่อยู่ของหน่วยความจำกลับมาที่จะแสดงในเลขฐาน 16 แต่ในบทเรียนนี้ ตัวอย่างของเราจะใช้เลขฐาน 10 เพื่อให้ง่ายต่อความเข้าใจของคุณ
int myNumber = 10;
cout << &myNumber; // assume to be 1477
สมมติคำสั่งด้านบนจะแสดง 1477
ออกทางหน้าจอ นั่นหมายถึงตัวแปร myNumber
มีตำแหน่งในหน่วยความจำคือ 1477 (physical address) ดังนั้น เราสามารถเข้าถึงข้อมูลของ myNumber
ได้โดยตรงโดยการใช้หลายเลขที่อยู่ 1477
Dereference operator (*)
ในตัวอย่างก่อนหน้า ที่อยู่ของตัวแปรสามารถได้มาจากเครื่องหมาย ampersand ก่อนชื่อตัวแปร ในการที่จะเข้าถึงข้อมูลโดยการใช้ที่อยู่เหล่านี้ เราใช้ *myNumber
เพื่อที่จะรับค่า
int myNumber = 10;
foo1 = &myNumber; // 1477
foo2 = *foo1 ;
ในตัวอย่างนี้ แสดงให้คุณเห็นถึงวิธีการเข้าถึงข้อมูลเมื่อเรารู้ที่อยู่ของมัน เราสมมติ 1477 เป็นที่อยู่ myNumber
เพราะว่าในความเป็นจริง เราไม่มีทางรู้ที่อยู่จริงๆ จนกว่าโปรแกรมจะรัน foo1
เก็บที่อยูของตัวแปร myNumber
(1477) ได้รับค่าที่ตัวแปร foo1
ชี้ไปโดยการใช้ *foo1
และมันจะส่งค่า 10 กลับมายังตัวแปร foo2
Declaring pointers
อย่างสองตัวอย่างที่ผ่านมา เราได้แนะนำเกี่ยวกับการรับที่อยู่ของตัวแปรและการเข้าถึงข้อมูลของมัน แต่ก่อนที่เราจะใช้พอยน์เตอร์เราต้องประกาศมันขึ้นมาก่อนเหมือนตัวแปร เพราะว่าพอยน์เตอร์เป็นประเภทตัวแปรของมันเอง เหมือนกับชื่อของมัน "พอยน์เตอร์" เป้าหมายของมันเพื่อชี้ไปยังที่อยู่ในหน่วยความจำ มาดูตัวอย่างการประกาศพอยน์เตอร์
int *pointer;
float *p1;
double *p2;
ในตัวอย่าง เราได้สร้างตัวแปรพอยน์เตอร์ 3 ตัว การสร้างพอยน์เตอร์จะต้องเริ่มด้วยการประกาศประเภทของมัน เช่น (int, float, double) ประเภทที่ว่านี้ไม่ได้หมายถึงประเภทของพอยน์เตอร์ แต่มันหมายถึงประเภทของตัวแปรที่พอยน์เตอร์จะชี้ไป และตามด้วยชื่อของพอยน์เตอร์ และคุณจะเห็นว่าเราได้ใส่เครื่องหมาย star (*) นำหน้าก่อนชื่อของมัน คุณอย่าสับสนในเครื่องหมาย deference operator (*) ที่มันใช้ในการเข้าถึงข้อมูลที่พอยน์เตอร์ได้ชี้ไป ซึ่งมันมีความหมายที่แตกต่างกันอย่างที่ได้กล่าวไป
#include <iostream>
using namespace std;
int main()
{
int myvar = 10;
int *mypointer;
mypointer = &myvar;
*mypointer = 20;
cout << myvar;
return 0;
}
เมื่อเรารันโปรแกรมนี้ มันจะได้ผลลัพธ์ดังนี้
20
ในตัวอย่างนี้ เราได้สร้างพอยน์เตอร์ที่ชื่อว่า mypointer
และประเภทของมันคือ int
เพราะว่าเราต้องการที่จะใช้ตัวแปรพอยน์เตอร์นี้ไปยังตัวแปร myvay
ซึ่งเป็นตัวแปรประเภทแบบ integer และคำสั่ง mypointer = &myvar
เราให้พอยน์เตอร์ของเราชี้ไปที่ตำแหน่งที่อยู่ของ myvar
ตอนนี้ เราสามารถทำทุกอย่างเกี่ยวกับที่อยู่ของตัวแปรพอยน์เตอร์ mypointer
ดังนั้นเราได้กำหนดค่า 20
ไปยังตำแหน่งนั้น และสุดท้าย เราแสดงผล myvar
เพื่อดูผลลัพธ์ของมัน
Pointers และ arrays
การใช้พอยน์เตอร์กับอาเรย์นั้นเป็นสิ่งที่มีประโยชน์มาก เพราะว่าเรารู้ว่าตำแหน่งของข้อมูลในอาเรย์นั้นอ้างอิงกับตำแหน่งแรกของอาเรย์
#include <iostream>
using namespace std;
int main()
{
int mynum[5] = {10, 20, 30, 40, 50};
int *mypoint;
mypoint = mynum;
*mypoint = 20;
mypoint++;
*mypoint = 80;
mypoint = mynum;
mypoint += 4;
*mypoint = 100;
for (int i = 0; i < 5; i++)
{
cout << mynum[i] << ", ";
}
return 0;
}
20, 80, 30, 40, 100,
ในตัวอย่างนี้ เราใช้พอยน์เตอร์ชี้ไปที่ mynum
และพอยน์เตอร์จะชี้ไปที่หัวหรือข้อมูลอันแรกของอาเรย์ ถ้าเราไม่รู้ตำแหน่งของอาเรย์ที่แน่นอน การเพิ่มค่าของพอยน์เตอร์โดยการใช้ ++
นั่นหมายความว่าเป็นการชี้ไปตำแหน่งถัดไปของข้อมูลในอาเรย์ เมื่อเราทราบว่าข้อมูลในอาเรย์ทุกตัวมีขนาดที่เท่ากัน เราสามารถไปที่ตำแหน่งใดๆ ของอาเรย์ได้โดยการใช้ mypoint += x
โดย x
เป็นจำแหน่งที่เราต้องการไปนับจากตำแหน่งแรกของอาเรย์หรือตำแหน่งปัจจุบันที่พอยน์เตอร์ชี้อยู่
Pointers addresses
พอนย์เตอร์นั้นเก็บค่าที่อยู่ของ Memory ที่ข้อมูลนั้นถูกเก็บอยู่ ในการที่จะดูตำแหน่งที่ข้อมูลถูกเก็บอยู่ สามารถดูได้สองวิธี คือผ่านตัวแปรพอยน์เตอร์ หรือผ่านสัญลักษณ์ของ Memory address (&) มาดูตัวอย่าง
#include <iostream>
using namespace std;
int main()
{
int mynum[5] = {10, 20, 30, 40, 50};
int *mypoint = mynum;
// via point
for (int i = 0; i < 5; i++)
{
cout << "Address at " << i << " = " << mypoint << endl;
mypoint++;
}
cout << endl;
// via addressing symbol
for (int i = 0; i < 5; i++)
{
cout << "Address at " << i << " = " << &mynum[i] << endl;
}
return 0;
}
และนี่เป็นผลลัพธ์เมื่อรันโปรแกรม โดยทั้งสองจะได้ผลลัพธ์เหมือนกัน
Address at 0 = 0x28fed0
Address at 1 = 0x28fed4
Address at 2 = 0x28fed8
Address at 3 = 0x28fedc
Address at 4 = 0x28fee0
Address at 0 = 0x28fed0
Address at 1 = 0x28fed4
Address at 2 = 0x28fed8
Address at 3 = 0x28fedc
Address at 4 = 0x28fee0
Pointer arithmetics
ในพอยน์เตอร์ ภาษา C++ ให้เราสามารถกระทำการทางคณิตศาสตร์กับตัวแปรพอยน์เตอร์ได้ ที่เราเพิ่งจะทำกันคือการทำให้พอยน์เตอร์ชี้ไปที่ที่อยู่ของตัวแปร มาดูตัวอย่างของพอยน์เตอร์กับการดำเนินการทางคณิตศาสตร์
int number = 8; // address 1277
int *p;
p = &number;
p++; // 1278
p--; // 1277
p+=1000; // 2277
int *p2;
p2 = &number;
*p2++; // number = 9
มาสมมติว่าเรามีตัวแปร number
ซึ่งที่ตำแหน่งที่อยู่ที่ 1277 และเราใช้พอยน์เตอร์ p
ชี้ไปที่ 1277 (Number's address) หลังจากนั้นเราสามารถย้ายพอยน์เตอร์ไปยังที่ไหนก็ตามที่เราต้องการ โดยอ้างอิงตำแหน่งจาก 1277 และเราใช้ p2
เพื่อเปลี่ยนค่าของ number
ในบทนี้ เราได้ครอบคลุมพื้นฐานในเรื่องพอยน์เตอร์ ซึ่งมันมีประโยชน์ในการจัดการหน่วยความจำแบบไดนามิกส์ ที่เราจะเรียนในบทถัดไป