พอยน์เตอร์ใน C: พอยน์เตอร์ในการเขียนโปรแกรม C คืออะไร? ประเภท
⚡ สรุปอย่างชาญฉลาด
ตัวชี้ในภาษาซีเป็นตัวแปรที่เก็บที่อยู่หน่วยความจำของตัวแปรอื่น ช่วยให้สามารถจัดสรรหน่วยความจำแบบไดนามิก จัดการอาร์เรย์และสตริงได้อย่างมีประสิทธิภาพ และสร้างโครงสร้างข้อมูลที่ซับซ้อนได้ โดยใช้ตัวดำเนินการ address-of และ dereference เพื่ออ่านหรือแก้ไขค่า

ตัวชี้ (Pointer) ในภาษาซีคืออะไร?
A ตัวชี้ ในภาษาซี ตัวชี้ (pointer) คือตัวแปรที่เก็บที่อยู่ของตัวแปรอื่น ตัวชี้สามารถอ้างอิงถึงตัวชี้อื่นหรือฟังก์ชันก็ได้ ตัวชี้สามารถเพิ่มค่าหรือลดค่าเพื่อชี้ไปยังตำแหน่งหน่วยความจำถัดไปหรือก่อนหน้าได้ จุดประสงค์ของตัวชี้คือการประหยัดพื้นที่หน่วยความจำและทำให้การประมวลผลเร็วขึ้น
วิธีใช้พอยน์เตอร์ใน C
ถ้าเราประกาศตัวแปร v ชนิด int ตัวแปร v จะเก็บค่าไว้ ตัวแปรแต่ละตัว นอกจากค่าแล้ว ยังมีที่อยู่ด้วย นั่นคือตำแหน่งที่มันอยู่ในหน่วยความจำ สามารถเรียกดูที่อยู่ได้โดยการใส่เครื่องหมายแอมเปอร์แซนด์ (&) หน้าชื่อตัวแปร ถ้าคุณพิมพ์ที่อยู่ของตัวแปรออกมา มันจะมีลักษณะเหมือนตัวเลขสุ่ม ซึ่งอาจแตกต่างกันไปในแต่ละครั้งที่ทำงาน
แทนที่จะเก็บค่า ตัวชี้จะเก็บที่อยู่ของตัวแปร ตัวอย่างเช่น:
int *y = &v;
| ตัวแปร | ตัวชี้ |
|---|---|
| A ความคุ้มค่า เก็บไว้ในไฟล์ ชื่อ ที่อยู่หน่วยเก็บข้อมูล/หน่วยความจำ | A ตัวแปร ที่ จุด ที่อยู่การจัดเก็บ/หน่วยความจำของ อื่น ตัวแปร |
ประกาศตัวชี้
เช่นเดียวกับตัวแปร ตัวชี้เข้า การเขียนโปรแกรม C ต้องประกาศตัวแปรชี้ก่อนจึงจะสามารถใช้งานได้ การประกาศตัวแปรชี้มีรูปแบบดังนี้:
data_type *pointer_variable_name;
ที่นี่ ประเภทข้อมูล คือชนิดข้อมูลพื้นฐานของตัวชี้ และบ่งบอกถึงชนิดของตัวแปรที่ตัวชี้ชี้ไป เครื่องหมายดอกจัน (*) ซึ่งเป็นสัญลักษณ์เดียวกับที่ใช้ในการคูณ เป็นตัวดำเนินการอ้างอิงที่ใช้ในการประกาศตัวชี้ ตัวอย่างการประกาศตัวชี้ที่ถูกต้องมีดังนี้:
int *ptr_thing; /* pointer to an integer */ int *ptr1, thing; /* ptr1 points to an int; thing is an int */ double *ptr2; /* pointer to a double */ float *ptr3; /* pointer to a float */ char *ch1; /* pointer to a character */
เริ่มต้นตัวชี้
หลังจากประกาศตัวชี้แล้ว เราจะกำหนดค่าเริ่มต้นให้กับตัวชี้ด้วยที่อยู่ของตัวแปร หากตัวชี้ไม่ได้กำหนดค่าเริ่มต้นและถูกนำไปใช้ ผลลัพธ์อาจคาดเดาไม่ได้และอาจร้ายแรงได้ ในการรับที่อยู่ของตัวแปร ให้ใช้เครื่องหมายแอมเปอร์แซนด์ (&) นำหน้าชื่อตัวแปร:
pointer = &variable;
ตัวอย่างโปรแกรมอย่างง่ายที่แสดงวิธีการใช้งานตัวชี้มีดังต่อไปนี้:
#include <stdio.h> int main() { int a = 10; // variable declaration int *p; // pointer variable declaration p = &a; // store address of a in pointer p printf("Address stored in p is: %x\n", p); // access the address printf("Value stored in p is: %d\n", *p); // access the value return 0; }
Output:
Address stored in p is: 60ff08 Value stored in p is: 10
| OperaTor | ความหมาย |
|---|---|
| * | ฟังก์ชันนี้มีสองวัตถุประสงค์ คือ ประกาศตัวชี้ และส่งคืนค่าของตัวแปรที่ถูกชี้ (การเข้าถึงค่าที่ชี้โดยตัวชี้) |
| & | มีหน้าที่เดียวคือ ส่งคืนที่อยู่ของตัวแปร |
ประเภทของพอยน์เตอร์ในภาษาซี
ตัวชี้ว่าง
เราสร้างพอยเตอร์ว่างโดยการกำหนดค่า NULL ให้กับมันในระหว่างการประกาศ ซึ่งมีประโยชน์เมื่อยังไม่มีการกำหนดที่อยู่ให้กับพอยเตอร์นั้น พอยเตอร์ว่างจะมีค่าเป็น 0 เสมอ:
#include <stdio.h> int main() { int *p = NULL; // null pointer printf("The value inside variable p is: %x", p); return 0; }
ตัวชี้โมฆะ
พอยเตอร์แบบ void หรือที่เรียกว่าพอยเตอร์ทั่วไป ไม่มีชนิดข้อมูลมาตรฐานใดๆ สร้างขึ้นโดยใช้คำหลัก void และสามารถเก็บที่อยู่ของตัวแปรใดๆ ก็ได้:
#include <stdio.h> int main() { void *p = NULL; // void pointer printf("The size of pointer is: %d\n", sizeof(p)); return 0; }
ไวลด์พอยน์เตอร์
ตัวชี้ (pointer) ที่ไม่ได้กำหนดค่าเริ่มต้นให้ชี้ไปยังตำแหน่งใดๆ จะเรียกว่าตัวชี้ที่ไม่ถูกต้อง (wild pointer) ตัวชี้เหล่านี้ไม่มีประสิทธิภาพ เนื่องจากอาจชี้ไปยังตำแหน่งหน่วยความจำที่ไม่รู้จัก ซึ่งอาจก่อให้เกิดปัญหาและทำให้โปรแกรมหยุดทำงานได้ โปรดระมัดระวังในการใช้ตัวชี้ที่ไม่ถูกต้องเสมอ:
#include <stdio.h> int main() { int *p; // wild pointer printf("%d", *p); return 0; }
ตัวชี้ประเภทอื่นๆ ในภาษาซี ได้แก่ ตัวชี้ที่ชี้ไปยังตำแหน่งที่ว่างอยู่ (dangling pointer), ตัวชี้ที่ซับซ้อน (complex pointer), ตัวชี้ใกล้ (near pointer), ตัวชี้ไกล (far pointer) และตัวชี้ขนาดใหญ่ (huge pointer)
ตัวชี้การเข้าถึงโดยตรงและโดยอ้อม
ในภาษาซี มีสองวิธีที่เทียบเท่ากันในการเข้าถึงและจัดการเนื้อหาของตัวแปร การเข้าถึงโดยตรงใช้ชื่อตัวแปรโดยตรง ในขณะที่การเข้าถึงโดยอ้อมใช้ตัวชี้ไปยังตัวแปร:
#include <stdio.h> int var = 1; /* declare and initialize an int variable */ int *ptr; /* declare a pointer to int */ int main(void) { ptr = &var; /* point ptr to var */ printf("\nDirect access, var = %d", var); printf("\nIndirect access, var = %d", *ptr); *ptr = 48; /* change var through the pointer */ printf("\nIndirect access, var = %d", *ptr); return 0; }
ตัวชี้เลขคณิตใน C
เมื่อทำงานกับตัวชี้ ให้สังเกตกฎลำดับความสำคัญเหล่านี้ ตัวดำเนินการ * และ & มีลำดับความสำคัญเท่ากับตัวดำเนินการเอกภาค (การปฏิเสธ !, การเพิ่มค่า ++, การลดค่า –) ในนิพจน์เดียวกัน ตัวดำเนินการเอกภาค *, &, !, ++ และ — จะถูกประเมินจากขวาไปซ้าย ถ้าตัวชี้ P ชี้ไปยังตัวแปร X แล้ว สามารถใช้ *P ได้ทุกที่ที่สามารถเขียน X ได้ นิพจน์ต่อไปนี้เทียบเท่ากัน:
| การแสดงออก | การแสดงออกที่เท่าเทียมกัน |
|---|---|
| Y = *P + 1 | Y = X + 1 |
| *P = *P + 10 | X = X + 10 |
| *P += 2 | X += 2 |
| ++ป | ++เอ็กซ์ |
| (*ป)++ | เอ็กซ์++ |
ในกรณีสุดท้าย จำเป็นต้องมีวงเล็บ เนื่องจากตัวดำเนินการเอกภาค * และ ++ จะถูกประเมินจากขวาไปซ้าย หากไม่มีวงเล็บ ตัวชี้ P จะถูกเพิ่มค่า ไม่ใช่วัตถุที่มันชี้ไป การดำเนินการทางคณิตศาสตร์ที่ใช้ได้กับตัวชี้ ได้แก่ การกำหนดค่า การเพิ่มค่าและการลดค่า และการบวกหรือการลบtracโดยการส่งค่าออฟเซ็ตที่เป็นจำนวนเต็ม ซึ่งจะเลื่อนตัวชี้ไปตามจำนวนองค์ประกอบนั้น (แต่ละขั้นเท่ากับขนาดเป็นไบต์ของชนิดข้อมูลพื้นฐาน)
ตัวชี้และอาร์เรย์ในภาษา C พร้อมตัวอย่าง
โดยทั่วไป เราเข้าถึงองค์ประกอบของอาร์เรย์โดยใช้ดัชนี แต่ตัวชี้ก็ทำให้การเข้าถึงง่ายขึ้นเช่นกัน ตัวชี้ที่กำหนดค่าเป็นชื่อของอาร์เรย์จะชี้ไปยังองค์ประกอบแรก:
#include <stdio.h> int main() { int a[5] = {1, 2, 3, 4, 5}; // array initialization int *p; // pointer declaration p = a; // p points to the first element; same as &a[0] for (int i = 0; i < 5; i++) { printf("%d\n", *p); // print element p++; // move to the next element } return 0; }
การเพิ่มตัวเลขให้กับตัวชี้จะทำให้ตัวชี้เลื่อนไปข้างหน้าตามจำนวนองค์ประกอบนั้น ถ้า p ชี้ไปยังตำแหน่งหน่วยความจำที่ 0 การเพิ่ม p + 1 จะทำให้ตัวชี้ชี้ไปยังตำแหน่งหน่วยความจำที่ 1
ตัวชี้และสตริง C พร้อมตัวอย่าง
สตริงคืออาร์เรย์ของอ็อบเจ็กต์ char ที่ลงท้ายด้วยอักขระว่าง '\0' เราสามารถจัดการสตริงโดยใช้พอยเตอร์ได้:
#include <stdio.h> #include <string.h> int main() { char str[] = "Hello Guru99!"; char *p; p = str; printf("First character is: %c\n", *p); p = p + 1; printf("Next character is: %c\n", *p); p = str; // reset the pointer for (int i = 0; i < strlen(str); i++) { printf("%c\n", *p); p++; } return 0; }
อีกวิธีหนึ่งในการจัดการกับสตริงคือการใช้อาร์เรย์ของพอยเตอร์:
#include <stdio.h> int main() { char *materials[] = {"iron", "copper", "gold"}; for (int i = 0; i < 3; i++) printf("%s\n", materials[i]); return 0; }
ข้อดีของพอยน์เตอร์ในภาษาซี
- ตัวชี้มีประโยชน์สำหรับการเข้าถึงตำแหน่งหน่วยความจำโดยตรง
- พวกมันเป็นวิธีที่มีประสิทธิภาพในการเข้าถึงองค์ประกอบต่างๆ ในอาร์เรย์
- ใช้สำหรับจัดสรรและยกเลิกการจัดสรรหน่วยความจำแบบไดนามิก
- พวกมันถูกใช้เพื่อสร้างโครงสร้างข้อมูลที่ซับซ้อน เช่น รายการเชื่อมโยง กราฟ และต้นไม้
ข้อเสียของพอยน์เตอร์ใน C
- ตัวชี้เป็นสิ่งที่ซับซ้อนเล็กน้อยที่จะเข้าใจ
- สิ่งเหล่านี้อาจทำให้เกิดข้อผิดพลาด เช่น ข้อผิดพลาดในการแบ่งส่วนหน่วยความจำ หรือการเข้าถึงตำแหน่งหน่วยความจำที่ไม่ต้องการ
- การกำหนดค่าที่ไม่ถูกต้องให้กับตัวชี้อาจทำให้เกิดความเสียหายต่อหน่วยความจำได้
- ตัวชี้ (pointers) ยังเป็นสาเหตุของการรั่วไหลของหน่วยความจำได้ หากหน่วยความจำนั้นไม่ได้รับการปล่อยให้ว่าง
- เป็นหน้าที่ของโปรแกรมเมอร์ที่จะต้องจัดการกับตัวชี้อย่างระมัดระวัง
