บทที่ 9
พอยเตอร์
พอยเตอร์(Pointer)
พอยเตอร์คือต้นฉบับของชนิดข้อมูล
เป็นชนิดข้อมูลที่สร้างจากข้อมูลมาตรฐานขนิดหนึ่งค่าขงอมันก็คือตำแหน่ง
(Address) ที่อยู่ในหน่วยความจำของคอมพิวเตอร์
ซึ่งจะใช้สำหรับกำหนดค่าหรือเข้าถึงข้อมูล
พอยเตอร์นั้นสร้างจากแนวความคิดพื้นฐานของ Pointer Constants
Pointer Values
Pointer Values คือ ค่าตำแหน่ง Address ของตัวแปรนั้น ถ้าต้องการค่าของ
Address ของตำแหน่งของตัวแปรใด
หรือจะกำหนดค่าที่รับเข้ามาทางคีย์บอร์ดให้ไปเก็บไว้ที่ตัวแปรนั้นจะต้องใช้
ดเครื่องหมาย Address หรือ & ดังตัวอย่างด้านล่างแสดงการใช้ตัวแปร
aChar

&aChar
รูปที่ 9-1 แสดงตำแหน่ง Address ของตัวแปร
ตัวแปรพอยเตอร์

ถ้าผู้ใช้มี Pointer Constant และ Pointer Value
ผู้ใช้ก็สามารถมี Pointer Variable หรือตัวแปรพอยเตอร์ได้
และผู้ใช้ก็สามารถบรรจุ Address
ของตัวแปรตัวหนึ่งให้กับตัวแปรอีกตัวหนึ่งได้ ซึ่งแสดงในรูปที่ 9-2
รูปที่ 9-2 แสดงลักษณะของตัวแปรพอยเตอร์
ผู้ใช้จะต้องแบ่งระหว่างตัวแปรกับค่าของมัน รูปที่ 9-2
แสดงรายละเอียดที่แตกต่างกันในรูปแสดงให้เห็นว่า ตัวแปร a มีค่า –123
และตัวแปร a นั้นตั้งอยู่ในตำแหน่งที่ 234560 ในหน่วยความจำ
แม้ว่าชื่อขงองตัวแปรแบะตำแหน่งจะเป็นค่าคงที่
แต่ค่าเหล่านั้นก็สามารถเปลี่ยนแปลงได้ เมื่อโปรแกรมทำไปแล้ว
ในรูปนี้มีตัวแปรพอยเตอร์ p อยู่ด้วยพอยเตอร์จะมีชื่อและตำแหน่งอยู่ด้วย
ซึ่งทั้งคู่ก็เป็นค่าคงที่ด้วยเช่นกัน ค่าของมันในตำแหน่งนี้คือ
ตำแหน่งของหน่วยความจำที่ 234560 ความหมายคือ p ชี้ไปยังตำแหน่งที่ a
อยู่ในรูปที่ 9-2
ลักษณะทางกายภาพได้แสดงถึวข้อมูลและตัวแปรพอยเตอร์ที่อยู๋ในหน่วยความจำ
ส่วนในลักษณะทางความคิดแสดงให้เห็นความสัมพันธ์ระหว่างสิ่งเหล่านั้น
ผู้ใช้สามารถที่กำหนดตำแหน่ง Address
ของตัวแปรให้กับตัวแปรพอยเตอร์ได้มากกว่าหนึ่งตัว
ซึ่งแสดงตัวอย่างในรูปที่ 9-3 ในรูปนี้จะมีตัวแปร a และตัวแปรพอยเตอร์ p
และ q ซึ่งแต่ละพอยเตอร์ทั้งสองจะมีชื่อและตำแหน่งที่เป็นค่าคงที่
และทั้งคู่มีค่าที่ชี้ไปยังตำแหน่งหน่วยความจำที่ 234560 หมายความว่าทั้ง p
และ q ชี้ไปยังที่ตัวแปร a และตัวแปรพอยเตอร์ที่จะชี้ไปยังตำแหน่ง Address
ของตัวแปรตัวเดียวกันนั้นสามารถมีได้ไม่จำกัดจำนวน

