คำตอบ:
ตามข้อกำหนดmalloc (0)จะส่งคืน "ตัวชี้ว่างหรือตัวชี้เฉพาะที่สามารถส่งผ่านไปยัง free () ได้สำเร็จ
โดยพื้นฐานแล้วจะช่วยให้คุณไม่ต้องจัดสรรอะไรเลย แต่ยังคงส่งผ่านตัวแปร "artist" ไปยัง call to free () ได้โดยไม่ต้องกังวล สำหรับวัตถุประสงค์ในทางปฏิบัติมันค่อนข้างเหมือนกับการทำ:
artist = NULL;
มาตรฐาน C (C17 7.22.3 / 1) กล่าวว่า:
หากขนาดของช่องว่างที่ร้องขอเป็นศูนย์จะมีการกำหนดพฤติกรรมการนำไปใช้: ตัวชี้ค่าว่างจะถูกส่งกลับหรือลักษณะการทำงานเหมือนกับว่าขนาดเป็นค่าที่ไม่ใช่ศูนย์ยกเว้นว่าจะไม่ใช้ตัวชี้ที่ส่งคืนเพื่อเข้าถึงวัตถุ
ดังนั้นmalloc(0)
สามารถส่งคืนNULL
หรือตัวชี้ที่ถูกต้องซึ่งอาจไม่สามารถอ้างอิงได้ ในทั้งสองกรณีก็ถูกต้องสมบูรณ์ที่จะเรียกfree()
มัน
ฉันไม่คิดว่าmalloc(0)
จะมีประโยชน์มากนักยกเว้นในกรณีที่malloc(n)
ถูกเรียกแบบวนซ้ำและn
อาจเป็นศูนย์
เมื่อดูโค้ดในลิงค์ฉันเชื่อว่าผู้เขียนมีความเข้าใจผิดสองประการ:
malloc(0)
ส่งกลับตัวชี้ที่ถูกต้องเสมอและfree(0)
ไม่ดี.ดังนั้นเขาจึงแน่ใจว่าartist
ตัวแปรอื่น ๆ มีค่าที่ "ถูกต้อง" อยู่ในตัวเสมอ ความคิดเห็นกล่าวว่าเท่า: // these must always point at malloc'd data
.
malloc(0)
ส่งคืนตัวชี้ที่ถูกต้องการmalloc()
ส่งคืนจะNULL
หมายถึง "ความล้มเหลว" เสมอและ0
ไม่ใช่กรณีพิเศษอีกต่อไปซึ่งสอดคล้องกันมากขึ้น
malloc
ความล้มเหลวในการรับหน่วยความจำถูกกำหนดให้ใช้งานได้การใช้งานจึงสามารถกำหนดได้ว่าการจัดสรรขนาด -0 นั้นไม่น่าพอใจเสมอ ( ENOMEM
) และตอนนี้การmalloc(0)
คืนค่า 0 (ด้วยerrno==ENOMEM
) จะสอดคล้องกัน :-)
realloc
ส่งตัวชี้กลับโดยmalloc(0)
? ได้realloc((char*)NULL)
มั้ย?
พฤติกรรม malloc (0) เป็นการใช้งานเฉพาะ ไลบรารีสามารถคืนค่า NULL หรือมีลักษณะการทำงาน malloc ปกติโดยไม่มีการจัดสรรหน่วยความจำ ไม่ว่าจะทำอะไรก็ตามจะต้องมีการบันทึกไว้ที่ใดที่หนึ่ง
โดยปกติแล้วจะส่งกลับตัวชี้ที่ถูกต้องและไม่ซ้ำกัน แต่ไม่ควรถูกอ้างถึง โปรดทราบว่าสามารถใช้หน่วยความจำได้แม้ว่าจะไม่ได้จัดสรรอะไรเลยก็ตาม
เป็นไปได้ที่จะจัดสรรตัวชี้ malloc (0) ที่ไม่ใช่ null ใหม่
การมี malloc (0) คำต่อคำไม่ได้ใช้มากนัก ส่วนใหญ่จะใช้เมื่อการจัดสรรแบบไดนามิกเป็นศูนย์ไบต์และคุณไม่สนใจที่จะตรวจสอบความถูกต้อง
malloc()
ต้องเก็บ "ข้อมูลการดูแลทำความสะอาด" ไว้ที่ไหนสักแห่ง (ขนาดของบล็อกที่จัดสรรไว้เช่นนี้และข้อมูลเสริมอื่น ๆ ) ดังนั้นหากmalloc(0)
ไม่กลับมาNULL
ก็จะใช้หน่วยความจำในการจัดเก็บข้อมูลนั้นและถ้าไม่free()
d จะทำให้หน่วยความจำรั่วไหล
malloc()
NULL
malloc(0)
. อย่างไรก็ตามในการใช้ไลบรารี C มาตรฐานเดียวกันrealloc(ptr, 0)
จะทำให้เป็นอิสระptr
และคืนค่า NULL
มีคำตอบที่อื่นในหน้านี้ซึ่งขึ้นต้นว่า "malloc (0) จะส่งคืนที่อยู่หน่วยความจำที่ถูกต้องและช่วงจะขึ้นอยู่กับประเภทของตัวชี้ที่กำลังจัดสรรหน่วยความจำ" ข้อความนี้ไม่ถูกต้อง (ฉันไม่มีชื่อเสียงมากพอที่จะแสดงความคิดเห็นเกี่ยวกับคำตอบนั้นโดยตรงดังนั้นจึงไม่สามารถใส่ความคิดเห็นนี้ได้โดยตรง)
การทำ malloc (0) จะไม่จัดสรรหน่วยความจำที่มีขนาดที่ถูกต้องโดยอัตโนมัติ ฟังก์ชัน malloc ไม่ทราบว่าคุณกำลังส่งผลลัพธ์ไปยังอะไร ฟังก์ชัน malloc ขึ้นอยู่กับจำนวนขนาดที่คุณให้เป็นอาร์กิวเมนต์เท่านั้น คุณต้องทำ malloc (sizeof (int)) เพื่อให้ได้พื้นที่เก็บข้อมูลเพียงพอที่จะเก็บ int ตัวอย่างเช่นไม่ใช่ 0
malloc(0)
ไม่สมเหตุสมผลสำหรับฉันเว้นแต่ว่าโค้ดจะขึ้นอยู่กับพฤติกรรมเฉพาะสำหรับการนำไปใช้งาน หากรหัสถูกกำหนดให้เป็นแบบพกพาก็จะต้องคำนึงถึงข้อเท็จจริงที่ว่าการคืนค่า NULL จากmalloc(0)
ไม่ใช่ความล้มเหลว เหตุใดจึงไม่เพียงกำหนดค่า NULL ให้artist
เพราะนั่นเป็นผลสำเร็จที่ถูกต้องและใช้รหัสน้อยกว่าและจะไม่ทำให้โปรแกรมเมอร์การบำรุงรักษาของคุณต้องใช้เวลาในการหาค่า
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
หรือmalloc(some_variable_which_might_be_zero)
บางทีอาจมีการใช้งานแม้ว่าคุณจะต้องระมัดระวังเป็นพิเศษอีกครั้งเพื่อไม่ให้การคืนค่า NULL เป็นความล้มเหลวหากค่าเป็น 0 แต่ขนาด 0 ควรจะใช้ได้
มีคำตอบที่เป็นจริงครึ่งหนึ่งอยู่มากมายดังนั้นนี่คือข้อเท็จจริงที่ยาก หน้าคนสำหรับmalloc()
พูดว่า:
ถ้าขนาดเป็น 0 ดังนั้น malloc () จะส่งกลับค่า NULL หรือค่าตัวชี้เฉพาะที่สามารถส่งผ่านไปยัง free () ได้ในภายหลัง
นั่นหมายความว่าไม่มีการรับประกันอย่างแน่นอนว่าผลลัพธ์ของmalloc(0)
จะไม่ซ้ำกันหรือไม่เป็น NULL การรับประกันเพียงอย่างเดียวมีให้โดยคำจำกัดความของfree()
อีกครั้งนี่คือสิ่งที่หน้าคนพูด:
หาก ptr เป็น NULL จะไม่มีการดำเนินการใด ๆ
ดังนั้นสิ่งที่ผลตอบแทนมันได้อย่างปลอดภัยจะส่งผ่านไปยังmalloc(0)
free()
แต่NULL
ตัวชี้ก็เช่นกัน
ดังนั้นการเขียน artist = malloc(0);
จึงไม่มีทางที่ดีไปกว่าการเขียน artist = NULL;
malloc(0)
สามารถส่งคืนพูด 0x1 และfree()
อาจมีการตรวจสอบกรณีพิเศษเป็น 0x1 เช่นเดียวกับ 0x0
NULL
หรือตัวชี้ที่ไม่ซ้ำกัน" แทน 'เป็นตัวชี้ค่าว่างหรือตัวชี้ไปยังพื้นที่ที่จัดสรร "ไม่มีข้อกำหนดเฉพาะ OTOH การส่งคืนค่าพิเศษที่ไม่ซ้ำกันอาจรบกวนรหัสที่นับตามค่าที่ไม่ซ้ำกันบางทีอาจเป็นคำถามกรณีมุมสำหรับ SO
man
อาจจัดทำเอกสารรูปแบบที่กำหนดการนำไปใช้งานที่ใช้ใน * nix ในกรณีนี้มันไม่เป็นเช่นนั้น แต่ก็ยังไม่ใช่แหล่งที่มาของบัญญัติสำหรับ C. ทั่วไป
ทำไมคุณไม่ควรทำสิ่งนี้ ...
เนื่องจากค่าส่งคืนของ malloc ขึ้นอยู่กับการนำไปใช้งานคุณอาจได้รับตัวชี้ NULL หรือที่อยู่อื่น ๆ กลับมา สิ่งนี้อาจทำให้การสร้างฮีปบัฟเฟอร์ล้นหากรหัสการจัดการข้อผิดพลาดไม่ตรวจสอบทั้งขนาดและค่าที่ส่งคืนซึ่งนำไปสู่ปัญหาด้านความเสถียร (ล่ม) หรือแม้แต่ปัญหาด้านความปลอดภัยที่แย่ลง
ลองพิจารณาตัวอย่างนี้ซึ่งการเข้าถึงหน่วยความจำเพิ่มเติมผ่านที่อยู่ที่ส่งคืนจะทำให้ขนาดของ heap iff เสียหายเป็นศูนย์และการใช้งานจะส่งคืนค่าที่ไม่ใช่ NULL กลับ
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
ดูหน้า Secure Codingจาก CERT Coding Standards ที่ฉันนำตัวอย่างด้านบนมาอ่านเพิ่มเติม
เป็นที่ยอมรับว่าฉันไม่เคยเห็นสิ่งนี้มาก่อนนี่เป็นครั้งแรกที่ฉันได้เห็นไวยากรณ์นี้ซึ่งอาจกล่าวได้ว่าเป็นกรณีคลาสสิกของฟังก์ชันโอเวอร์คิล จากคำตอบของ Reed ฉันอยากจะชี้ให้เห็นว่ามีสิ่งที่คล้ายกันซึ่งดูเหมือนว่าจะมีฟังก์ชันมากเกินไปrealloc
:
realloc(foo, size);
. เมื่อคุณส่งผ่านตัวชี้ที่ไม่ใช่ NULL และขนาดของศูนย์ไปยัง realloc realloc จะทำงานราวกับว่าคุณได้เรียกว่าฟรี (…)realloc(foo, size);
1 เมื่อคุณส่งผ่านตัวชี้ NULL และขนาดไม่ใช่ศูนย์ realloc จะทำงานราวกับว่าคุณเรียกว่า malloc (…)หวังว่านี่จะช่วยได้ขอแสดงความนับถือทอม
เพื่อตอบคำถามที่ถามจริง: ไม่มีเหตุผลที่จะทำเช่นนั้น
malloc (0) จะส่งคืนค่า NULL หรือตัวชี้ที่ถูกต้องซึ่งสามารถส่งผ่านไปยังอิสระได้อย่างถูกต้อง และถึงแม้ว่าความทรงจำที่ชี้ไปนั้นจะไร้ประโยชน์หรือไม่สามารถเขียนหรืออ่านได้ แต่ก็ไม่เป็นความจริงเสมอไป :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
เราคาดว่าจะมีข้อผิดพลาดในการแบ่งส่วนที่นี่ แต่น่าแปลกใจที่พิมพ์ได้ 100! เป็นเพราะ malloc ขอหน่วยความจำจำนวนมากเมื่อเราเรียก malloc เป็นครั้งแรก ทุกครั้งที่โทรหา malloc หลังจากนั้นจะใช้หน่วยความจำจากก้อนใหญ่นั้น หลังจากที่ชิ้นส่วนใหญ่สิ้นสุดลงหน่วยความจำใหม่จะถูกถาม
การใช้ malloc (0): หากคุณอยู่ในสถานการณ์ที่คุณต้องการให้การโทร malloc ครั้งต่อ ๆ ไปเร็วขึ้นการโทร malloc (0) ควรทำเพื่อคุณ (ยกเว้นกรณี edge)
*i
อาจไม่ผิดพลาดในกรณีของคุณ แต่ก็เป็นพฤติกรรมที่ไม่ได้กำหนดไว้ ระวังปีศาจจมูก!
malloc(0)
ที่ไม่ได้กล่าวถึง ในการใช้งานเหล่านั้นที่ส่งคืนค่าที่ไม่ใช่ค่าว่างโดยเฉพาะอย่างยิ่งในบิลด์ DEBUG มีแนวโน้มว่าจะจัดสรรมากกว่าที่คุณขอและให้ตัวชี้ผ่านส่วนหัวภายใน สิ่งนี้ช่วยให้คุณรู้สึกถึงการใช้หน่วยความจำจริงหากคุณได้รับสิ่งนี้ก่อนและหลังการจัดสรรชุด เช่น: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
หรือบางอย่าง
malloc(0)
และเดนนิสริตชี่และผมจำไม่ได้ว่ามันพูดอะไรเกี่ยวกับ คุณช่วยบอกว่าคุณกำลังอ้างถึงบทไหนด้วย? การเสนอราคาที่แน่นอนก็จะดีเช่นกัน
ใน Windows:
void *p = malloc(0);
จะจัดสรรบัฟเฟอร์ที่มีความยาวเป็นศูนย์บนฮีปโลคัล ตัวชี้ที่ส่งกลับเป็นตัวชี้ฮีปที่ถูกต้องmalloc
ในที่สุดเรียกHeapAlloc
โดยใช้ C runtime heap เริ่มต้นซึ่งจะเรียกRtlAllocateHeap
ฯลฯfree(p);
ใช้HeapFree
เพื่อเพิ่มความยาว 0 บัฟเฟอร์บนฮีป การไม่ปล่อยให้เป็นอิสระจะส่งผลให้หน่วยความจำรั่วไหลมันมีประโยชน์จริง ๆ และ (เห็นได้ชัดว่า IMHO) พฤติกรรมที่อนุญาตในการส่งคืนตัวชี้ NULL นั้นเสีย ตัวชี้แบบไดนามิกมีประโยชน์ไม่เพียง แต่สำหรับสิ่งที่ชี้ไปเท่านั้น แต่ยังรวมถึงความจริงที่ว่าที่อยู่นั้นไม่ซ้ำ การส่งคืนค่า NULL จะลบคุณสมบัติที่สองนั้น โปรแกรม mallocs I แบบฝังทั้งหมด (ค่อนข้างบ่อยในความเป็นจริง) มีพฤติกรรมเช่นนี้
ไม่แน่ใจตามซอร์สโค้ด malloc แบบสุ่มที่ฉันพบการป้อนข้อมูลเป็น 0 ส่งผลให้ค่าคืนค่าเป็น NULL ดังนั้นจึงเป็นวิธีที่ยอดเยี่ยมในการตั้งค่าตัวชี้ศิลปินเป็น NULL
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
นี่คือการวิเคราะห์หลังจากรันด้วยเครื่องมือตรวจสอบหน่วยความจำ valgrind
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
และนี่คือโค้ดตัวอย่างของฉัน:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
โดยค่าเริ่มต้น 1024 ไบต์จะถูกจัดสรร ถ้าฉันเพิ่มขนาดของ malloc ไบต์ที่จัดสรรจะเพิ่มขึ้น 1025 เป็นต้นไป
ตามคำตอบของReed Copseyและ man page ของ malloc ฉันเขียนตัวอย่างเพื่อทดสอบ และฉันพบว่า malloc (0) จะให้ค่าที่ไม่ซ้ำกันเสมอ ดูตัวอย่างของฉัน:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
ผลลัพธ์จะเป็น "Got a valid pointer" ซึ่งหมายความว่าptr
ไม่เป็นค่าว่าง
malloc(0)
จะส่งคืนที่อยู่หน่วยความจำที่ถูกต้องและช่วงที่มีจะขึ้นอยู่กับชนิดของตัวชี้ที่กำลังจัดสรรหน่วยความจำ นอกจากนี้คุณยังสามารถกำหนดค่าให้กับพื้นที่หน่วยความจำได้ แต่ควรอยู่ในช่วงที่ใช้ชนิดของตัวชี้ คุณยังสามารถเพิ่มหน่วยความจำที่จัดสรรให้เป็นอิสระ ฉันจะอธิบายสิ่งนี้ด้วยตัวอย่าง:
int *p=NULL;
p=(int *)malloc(0);
free(p);
โค้ดด้านบนจะทำงานได้ดีในgcc
คอมไพเลอร์บนเครื่อง Linux หากคุณมีคอมไพเลอร์ 32 บิตคุณสามารถระบุค่าในช่วงจำนวนเต็มได้เช่น -2147483648 ถึง 2147483647 เช่นเดียวกันกับอักขระด้วย โปรดทราบว่าหากประเภทของตัวชี้ที่ประกาศมีการเปลี่ยนแปลงช่วงของค่าต่างๆจะเปลี่ยนไปโดยไม่คำนึงถึงประเภทของการmalloc
พิมพ์กล่าวคือ
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
จะใช้ค่าตั้งแต่ 0 ถึง 255 ของถ่านเนื่องจากมีการประกาศ int ที่ไม่ได้ลงนาม
malloc()
ไม่รู้อะไรเกี่ยวกับนักแสดง (ซึ่งจริงๆแล้วมีอิทธิพลมากใน C) การอ้างถึงค่าที่ส่งคืนของmalloc(0)
will เรียกใช้พฤติกรรมที่ไม่ได้กำหนด
เพื่อแก้ไขการแสดงผลที่ผิดพลาดที่นี่:
artist = (char *) malloc(0);
จะไม่มีวันกลับมาNULL
อีก artist = NULL;
มันไม่เหมือนกัน เขียนโปรแกรมง่ายๆและเปรียบเทียบartist
กับNULL
. if (artist == NULL)
เป็นเท็จและif (artist)
เป็นความจริง