ฟรี (ptr) ที่ ptr เป็นหน่วยความจำ NULL เสียหายหรือไม่


112

ในทางทฤษฎีฉันสามารถพูดได้ว่า

free(ptr);
free(ptr); 

เป็นความเสียหายของหน่วยความจำเนื่องจากเรากำลังปลดปล่อยหน่วยความจำที่ได้รับการปลดปล่อยไปแล้ว

แต่ถ้า

free(ptr);
ptr=NULL;
free(ptr); 

เนื่องจากระบบปฏิบัติการจะทำงานในลักษณะที่ไม่ได้กำหนดฉันจึงไม่สามารถรับการวิเคราะห์ทางทฤษฎีที่แท้จริงเกี่ยวกับสิ่งที่เกิดขึ้นได้ ไม่ว่าฉันกำลังทำอะไรอยู่นี้หน่วยความจำเสียหายหรือไม่?

การพ้นตัวชี้ NULL ถูกต้องหรือไม่?


1
ไม่แน่ใจเกี่ยวกับมาตรฐาน C ฟรี แต่ในการลบ C ++ (NULL) นั้นถูกต้องอย่างสมบูรณ์ดังนั้นฉันคิดว่าฟรี (NULL) ก็ควรเป็นเช่นกัน
Priyank Bolia

14
@Pryank: delete NULLไม่ถูกต้องใน C ++ ลบสามารถนำไปใช้ค่า null ชี้ประเภทคอนกรีต NULLแต่ไม่ให้ delete (int*) NULLเป็นกฎหมาย delete NULLแต่ไม่ได้
AnT

ดังนั้นหมายความว่าหากตัวชี้ชี้ไปที่ NULL free จะไม่ทำอะไรนั่นหมายความว่า !!!!!! ทุกครั้งในการเขียนโปรแกรมของเราหากต้องการเพิ่มหน่วยความจำสามารถแทนที่ free (ptr) ด้วย ptr = NULL?
Vijay

3
ไม่ได้หากptrชี้ไปที่หน่วยความจำและคุณไม่ได้เรียกfreeใช้หน่วยความจำนั้นจะรั่วไหล การตั้งค่าให้NULLสูญเสียการจัดการกับหน่วยความจำและการรั่วไหล หากptr เกิดขึ้นการNULLโทรfreeคือการไม่ดำเนินการ
GManNickG

1
@benjamin: หือ? อะไรทำให้คุณสรุปได้ว่าคุณสามารถแทนที่free(ptr)ด้วยptr = NULL. ไม่มีใครพูดอะไรแบบนั้น
AnT

คำตอบ:


225

7.20.3.2 freeฟังก์ชัน

สรุป

#include <stdlib.h> 
void free(void *ptr); 

ลักษณะ

freeฟังก์ชั่นที่ทำให้เกิดช่องว่างที่ชี้ไปตามptrที่จะ deallocated, ที่อยู่, ทำใช้ได้สำหรับการจัดสรรเพิ่มเติม ถ้าptrเป็นตัวชี้ค่าว่างจะไม่มีการดำเนินการใด ๆ เกิดขึ้น

ดูISO-IEC 9899

ดังที่กล่าวไว้เมื่อดูโค้ดเบสที่แตกต่างกันในป่าคุณจะสังเกตเห็นบางครั้งผู้คนทำ:

if (ptr)
  free(ptr);

นี่เป็นเพราะเวลาทำงานของ C (ฉันจำได้ว่าเป็นกรณีของ PalmOS) จะผิดพลาดเมื่อปล่อยตัวNULLชี้

แต่ปัจจุบันฉันเชื่อว่าปลอดภัยที่จะถือว่าfree(NULL)เป็น nop ตามคำแนะนำของมาตรฐาน


29
ไม่ ptr = NULL ไม่มีทางแทนที่ฟรี (ptr) ทั้งสองอย่างแตกต่างกันอย่างสิ้นเชิง
Prasoon Saurav

7
NO ก็หมายความว่าfree(ptr)ที่ptrเป็นโมฆะไม่มีผลข้างเคียง แต่ไม่ว่าในกรณีใดทุกหน่วยความจำที่จัดสรรโดยใช้malloc()หรือcalloc()ต้องปล่อยหลังจากนั้นโดยใช้free()
Gregory Pakosz

4
ptr = NULL ช่วยให้มั่นใจได้ว่าแม้ว่าคุณจะโทรฟรี (ptr) โดยไม่ได้ตั้งใจโปรแกรมของคุณจะไม่ผิดพลาด
Prasoon Saurav