รูปที่ 9-3 แสดงการใช้ตัวแปรพอยเตอร์หลายตัวชี้ไปที่ตัวแปรเดียวกัน
การเข้าถึงตัวแปรพอยเตอร์
ในขณะนี้ผู้ใช้มีตัวแปรและมีพอยเตอร์ที่ชี้ไปยังตัวแปรตัวนั้น
เมื่อไรที่ผู้ใช้ต้องการพอยเตอร์และต้องการเข้าถึงค่าที่พอยเตอร์ตัวนั้นชี้
อยู่ จะต้องใช้ตัวดำเนินการ Indirection หรือ * ยกตัวอย่างเช่น
ถ้าต้องการเข้าถึงค่าของตัวแปรที่มีพอยเตอร์ p ชี้อยู่
ก็สามารถเขียนได้ดังนี้
*p
อีกตัวอย่างหนึ่ง ถ้าผู้ใช้ต้องการที่จะบวก 1 ให้กับตัวแปร a
ผู้ใช้สามารถทำได้ อย่างเช่นใช้ชุดคำสั่งปกติ หรือสมมุติว่ามีพอยเตอร์ p
และกำหนดให้ p = &a จะเขียนชุดคำสั่งได้ดังนี้
a++; a=a+1; *p=p+1; (*p)++;
ในตัวอย่างชุดท้าย (*p)++ ผู้ใช้ต้องใช้วงเล็บตามตัวอย่าง
ไม่เช่นนั้นโปรแกรมจะผิดพลาดขึ้นมาทันที เพราะนิพจน์แบบ Postfix
แบบเพิ่มค่า มีลำดับความสำคัญอยู่ที่ 16 แต่เครื่องหมาย *
มีลำดับความสำคัญอยู่ที่ 15
ฉะนั้นการทำงานโดยไม่ใส่วงเล็บจะเป้ฯการเพิ่มค่าของตำแหน่งที่อยู่ที่ p
เก็บอยู่ไปอีก 1 ก่อน แล้วจึงไปนำค่าในตำแหน่งที่อยู่ใหม่ออกมาแทน
รูปที่ 9-4 จะแสดงตัวอย่างการเข้าถึงต่างๆ ซึ่งมีตัวแปร x และมีตัวแปรพอยเตอร์ p และq ที่ชี้ไปยังตัวแปร a

รูปที่ 9-4 แสดงตัวอย่างการเข้าถึงค่าที่พอยเตอร์ชี้ในแบบต่างๆ

เครื่องหมาย Indirection (*) และ address(&)
จะเป็นเครื่องหมายที่มีความหามายตรงกันข้าม และเมื่อนำมารวมกัน เช่น
*&x ก็จะมีความหมายเท่ากับ x นั่นเอง
รูปที่ 9-5 เครื่องหมาย Indirection และ Address
การประกาศและกำหนดลักษณะของพอยเตอร์
รูปที่ 9-6 ผู้ใช้จะใช้เครื่องหมาย Indirection
ในการประกาศและกำหนดลักษณะของตัวแปรพอยเตอร์
เมื่อทำตามนี้แล้วพอยเตอร์ก็จะยังไม่ชี้ไปยังตัวแปรใด
จะทำการกำหนดค่าให้ก่อนเสมอเหมือนตัวแปรทั่วๆไป

รูปที่ 9-6 การประกาศตัวแปรแบบพอยเตอร์

ในรูปที่ 9-7 แสดงการประกาศตัวแปรพอยเตอร์แบบต่างๆ
ซึ่งจะมีข้อมูลที่ตรงตามชนิดข้อมูล
และพอยเตอร์ที่ประกาศจะมีชนิดข้อมูลเป็นดังนี้ p เป็นพอยเตอร์ชนิดตัวอักษร
(Character),q เป็นพอยเตอร์ชนิดตัวเลขจำนวนเต็ม(Integer) และ r
เป็นพอยเตอร์ชนิดตัวเลขทศนิยม (Floating – point)
รูปที่ 9-7 การประกาศตัวแปรพอยเตอร์
ในโปรแกรมที่ 9-1 เป็นการบรรจุ Address ของตัวแปรให้กับพอยเตอร์ และพิมพ์คำเหล่านั้นออกมาโดยใช้ทั้งตัวแปรและพอยเตอร์
โปรแกรมที่ 9-1 แสดงการใช้พอยเตอร์
#include<stdio.h>
#include<conio.h>
int main (void)
{
int a;
int *p;
clrscr();
a=14;
p=&a;
printf("%d\n",*p);
printf("Value of 'a' is %d and Address of 'a' is %p\n",a,&a);
printf("Address of 'p' is %p Value of '*p' os %d and Value of 'a' is %d\n",p,*p,a);
getch();
return 0;
} |
ผลลัพธ์ที่ได้:
- 000135790
00135760 14 14 |
การกำหนดค่าเริ่มต้นของพอยเตอร์
ในภาษา C ถ้าไม่มีการกำหนดค่าเริ่มต้นให้กับตัวแปร
เหมือนโปรแกรมเริ่มทำงานหน่วยความจำของตัวแปรนั้นจะมีค่าบางอย่างที่ไม่อาจ
จะทราบได้
พอยเตอร์ก็เหมือนกับตัวแปร คือ เมื่อโปรแกรมเริ่มทำงานแล้ว
ไม่ได้ทำการกำหนดค่าเริ่มต้นให้กับพอยเตอร์
ในหน่วยความจำของพอยเตอร์ตัวนั้นจะมีค่าบางอย่างที่ไม่อาจจะทราบได้ค่า
บางอย่างนั้นคอมพิวเตอร์อาจจะนำไปใช้ไม่ได้
และถ้านำไปใช้อาจจะทำให้โปรแกรมเกิดการผิดพลาดขึ้นได้ ดังรูปที่ 9-8
จะแสดงตัวแปรและพอยเตอร์ที่ไม่มีการกำหนดค่า

