พอยน์เตอร์ลอย
อันตรายจากการใช้หลังคืนหน่วยความจำ
พอยน์เตอร์ลอย เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
พอยน์เตอร์ห้อยคืออะไร
พอยน์เตอร์ห้อยชี้ไปยังหน่วยความจำที่ถูกคืนแล้ว หรือไม่สามารถใช้งานได้อีกต่อไป
การใช้งานพอยน์เตอร์ลักษณะนี้ทำให้เกิดพฤติกรรมที่ไม่กำหนดไว้ เช่น โปรแกรมล่ม หน่วยความจำเสียหาย หรือเกิดข้อผิดพลาดที่ตรวจพบได้ยาก
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
*p = 5;
printf("%d\n", *p);
free(p);
p = NULL;
return 0;
}การใช้งานหลังคืนหน่วยความจำ
สาเหตุที่พบบ่อยที่สุดคือการอ่านหรือเขียนผ่านพอยน์เตอร์หลังเรียกใช้ free
บล็อกหน่วยความจำนั้นอาจถูกนำไปใช้กับสิ่งอื่นแล้ว
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
*p = 42;
free(p);
/* Reading *p here would be use-after-free. */
p = NULL;
printf("avoided use-after-free\n");
return 0;
}ตั้งเป็นค่าว่างหลังคืนหน่วยความจำ
การตั้งพอยน์เตอร์เป็น NULL ทันทีหลังคืนหน่วยความจำ จะเปลี่ยนการใช้งานโดยไม่ตั้งใจให้กลายเป็นการหยุดทำงานที่ตรวจพบได้ชัดเจน หรือเป็นการเรียก free(NULL) ที่ไม่ก่ออันตราย
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char *buf = malloc(10);
buf[0] = 'A';
free(buf);
buf = NULL;
if (buf == NULL) printf("buf is safely null\n");
return 0;
}การคืนแอดเดรสของตัวแปรภายใน
การคืนแอดเดรสของตัวแปรภายใน (บนสแตก) ทำให้เกิดพอยน์เตอร์ห้อย เพราะตัวแปรนั้นจะหายไปเมื่อฟังก์ชันคืนค่า
ให้ใช้หน่วยความจำบนฮีป หรือส่งบัฟเฟอร์เข้ามาแทน
#include <stdio.h>
#include <stdlib.h>
int *make_value(int v) {
int *p = malloc(sizeof(int));
*p = v;
return p;
}
int main(void) {
int *p = make_value(99);
printf("%d\n", *p);
free(p);
return 0;
}พอยน์เตอร์หลายตัวชี้บล็อกเดียวกัน
หากพอยน์เตอร์สองตัวอ้างถึงบล็อกเดียวกัน การคืนหน่วยความจำผ่านตัวหนึ่งจะทำให้อีกตัวกลายเป็นพอยน์เตอร์ห้อย
ให้ติดตามสิทธิ์ความเป็นเจ้าของ เพื่อให้มีเพียงเจ้าของเท่านั้นที่คืนหน่วยความจำ
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(sizeof(int));
*a = 7;
int *b = a;
printf("%d\n", *b);
free(a);
a = NULL;
b = NULL;
printf("both nulled\n");
return 0;
}พอยน์เตอร์ห้อยหลัง realloc
เมื่อ realloc ย้ายบล็อก พอยน์เตอร์เก่าที่ชี้ไปยังตำแหน่งเดิมจะกลายเป็นพอยน์เตอร์ห้อย
ให้ใช้เฉพาะพอยน์เตอร์ที่ realloc คืนมา
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *a = malloc(sizeof(int));
a[0] = 1;
int *b = realloc(a, 50 * sizeof(int));
/* a may now be dangling; use only b. */
b[0] = 2;
printf("%d\n", b[0]);
free(b);
return 0;
}การคืนหน่วยความจำในฟังก์ชันช่วย
หากฟังก์ชันช่วยคืนบล็อกหน่วยความจำ พอยน์เตอร์ของฟังก์ชันผู้เรียกจะกลายเป็นพอยน์เตอร์ห้อย ให้ตั้งค่าเป็นค่าว่างหลังการเรียก หรือออกแบบฟังก์ชันช่วยให้รับพอยน์เตอร์ไปยังพอยน์เตอร์
#include <stdio.h>
#include <stdlib.h>
void destroy(int **p) {
free(*p);
*p = NULL;
}
int main(void) {
int *p = malloc(sizeof(int));
*p = 5;
destroy(&p);
printf("p is %s\n", p == NULL ? "null" : "set");
return 0;
}เหตุใดจึงอันตราย
การใช้งานหน่วยความจำหลังคืนแล้วเป็นอันตราย เพราะหน่วยความจำนั้นอาจเก็บข้อมูลอื่นอยู่ การเขียนข้อมูลอาจทำให้สถานะที่ไม่เกี่ยวข้องเสียหาย และผู้โจมตีอาจใช้ประโยชน์จากช่องโหว่นี้ได้
พอยน์เตอร์ห้อยตามขอบเขต
พอยน์เตอร์ที่ชี้ไปยังตัวแปรภายในบล็อกจะไม่ถูกต้องเมื่อบล็อกสิ้นสุดลง อย่าเก็บพอยน์เตอร์ไว้นานกว่าอายุการใช้งานของสิ่งที่พอยน์เตอร์ชี้อยู่
#include <stdio.h>
int main(void) {
int *p;
{
int x = 10;
p = &x;
printf("in scope: %d\n", *p);
}
/* p now dangles; do not dereference it here. */
printf("block ended\n");
return 0;
}การตรวจหาพอยน์เตอร์ห้อย
เครื่องมืออย่าง AddressSanitizer และ Valgrind ตรวจจับการใช้งานหน่วยความจำหลังคืนแล้วขณะโปรแกรมทำงาน พร้อมระบุบรรทัดที่เกิดปัญหาได้อย่างแม่นยำ
ให้สร้างโปรแกรมพร้อมเครื่องมือตรวจสอบหน่วยความจำระหว่างการพัฒนา
สรุปวงจรการใช้งานที่ปลอดภัยในโค้ด
จองหน่วยความจำ ใช้งาน คืนหน่วยความจำ แล้วตั้งเป็นค่าว่าง การทำตามลำดับนี้อย่างสม่ำเสมอจะป้องกันไม่ให้พอยน์เตอร์กลายเป็นพอยน์เตอร์ห้อย
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int *p = malloc(sizeof(int));
if (!p) return 1;
*p = 123;
printf("%d\n", *p);
free(p);
p = NULL;
return 0;
}ตรวจสอบความเข้าใจ
ทดสอบความเข้าใจเรื่องพอยน์เตอร์ห้อย
สรุป
คุณได้เรียนรู้เกี่ยวกับพอยน์เตอร์ห้อย:
- พอยน์เตอร์เหล่านี้ชี้ไปยังหน่วยความจำที่ถูกคืนแล้วหรืออยู่นอกขอบเขต การใช้งานจึงมีพฤติกรรมที่ไม่กำหนดไว้
- หลีกเลี่ยงการคืนแอดเดรสของตัวแปรภายใน และอย่าใช้พอยน์เตอร์หลัง
freeหรือหลัง realloc ย้ายบล็อก - ตั้งพอยน์เตอร์เป็น
NULLหลังคืนหน่วยความจำ และติดตามสิทธิ์ความเป็นเจ้าของ - ใช้เครื่องมือตรวจสอบหน่วยความจำและ Valgrind เพื่อตรวจหาการใช้งานหน่วยความจำหลังคืนแล้ว
คำถามที่พบบ่อย
บทเรียน “พอยน์เตอร์ลอย” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “พอยน์เตอร์ลอย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “พอยน์เตอร์ลอย”
อันตรายจากการใช้หลังคืนหน่วยความจำ คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “พอยน์เตอร์ลอย” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม
ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- malloc และ free
- calloc และ realloc
- หน่วยความจำรั่ว
- พอยน์เตอร์ลอย