2
โปรดทราบว่าแม้ว่ามาตรฐาน C จะบอกว่าเป็น no-op แต่ก็ไม่ได้หมายความว่า C-library ทุกแห่งจะจัดการกับมันเช่นนั้น ฉันเคยพบข้อขัดข้องฟรี (NULL) ดังนั้นจึงเป็นการดีที่สุดที่จะหลีกเลี่ยงการโทรฟรีตั้งแต่แรก
Derick

6
@WereWolfBoy เขาหมายถึงหลีกเลี่ยงfree(NULL)โดยการทดสอบตัวชี้กับNULLก่อนที่จะโทรfree()
Gregory Pakosz

22

ไลบรารี C เวอร์ชันที่เป็นไปตามมาตรฐานทั้งหมดถือว่าฟรี (NULL) เป็น no-op

ที่กล่าวว่าครั้งหนึ่งมีเวอร์ชันฟรีบางเวอร์ชันที่จะหยุดทำงานฟรี (NULL) ซึ่งเป็นสาเหตุที่คุณอาจเห็นเทคนิคการเขียนโปรแกรมป้องกันที่แนะนำ:

if (ptr != NULL)
    free(ptr);

8
-1 [ต้องการอ้างอิง] การเปลี่ยนรูปแบบรหัสเนื่องจากทฤษฎีบางประการเกี่ยวกับการใช้คำบอกเล่าแบบโบราณเป็นความคิดที่ไม่ดี
Tomas

41
@ โทมัส - ฉันไม่เคยแนะนำให้เปลี่ยนสไตล์ฉันอธิบายง่ายๆว่าทำไมคุณยังคงเห็นคำแนะนำนี้ในบางสไตล์
R Samuel Klatchko

5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) และ PalmOS สำหรับสอง (มือ 2 สำหรับทั้งคู่)
Douglas Leeder

7
@ โทมัส: ปัญหาอยู่ในสิ่งต่างๆเช่นเวอร์ชัน 7 Unix เมื่อฉันกำลังเรียนรู้ฟรี (xyz) โดยที่ xyz == NULL เป็นสูตรสำหรับภัยพิบัติทันทีบนเครื่องที่ฉันเรียนรู้ (ICL Perq ที่รัน PNX ซึ่งอิงตามเวอร์ชัน 7 Unix พร้อมด้วยระบบพิเศษบางอย่างของ System III) แต่ฉันไม่ได้เขียนโค้ดแบบนั้นมานานแล้ว
Jonathan Leffler

2
Netware ขัดข้องบน NULL ฟรีด้วย ... (เพิ่งแก้ไขข้อผิดพลาดที่เกิดขึ้น ... )
Calmarius

13

หาก ptr เป็น NULL จะไม่มีการดำเนินการใด ๆ

เอกสารกล่าวว่า


คุณหมายความว่าฟรีจะไม่ทำอะไรเลยหรือ?
Vijay

2
เบนจามินนั่นคือสิ่งที่หมายถึง คุณคาดหวังให้มันทำงานอะไรหากตระหนักถึงความว่างเปล่าของอาร์กิวเมนต์
Michael Krelin - แฮ็กเกอร์

12

ฉันจำได้ว่าทำงานบน PalmOS ที่free(NULL)เกิดปัญหา


4
น่าสนใจ - นั่นทำให้แพลตฟอร์มที่สอง (หลัง 3BSD) เกิดปัญหา
Douglas Leeder

2
ถ้าจำไม่ผิดไม่มีบน Palm the C Standard Library แต่มีไฟล์ส่วนหัวส่วนใหญ่ที่ไม่รองรับซึ่งแมปไลบรารีมาตรฐานที่เรียกผ่านไปยัง Palm OS SDK หลายสิ่งหลายอย่างเกิดขึ้นโดยไม่คาดคิด การขัดข้องNULLเป็นหนึ่งในความแตกต่างที่สำคัญของกล่องเครื่องมือ Palm เมื่อเทียบกับไลบรารีมาตรฐาน
Steven Fisher

8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

คุณสามารถลบตัวชี้ NULL ได้อย่างปลอดภัย จะไม่มีการดำเนินการใด ๆ ในกรณีนั้นกล่าวอีกนัยหนึ่งคือ free () ไม่ทำอะไรเลยบนตัวชี้ NULL


8

แนะนำการใช้งาน:

free(ptr);
ptr = NULL;

ดู:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

เมื่อคุณตั้งค่าตัวชี้เป็นNULLหลังจากที่free()คุณสามารถเรียกfree()อีกครั้งและจะไม่มีการดำเนินการใด ๆ


3
นอกจากนี้ยังช่วยในการตรวจจับ segfaults ด้วยดีบักเกอร์ เห็นได้ชัดว่า segfault ที่ p-> do () ด้วย p = 0 คือคนที่ใช้ตัวชี้อิสระ ชัดเจนน้อยลงเมื่อคุณเห็น p = 0xbfade12 ในดีบักเกอร์ :)
neuro