รูปที่ 9-8 การประกาศตัวแปรพอยเตอร์
ปัญหาที่แสดงในรูปที่ 9-8 คือ ผู้ใช้ทำการกำหนดค่าให้ตัวแปรหรือพอยเตอร์เหล่านั้น
เช่น
int x; /*ตัวแปรชนิด int*/
int p=&a; /*pมีค่าของAddress*/
p=89 /*กำหนดค่า 89 ให้ a*/
จากตัวอย่างด้านบนในบรรทัดที่ 2 จะพบว่า มีการทำ 2 คำสั่งในบรรทัดเดียวกัน ซึ่งคำสั่งแสดงในรูปที่ 9-9

รูปที่ 9-9 การประกาศตัวแปรพอยเตอร์
และถ้าต้องการให้พอยเตอร์ชี้ไปที่ค่า NULL ก็สามารถทำได้ดังนี้
Int*p=NULL
เมื่อได้กำหนดพอยเตอร์ให้เป็น NULL ก็เท่ากับผู้ใช้ได้ใช้ Address ที่ 0
โปรแกรมที่ 9-2 แสดงการทำงานของพอยเตอร์
#include<stdio.h>
#include<conio.h>
int main (void)
{
int a;
int b;
int c;
int *p;
int *q;
int *r;
clrscr();
a = 6; //'p' =address of 'b'
b = 12; //'q'=address of 'b'
p = &b; // 'r'=address of 'c'
q = p; //p = address of 'a'
r = &c; // Value of 'q' =8
p = &a; //Value of 'r' =6
*q = 8;
*r = *p;
*r= a + *q + *&c;
printf("%d %d %d\n",a,b,c);
printf("%d %d %d\n",*p,*q,*r);
getch();
return 0;
} |
ผลลัพธ์ที่ได้:
6 8 20
6 8 20 |
ในโปรแกรมที่ 9-3 นี้จะเป็นการใช้พอยเตอร์ในการบวกเลขสองตัว ซึ่งจะมีตัวแปรต่างๆ ดังรูปที่ 9-10

รูปที่ 9-10 การบวกเลข 2 ตัว โดยใช้พอยเตอร์
โปรแกรมที่ 9-3 การบวกเลข 2 ตัวโดยใช้พอยเตอร์
#include<stdio.h>
#include<conio.h>
int main (void)
{
int a;
int b;
int c;
int *pa = &a;
int *pb = &b;
int *pc = &c;
clrscr();
printf("Enter the first number :");
scanf("%d",pa);
printf("Emter the second number :");
scanf("%d",pb);
*pc=*pa + *pb;
printf("\n%d+%d is %d",*pa,*pb,*pc);
getch();
return 0;
} |
ผลลัพธ์ที่ได้:
Enter the first number :15
Enter the second number:51
15+51 is 66 |
พอยเตอร์กับฟังก์ชัน
ในการใช้พอยเตอร์กับฟังก์ชัน จะมีการใช้อยู่ 2 แบบ คือ

1.การใช้พอยเตอร์เป็นพารามิเตอร์(Pointer ass Formal Parameters)
รูปที่ 9-11 และ 9-12 เป็นการสาธิตการใช้พอยเตอร์ ในรูปที่ 9-12 นั้น
มีการเรียกใช้ฟังก์ชัน Exchange ซึ่งฟังก์ชัน Exchange นี้ต้องการตัวแปร 2
ตัว ส่งไปให้เมื่อผู้ใช้ใช้การส่งค่าแบบ Pass-by-value
ข้อมูลที่แท้จริงในฟังกืชันทีเรียกจะไม่ถูกเปลี่ยนในฟังก์ชันที่ถูกเรียก
รูปที่ 9-11 แสดงการเปลี่ยนค่าที่ไม่ได้เปลี่ยนในตัวแปรจริง
ถ้าต้องการจะให้ค่าของตัวแปรตัวจริงสลับกัน จะต้องใช้พอยเตอร์เข้ามาช่วย หรือไม่ก็ประกาศตัวแปรเหล่านั้นแบบ Global
ในรูปที่ 9-12
แสดงการสลับค่าโดยใช้พอยเตอร์ให้สร้างพอยเตอร์ขึ้นมา แล้วเครื่องหมาย
Address ในเวลาที่ส่งค่าไปให้กับฟังก์ชั่นอื่น
ซึ่งแสดงดังตัวอย่างข้างล่าง จะส่งค่าตำแหน่ง Address ของตัวแปร a และ b
ไปให้
exchange(&a,&b);
ในการใช้การส่งค่าโดย Address นี้
พารามิเตอร์ในฟังก็ชั่นที่ถูกเรียก จะต้องกำหนดเป็นตัวแปรพอยเตอร์
ดังตัวอย่างที่แสดงด้านล่าง

void exchange(int *x,int *y);
รูปที่ 9-12 แสดงการเปลี่ยนค่าโดยใช้พอยเตอร์

2.ฟังก์ชันที่มีการส่งค่ากลับเป็นพอยเตอร์ (Functions Returning Parameters) ถ้า
ผู้ใช้มีฟังก์ชันที่ใช้หาค่าที่น้อยที่สุดระหว่างตัวเลข 2 ตัว
ในกรณีนี้ผู้ใช้จะต้องกำหนดให้พอยเตอร์ที่ชี้ไปตัวแปรทั้ง 2 ตัวนั้น
โดยให้เป็น a และ b โดยในฟังก์ชันมีเงื่อนไขที่ใช้หาค่าที่น้อยกว่า
และถ้าตัวเลขตัวไหนน้อยกว่าก็ส่งค่า Address ของตัวเลขตัวนั้นกลับมา
ตัวอย่างการส่งค่ากลับโดยใช้พอยเตอร์ แสดงในรูปที่ 9-13
รูปที่ 9-13 การส่งค่ากลับโดยใช้พอยเตอร์
Pointers To Pointers
Pointers To Pointers
คือ การใช้พอยเตอร์ตัวหนึ่งชี้ไปยังพอยเตอร์อีกตัวหนึ่ง
ซึ่งพอยเตอร์นั้นชี้ไปยังตัวแปร ซึ่งในรูปที่ 9-14 แสดงการชี้ 2 ระดับ
ซึ่งการทำแบบนี้สามารถทำได้ไม่จำกัดระดับ
ในแต่ละระดับนั้นต้องมีเครื่องหมาย Indirection 1 ตัว ดังรูปที่ 9-17 ให้ p ชี้ไปยัง a ก็สามารถ เขียนคำสั่งได้ดังนี้
*P
และถ้าต้องการให้ q ชี้ไปยัง a โดยผ่าน p ก็จะเป็น 2 ระดับ ก็จะเขียนคำสั่งได้ดังนี้
**q
ซึ่งผลลัพธ์ของโปรแกรมที่แสดงในรูปที่ 9-17 จะได้ดังนี้

58 58 58
รูปที่ 9-14 แสดง Pointers To Pointers

ในโปรแกรมที่ 9-4 แสดงการใช้ Pointers To Pointers ซึ่งจะโปรแกรมตามรูปที่ 9-15
รูปที่ 9-15 แสดงการใช้ Pointers To Pointers
โปรแกรมที่ 9-4 แสดงการใช้ Pointers To Pointers
#include<stdio.h>
#include<conio.h>
int main (void)
{
int a;
int *p;
int **q;
int ***r;
p = &a;
q = &p;
r = &q;
clrscr();
printf("Enter a number:");
scanf("%d",&a);
printf("The number is :%d\n",a);
printf("Enter a number:");
scanf("%d",p);
printf("The number is :%d\n",a);
printf("Enter a number:");
scanf("%d",*q);
printf("The number is :%d\n",a);
printf("Enter a number:");
scanf("%d",**r);
printf("The number is :%d\n",a);
getch();
return 0;
} |
ผลลัพธ์ที่ได้:
Enter a number:1
The number is :1
Enter a number:2
The number is:2
Enter a number:3
The number is:3
Enter a number:4
The number is:4 |