6

free(NULL)ถูกต้องตามกฎหมายใน C เช่นเดียวกับdelete (void *)0และdelete[] (void *)0ถูกกฎหมายใน C ++

BTW การเพิ่มหน่วยความจำสองครั้งมักจะทำให้เกิดข้อผิดพลาดรันไทม์บางอย่างดังนั้นจึงไม่เสียหายอะไร


2
delete 0ไม่ถูกกฎหมายใน C ++ deleteต้องการนิพจน์ประเภทตัวชี้อย่างชัดเจน ถูกต้องตามกฎหมายที่จะนำไปใช้deleteกับค่า null-pointer ที่พิมพ์ แต่ไม่ใช้กับ0(และไม่ใช่NULL)
AnT

1
คุณไม่สามารถลบvoid*ได้: P มันควรเรียกใช้ตัวทำลายใด?
GManNickG

1
@GMan: คุณสามารถลบได้void *ตราบเท่าที่เป็น null-pointer
AnT

โอเคยุติธรรมพอ ฉันลืมไปว่าเรากำลังจัดการกับโมฆะโดยเฉพาะ
GManNickG

มักจะไม่เสียหายอะไร แต่ไม่รับประกัน ASLR ทำให้สิ่งนี้ไม่น่าเป็นไปได้ แต่ก็ยังไม่เป็นไปไม่ได้: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - ที่นี่หากคุณโชคไม่ดี buf2 มีที่อยู่เดียวกันกับ buf1 และคุณปล่อย buf1 โดยไม่ได้ตั้งใจสองครั้งดังนั้นในครั้งที่ 2 ที่ไม่มี buf1 คุณจะปล่อย buf2 อย่างเงียบ ๆ โดยไม่ต้องทำซ้ำ ข้อผิดพลาด / ความผิดพลาดใด ๆ (ไม่แน่นอน) / อะไรก็ตาม (แต่คุณอาจจะยังคงขัดข้องในครั้งต่อไปที่พยายามใช้ buf2 - และสถานการณ์นี้ไม่น่าเป็นไปได้มากหากคุณใช้ ASLR)
hanshenrik

3

free(ptr)จะบันทึกใน C ถ้าptrเป็นNULLอย่างไรก็ตามสิ่งที่คนส่วนใหญ่ไม่รู้คือNULLไม่จำเป็นต้องเท่ากับ 0 ฉันมีตัวอย่างโรงเรียนเก่าที่ดี: บน C64 ที่อยู่ 0 มี IO-Port หากคุณเขียนโปรแกรมใน C เพื่อเข้าถึงพอร์ตนี้คุณจะต้องมีตัวชี้ที่มีค่าเป็น 0 ไลบรารี C ที่เกี่ยวข้องจะต้องแยกความแตกต่างระหว่าง 0 และNULLจากนั้น

ขอแสดงความนับถือ.


ข้อเท็จจริงที่น่าสนใจทำให้ฉันประหลาดใจ ทำให้ฉันรู้สึกถูกบังคับให้เดินทางไปรอบ ๆ คำถาม / คำตอบของตัวชี้ NULL
arthropod

0

ไม่ใช่ความเสียหายของหน่วยความจำ แต่พฤติกรรมขึ้นอยู่กับการนำไปใช้ ตามมาตรฐานควรเป็นประมวลกฎหมาย


-3

ptr ชี้ไปที่ตำแหน่งหน่วยความจำบางตำแหน่งสมมติว่า 0x100

เมื่อคุณว่าง (ptr) โดยพื้นฐานแล้วคุณจะอนุญาตให้ใช้ 0x100 โดยตัวจัดการหน่วยความจำเพื่อใช้สำหรับกิจกรรมหรือกระบวนการอื่น ๆ และพูดง่ายๆก็คือการจัดสรรทรัพยากร

เมื่อคุณทำ ptr = NULL คุณกำลังทำให้ ptr ชี้ไปยังตำแหน่งใหม่ (ไม่ต้องกังวลว่า NULL คืออะไร) การทำเช่นนี้คุณสูญเสียการติดตามข้อมูลหน่วยความจำ 0x100 นี่คือสิ่งที่หน่วยความจำรั่วไหล

ดังนั้นจึงไม่แนะนำให้ใช้ ptr = NULL บน ptr ที่ถูกต้อง

แต่คุณสามารถตรวจสอบความปลอดภัยได้โดยใช้:

ถ้า (ptr! = NULL) {ฟรี (ptr);}

เมื่อคุณว่าง (ptr) โดยที่ ptr ชี้ไปที่ NULL อยู่แล้วจะไม่มีการดำเนินการใด ๆ ดังนั้นจึงปลอดภัยที่จะทำเช่นนั้น

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.