ความแตกต่างระหว่างการทำคืออะไร:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
หรือ:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
เมื่อใดที่ควรใช้ calloc ผ่าน malloc หรือในทางกลับกัน
ptr = calloc(MAXELEMS, sizeof(*ptr));
ความแตกต่างระหว่างการทำคืออะไร:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
หรือ:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
เมื่อใดที่ควรใช้ calloc ผ่าน malloc หรือในทางกลับกัน
ptr = calloc(MAXELEMS, sizeof(*ptr));
คำตอบ:
calloc()
ให้บัฟเฟอร์แบบ zero-initialized ขณะที่malloc()
ปล่อยให้หน่วยความจำไม่เริ่มต้น
สำหรับการจัดสรรขนาดใหญ่calloc
การใช้งานส่วนใหญ่ภายใต้ระบบปฏิบัติการหลักจะได้รับหน้าที่เป็นศูนย์จากระบบปฏิบัติการ (เช่นผ่าน POSIX mmap(MAP_ANONYMOUS)
หรือ Windows VirtualAlloc
) ดังนั้นจึงไม่จำเป็นต้องเขียนในพื้นที่ผู้ใช้ นี่คือวิธีที่ปกติmalloc
ได้รับหน้าเพิ่มเติมจากระบบปฏิบัติการเช่นกัน; calloc
เพียงแค่ใช้ประโยชน์จากการรับประกันของระบบปฏิบัติการ
ซึ่งหมายความว่าcalloc
หน่วยความจำยังคงสามารถ "สะอาด" และจัดสรรแบบ lazily และคัดลอกเมื่อเขียนไปยังเพจฟิสิคัลที่แบ่งใช้ทั่วทั้งระบบของศูนย์ (สมมติว่าระบบมีหน่วยความจำเสมือน)
คอมไพเลอร์บางคนยังสามารถเพิ่มประสิทธิภาพ + memset malloc (0) เข้า calloc สำหรับคุณ แต่คุณควรใช้ calloc 0
อย่างชัดเจนถ้าคุณต้องการหน่วยความจำในการอ่านเป็น
หากคุณไม่ได้อ่านหน่วยความจำก่อนที่จะเขียนให้ใช้malloc
เพื่อให้ (อาจ) ให้หน่วยความจำสกปรกจากรายการฟรีภายในแทนการรับหน้าใหม่จากระบบปฏิบัติการ (หรือแทนที่จะเป็นศูนย์บล็อกหน่วยความจำในรายการฟรีสำหรับการจัดสรรขนาดเล็ก)
การใช้งานในตัวของcalloc
อาจทำให้calloc
หน่วยความจำศูนย์ถึงตัวเองถ้าไม่มีระบบปฏิบัติการหรือมันไม่ใช่ระบบปฏิบัติการที่ผู้ใช้หลายคนที่ศูนย์หน้าเพื่อหยุดการรั่วไหลของข้อมูลระหว่างกระบวนการ
บน Linux ที่ฝังตัว malloc สามารถทำได้mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS)
ซึ่งเปิดใช้งานสำหรับเมล็ดในตัวบางตัวเท่านั้นเนื่องจากไม่ปลอดภัยในระบบที่มีผู้ใช้หลายคน
calloc
ไม่จำเป็นต้องมีราคาแพงมากนักเนื่องจากระบบปฏิบัติการสามารถใช้ลูกเล่นบางอย่างเพื่อเร่งความเร็วได้ ฉันรู้ว่า FreeBSD เมื่อมันได้รับเวลา CPU ที่ไม่ได้ใช้ให้ใช้เพื่อเรียกใช้กระบวนการง่ายๆที่เพิ่งไปรอบ ๆ และ zeroes บล็อกหน่วยความจำที่จัดสรรคืนและทำเครื่องหมายบล็อกซึ่งประมวลผลด้วยแฟล็ก ดังนั้นเมื่อคุณทำเช่นcalloc
นั้นก่อนอื่นคุณจะพยายามหาบล็อกที่มีค่าศูนย์ก่อนหน้านี้หนึ่งบล็อกและให้มันแก่คุณ - และเป็นไปได้มากว่ามันจะหาได้
ความแตกต่างที่รู้จักกันน้อยคือในระบบปฏิบัติการที่มีการจัดสรรหน่วยความจำในแง่ดีเช่น Linux ตัวชี้ที่ส่งคืนโดยmalloc
ไม่ได้รับการสนับสนุนจากหน่วยความจำจริงจนกว่าโปรแกรมจะสัมผัสจริง
calloc
ไม่แตะต้องหน่วยความจำ (มันเขียนเลขศูนย์บน) และดังนั้นคุณจะแน่ใจได้ว่าระบบปฏิบัติการกำลังสำรองการจัดสรรด้วย RAM จริง (หรือสลับ) นี่คือสาเหตุที่ช้ากว่า malloc (ไม่เพียง แต่ต้องเป็นศูนย์เท่านั้นระบบปฏิบัติการยังต้องค้นหาพื้นที่หน่วยความจำที่เหมาะสมโดยอาจสลับกระบวนการอื่น ๆ )
ดูตัวอย่างคำถาม SO นี้สำหรับการสนทนาเพิ่มเติมเกี่ยวกับพฤติกรรมของ malloc
calloc
ไม่จำเป็นต้องเขียนเลขศูนย์ หากบล็อกที่จัดสรรนั้นส่วนใหญ่เป็นศูนย์หน้าใหม่ที่จัดทำโดยระบบปฏิบัติการบล็อกนั้นสามารถปล่อยให้ไม่มีใครแตะต้องได้ นี้แน่นอนต้องที่จะปรับระบบปฏิบัติการมากกว่าฟังก์ชั่นห้องสมุดทั่วไปด้านบนของcalloc
malloc
หรือผู้ดำเนินการสามารถcalloc
เปรียบเทียบแต่ละคำกับศูนย์ก่อน zeroing สิ่งนี้จะไม่ประหยัดเวลา แต่จะหลีกเลี่ยงการทำให้หน้าใหม่สกปรก
dlmalloc
การใช้งานที่มีลักษณะคล้ายกันทั้งหมดข้ามขั้นตอนนี้memset
หากได้รับชิ้นผ่านmmap
หน้าใหม่ที่ไม่ระบุชื่อ (หรือเทียบเท่า) โดยปกติแล้วการจัดสรรแบบนี้จะใช้สำหรับชิ้นที่ใหญ่กว่าเริ่มต้นที่ 256k หรือมากกว่านั้น ฉันไม่รู้การใช้งานที่เปรียบเทียบกับศูนย์ก่อนที่จะเขียนศูนย์นอกเหนือจากของฉันเอง
omalloc
ยังข้ามmemset
; calloc
ไม่จำเป็นต้องแตะหน้าใด ๆ ที่ไม่ได้ใช้งานโดยแอปพลิเคชัน (แคชหน้า) ตลอดไป แม้ว่าการใช้งานดั้งเดิมมากcalloc
แตกต่างกัน
ข้อดีอย่างหนึ่งที่มักถูกมองข้ามcalloc
ก็คือ (การใช้งานตามมาตรฐาน) ซึ่งจะช่วยปกป้องคุณจากช่องโหว่จำนวนเต็มล้น เปรียบเทียบ:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
เมื่อเทียบกับ
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
อดีตอาจส่งผลให้การจัดสรรขนาดเล็กและหน่วยความจำล้นที่ตามมาหากมีค่ามากกว่าcount
SIZE_MAX/sizeof *bar
หลังจะล้มเหลวโดยอัตโนมัติในกรณีนี้เนื่องจากวัตถุที่ไม่สามารถสร้างขนาดใหญ่
แน่นอนคุณอาจต้องระวังการใช้งานที่ไม่สอดคล้องซึ่งละเลยความเป็นไปได้ของการล้น ... หากนี่เป็นข้อกังวลเกี่ยวกับแพลตฟอร์มที่คุณกำหนดเป้าหมายคุณจะต้องทำการทดสอบด้วยตนเองสำหรับการโอเวอร์โฟลว์ต่อไป
char
คือไม่ล้น แต่แปลงการดำเนินงานที่กำหนดไว้เมื่อกำหนดกลับผลเป็นchar
วัตถุ
size_t
เป็น 64- บิตดังนั้นจึงไม่มีปัญหา" นั่นเป็นวิธีคิดที่สมบูรณ์แบบที่จะนำไปสู่ข้อบกพร่องด้านความปลอดภัย size_t
เป็นประเภทนามธรรมที่แสดงถึงขนาดและมีเหตุผลที่จะคิดว่าสินค้าโดยพลการของจำนวน 32 บิตและไม่มีsize_t
(หมายเหตุ: sizeof *bar
สามารถในหลักการจะสูงกว่า 2 ^ 32 ในการดำเนินงาน C 64 บิต) size_t
พอดีใน
เอกสารทำให้ calloc มีลักษณะเหมือน malloc ซึ่งเพิ่งเริ่มต้นใช้หน่วยความจำไม่เป็นศูนย์ นี่ไม่ใช่ความแตกต่างหลัก! แนวคิดของ calloc คือการยกเลิกความหมายของ copy-on-write สำหรับการจัดสรรหน่วยความจำ เมื่อคุณจัดสรรหน่วยความจำด้วย calloc มันแผนที่ทั้งหมดไปยังหน้าทางกายภาพเดียวกันซึ่งเริ่มต้นเป็นศูนย์ เมื่อเพจใด ๆ ของหน่วยความจำที่จัดสรรถูกเขียนลงในฟิสิคัลเพจจะถูกจัดสรร มักใช้เพื่อสร้างตารางแฮชขนาดใหญ่ตัวอย่างเช่นเนื่องจากส่วนของแฮชที่ว่างเปล่าไม่ได้รับการสนับสนุนจากหน่วยความจำเพิ่มเติม (หน้า) พวกเขาชี้ไปที่หน้าเริ่มต้นเป็นศูนย์เดียวอย่างมีความสุขซึ่งสามารถแบ่งปันได้ระหว่างกระบวนการ
การเขียนไปยังที่อยู่เสมือนใด ๆ จะถูกแมปไปยังหน้าถ้าหน้านั้นเป็นหน้าศูนย์หน้าทางกายภาพอื่นได้รับการจัดสรรหน้าศูนย์จะถูกคัดลอกที่นั่นและการไหลของการควบคุมจะถูกส่งกลับไปยังกระบวนการไคลเอนต์ วิธีนี้ใช้งานได้เช่นเดียวกับไฟล์ที่แมปหน่วยความจำหน่วยความจำเสมือน ฯลฯ ใช้ .. การเพจ
นี่คือเรื่องราวการเพิ่มประสิทธิภาพหนึ่งเรื่องเกี่ยวกับหัวข้อ: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
ขนาดของบล็อกหน่วยความจำที่จัดสรรไม่แตกต่างกัน calloc
เพียงเติมบล็อกหน่วยความจำด้วยรูปแบบศูนย์ทั้งหมดบิตแบบฟิสิคัล ในทางปฏิบัติมันมักจะสันนิษฐานว่าวัตถุที่อยู่ในบล็อกหน่วยความจำที่จัดสรรด้วยcalloc
มีค่าเริ่มต้นราวกับว่าพวกเขาเริ่มต้นด้วยตัวอักษร0
เช่นจำนวนเต็มควรมีค่า0
ตัวแปรตัวแปรจุดลอยตัว - มูลค่าของ0.0
ตัวชี้ - ค่าตัวชี้โมฆะที่เหมาะสม และอื่น ๆ
จากจุดอวดความรู้ในมุมมองของ แต่calloc
(เช่นเดียวกับmemset(..., 0, ...)
) จะรับประกันเฉพาะที่จะต้องเริ่มต้น (มีเลขศูนย์) unsigned char
วัตถุชนิด ทุกอย่างอื่นไม่รับประกันว่าจะเริ่มต้นอย่างถูกต้องและอาจมีการเรียกว่าการเป็นตัวแทนกับดักซึ่งทำให้พฤติกรรมที่ไม่ได้กำหนด กล่าวอีกนัยหนึ่งสำหรับประเภทอื่นใดนอกเหนือunsigned char
จาก patterm all-zero-bits ดังกล่าวข้างต้นอาจเป็นตัวแทนของค่าที่ผิดกฎหมายการเป็นตัวแทนกับดัก
ต่อมาในหนึ่งใน Corrigenda ทางเทคนิคถึงมาตรฐาน C99 พฤติกรรมถูกกำหนดไว้สำหรับจำนวนเต็มทุกประเภท (ซึ่งสมเหตุสมผล) นั่นคืออย่างเป็นทางการในภาษา C ปัจจุบันคุณสามารถเริ่มต้นประเภทจำนวนเต็มด้วยcalloc
(และmemset(..., 0, ...)
) การใช้มันเพื่อเริ่มต้นสิ่งอื่นในกรณีทั่วไปนำไปสู่พฤติกรรมที่ไม่ได้กำหนดจากมุมมองของภาษา C
ในทางปฏิบัติcalloc
งานเรารู้ :) แต่ไม่ว่าคุณต้องการใช้ (พิจารณาข้างต้น) ขึ้นอยู่กับคุณ โดยส่วนตัวฉันชอบที่จะหลีกเลี่ยงมันอย่างสมบูรณ์ใช้malloc
แทนและทำการเริ่มต้นของตัวเอง
ในที่สุดรายละเอียดที่สำคัญอีกอย่างหนึ่งก็calloc
คือต้องใช้การคำนวณขนาดบล็อกขั้นสุดท้ายภายในโดยการคูณขนาดองค์ประกอบด้วยจำนวนองค์ประกอบ ในขณะที่ทำเช่นนั้นcalloc
ต้องคอยระวังโอเวอร์โฟลว์ทางคณิตศาสตร์ มันจะทำให้การจัดสรรไม่สำเร็จ (ตัวชี้โมฆะ) หากไม่สามารถคำนวณขนาดบล็อกที่ร้องขอได้อย่างถูกต้อง ในขณะที่malloc
รุ่นของคุณไม่พยายามดูมากเกินไป มันจะจัดสรรจำนวนหน่วยความจำที่ "คาดเดาไม่ได้" ในกรณีที่เกิดโอเวอร์โฟลว์
memset(p, v, n * sizeof type);
เกิดปัญหาเพราะn * sizeof type
อาจล้น เดาว่าฉันจะต้องใช้การfor(i=0;i<n;i++) p[i]=v;
วนซ้ำสำหรับโค้ดที่มีประสิทธิภาพ
n
องค์ประกอบอยู่ที่องค์ประกอบที่มีขนาดsizeof type
แล้วn*sizeof type
ไม่สามารถล้นเพราะขนาดสูงสุดของวัตถุใด ๆ SIZE_MAX
ที่จะต้องน้อยกว่า
SIZE_MAX
แต่ยังไม่มีอาร์เรย์ที่นี่ ตัวชี้ที่ส่งคืนจากcalloc()
สามารถชี้ไปยังหน่วยความจำที่จัดสรรเกินSIZE_MAX
ได้ การนำไปใช้งานหลายอย่าง จำกัด ผลิตภัณฑ์ของ 2 args ไปcalloc()
ที่SIZE_MAX
แต่ C spec ไม่ได้กำหนดขีด จำกัด นั้น
จากบทความการเปรียบเทียบสนุกกับ calloc () และศูนย์หน้าในบล็อกของ Georg Hager
เมื่อจัดสรรหน่วยความจำโดยใช้ calloc () จำนวนหน่วยความจำที่ร้องขอจะไม่ถูกจัดสรรทันที หน้าทั้งหมดที่เป็นของบล็อกหน่วยความจำจะเชื่อมต่อกับหน้าเดียวที่มีเลขศูนย์ทั้งหมดด้วยเวทมนตร์ MMU (ลิงก์ด้านล่าง) หากหน้าดังกล่าวเป็นเพียงการอ่าน (ซึ่งเป็นจริงสำหรับอาร์เรย์ b, c และ d ในเวอร์ชันมาตรฐานเดิม) ข้อมูลจะถูกจัดเตรียมจากหน้าศูนย์เดียวซึ่งแน่นอนว่าเหมาะกับแคช มากสำหรับเคอร์เนลวนหน่วยความจำที่ถูกผูกไว้ หากหน้าถูกเขียนไปยัง (ไม่ว่าจะเกิดอะไรขึ้น) จะเกิดความผิดพลาดหน้า“ ของจริง” จะถูกแมปและหน้าศูนย์จะถูกคัดลอกไปยังหน่วยความจำ สิ่งนี้เรียกว่า copy-on-write ซึ่งเป็นวิธีการเพิ่มประสิทธิภาพที่เป็นที่รู้จักกันดี (ซึ่งฉันได้สอนหลายครั้งในการบรรยาย C ++) หลังจากนั้น,
calloc
โดยทั่วไป malloc+memset
0
โดยทั่วไปจะดีกว่าเล็กน้อยที่จะใช้malloc+memset
อย่างชัดเจนโดยเฉพาะเมื่อคุณทำสิ่งที่ชอบ:
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
นั่นเป็นสิ่งที่ดีกว่าเพราะsizeof(Item)
รู้ว่าคอมไพเลอร์ ณ เวลารวบรวมและคอมไพเลอร์ส่วนใหญ่จะแทนที่ด้วยคำแนะนำที่ดีที่สุดเท่าที่จะเป็นไปได้สำหรับหน่วยความจำศูนย์ ในทางกลับกันหากmemset
เกิดขึ้นcalloc
ขนาดพารามิเตอร์ของการจัดสรรจะไม่ถูกรวบรวมในcalloc
รหัสและmemset
มักจะเรียกจริงซึ่งมักจะมีรหัสที่จะทำไบต์ - by - byte เติมจนขอบเขตยาวกว่าวงจรที่จะเติม เพิ่มหน่วยความจำเป็นsizeof(long)
ชิ้นและในที่สุดไบต์ต่อไบต์จะเต็มพื้นที่ที่เหลือ แม้ว่าตัวจัดสรรจะฉลาดพอที่จะโทรมาบ้างaligned_memset
มันจะยังคงเป็นลูปทั่วไป
หนึ่งข้อยกเว้นที่น่าสังเกตคือเมื่อคุณทำ malloc / calloc ของหน่วยความจำขนาดใหญ่มาก (บาง power_of_two กิโลไบต์) ซึ่งการจัดสรรกรณีอาจทำได้โดยตรงจากเคอร์เนล ในขณะที่เมล็ดในระบบปฏิบัติการโดยทั่วไปจะเป็นศูนย์ออกหน่วยความจำทั้งหมดที่พวกเขาให้ไปด้วยเหตุผลด้านความปลอดภัย calloc ฉลาดพอที่อาจเพียงแค่ส่งกลับมาพร้อมกับ zeroing เพิ่มเติม อีกครั้ง - หากคุณเพิ่งจัดสรรสิ่งที่คุณรู้ว่ามีขนาดเล็กคุณอาจจะดีกว่าด้วยประสิทธิภาพของ malloc + memset
calloc()
ช้ากว่าmalloc()
: การคูณสำหรับขนาด calloc()
จำเป็นต้องใช้การคูณทั่วไป (ถ้าsize_t
เป็น 64 บิตแม้การดำเนินการ 64 บิตที่มีราคาแพงมาก * 64 บิต = 64 บิต) ในขณะที่ malloc () มักจะมีค่าคงที่เวลารวบรวม
struct foo { char a,b,c; };
ไบต์ในช่วงเวลาที่ไม่ได้ไปจะได้เร็วขึ้นเพียงเพราะคุณกำลังแล้วจะใช้การระงับ calloc
ดีกว่าmalloc
+ เสมอmemset
หากคุณจะล้างพื้นที่ทั้งหมดตลอดmalloc
เวลา calloc
มีการตรวจสอบอย่างระมัดระวัง แต่มีประสิทธิภาพสำหรับองค์ประกอบ int * ขนาดที่มากเกินไป
ความแตกต่าง 1:
malloc()
มักจะจัดสรรบล็อกหน่วยความจำและมันจะเริ่มต้นส่วนหน่วยความจำ
calloc()
จัดสรรบล็อกหน่วยความจำและเริ่มต้นบล็อกหน่วยความจำทั้งหมดเป็น 0
ความแตกต่าง 2:
หากคุณพิจารณาmalloc()
ไวยากรณ์มันจะใช้เวลาเพียง 1 อาร์กิวเมนต์ ลองพิจารณาตัวอย่างต่อไปนี้ด้านล่าง:
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
เช่นหากคุณต้องการจัดสรรหน่วยความจำ 10 บล็อกสำหรับประเภท int
int *ptr = (int *) malloc(sizeof(int) * 10 );
หากคุณพิจารณาcalloc()
ไวยากรณ์มันจะใช้เวลา 2 ข้อโต้แย้ง ลองพิจารณาตัวอย่างต่อไปนี้ด้านล่าง:
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
ตัวอย่าง: หากคุณต้องการจัดสรรหน่วยความจำ 10 บล็อกสำหรับประเภท int และกำหนดค่าเริ่มต้นทั้งหมดเป็นศูนย์
int *ptr = (int *) calloc(10, (sizeof(int)));
ความคล้ายคลึงกัน:
ทั้งสองmalloc()
และcalloc()
จะคืนค่าเป็นโมฆะ * โดยค่าเริ่มต้นหากไม่ใช่ประเภท casted!
มีความแตกต่างสองประการ
ข้อแรกคือจำนวนข้อโต้แย้ง malloc()
รับอาร์กิวเมนต์เดี่ยว (หน่วยความจำจำเป็นต้องมีหน่วยเป็นไบต์) ในขณะที่calloc()
ต้องการสองอาร์กิวเมนต์
ประการที่สองmalloc()
ไม่เริ่มต้นหน่วยความจำที่จัดสรรในขณะที่calloc()
เริ่มต้นหน่วยความจำที่จัดสรรให้เป็นศูนย์
calloc()
จัดสรรพื้นที่หน่วยความจำความยาวจะเป็นผลคูณของพารามิเตอร์ calloc
เติมหน่วยความจำด้วย ZERO's และส่งคืนพอยน์เตอร์ไปที่ไบต์แรก ถ้ามันล้มเหลวในการค้นหาพื้นที่เพียงพอมันจะส่งกลับNULL
ตัวชี้ไวยากรณ์: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
เช่นptr_var=(type *)calloc(n,s);
malloc()
จัดสรรบล็อกหน่วยความจำเดียวขนาด REQUSTED SIZE และส่งกลับพอยน์เตอร์ไปยังไบต์แรก หากไม่สามารถระบุจำนวนหน่วยความจำที่ต้องการได้จะส่งคืนพอยน์เตอร์พอยน์เตอร์ไวยากรณ์: ฟังก์ชั่นใช้เวลาหนึ่งอาร์กิวเมนต์ซึ่งเป็นจำนวนไบต์ที่จะจัดสรรในขณะที่ptr_var=(cast_type *)malloc(Size_in_bytes);
malloc()
calloc()
ฟังก์ชั่นใช้เวลาสองมีปากเสียงหนึ่งเป็นจำนวนขององค์ประกอบและอื่น ๆ ที่เป็นจำนวนไบต์ที่จะจัดสรรสำหรับแต่ละองค์ประกอบเหล่านั้น นอกจากนี้calloc()
เริ่มต้นพื้นที่ที่จัดสรรให้เป็นศูนย์ในขณะที่malloc()
ไม่ได้
calloc()
ฟังก์ชั่นที่มีการประกาศใน<stdlib.h>
ส่วนหัวมีคู่ของประโยชน์มากกว่าmalloc()
ฟังก์ชั่น
malloc()
และcalloc()
เป็นฟังก์ชั่นจากไลบรารีมาตรฐาน C ที่อนุญาตการจัดสรรหน่วยความจำแบบไดนามิกซึ่งหมายความว่าทั้งคู่อนุญาตการจัดสรรหน่วยความจำระหว่างรันไทม์
ต้นแบบของพวกเขามีดังนี้:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
มีความแตกต่างสองหลักระหว่างสอง:
พฤติกรรม: malloc()
จัดสรรบล็อกหน่วยความจำโดยไม่เริ่มต้นและการอ่านเนื้อหาจากบล็อกนี้จะส่งผลให้มีค่าขยะ calloc()
ในทางกลับกันจัดสรรบล็อกหน่วยความจำและเริ่มต้นให้เป็นศูนย์และเห็นได้ชัดว่าการอ่านเนื้อหาของบล็อกนี้จะส่งผลให้ศูนย์
ไวยากรณ์: malloc()
รับ 1 อาร์กิวเมนต์ (ขนาดที่จะจัดสรร) และcalloc()
รับสองอาร์กิวเมนต์ (จำนวนบล็อกที่จะจัดสรรและขนาดของแต่ละบล็อก)
ค่าส่งคืนจากทั้งคู่เป็นตัวชี้ไปยังบล็อกของหน่วยความจำที่จัดสรรไว้หากประสบความสำเร็จ มิฉะนั้นจะคืนค่า NULLเพื่อระบุว่าการจัดสรรหน่วยความจำล้มเหลว
ตัวอย่าง:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
ฟังก์ชั่นเดียวกับที่calloc()
สามารถทำได้โดยใช้malloc()
และmemset()
:
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
โปรดทราบว่าmalloc()
มีการใช้งานมากกว่าcalloc()
เนื่องจากเร็วกว่า หากต้องการให้ค่าเริ่มต้นเป็นศูนย์ให้ใช้calloc()
แทน
ข้อแตกต่างที่ยังไม่ได้กล่าวถึง: จำกัด ขนาด
void *malloc(size_t size)
SIZE_MAX
เท่านั้นที่สามารถจัดสรรได้ถึง
void *calloc(size_t nmemb, size_t size);
SIZE_MAX*SIZE_MAX
สามารถจัดสรรขึ้นประมาณ
ความสามารถนี้ไม่ได้ใช้บ่อยในหลาย ๆ แพลตฟอร์มที่มีการกำหนดแอดเดรสเชิงเส้น ระบบดังกล่าว จำกัดด้วยcalloc()
nmemb * size <= SIZE_MAX
พิจารณาประเภทของ 512 ไบต์ที่เรียกว่าdisk_sector
และรหัสต้องการใช้เซ็กเตอร์จำนวนมาก ที่นี่รหัสสามารถใช้งานได้สูงสุดถึงSIZE_MAX/sizeof disk_sector
ภาค
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
พิจารณาสิ่งต่อไปนี้ซึ่งทำให้สามารถจัดสรรได้มากขึ้น
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
ตอนนี้ถ้าระบบดังกล่าวสามารถจัดหาการจัดสรรขนาดใหญ่เป็นเรื่องอื่น ส่วนใหญ่ในวันนี้จะไม่ ถึงกระนั้นมันก็เกิดขึ้นมาหลายปีแล้วเมื่อSIZE_MAX
มีจำนวน 65535 กฎหมายของมัวร์สงสัยว่าสิ่งนี้จะเกิดขึ้นประมาณปี 2030 ด้วยรุ่นหน่วยความจำบางรุ่นSIZE_MAX == 4294967295
และพูลหน่วยความจำใน 100 GBytes
size_t
มีขนาดใหญ่กว่า 32 บิต คำถามเดียวก็คือว่าการใช้calloc
กับค่าที่มีผลิตภัณฑ์เกินกว่าSIZE_MAX
สามารถพึ่งพาเพื่อให้ผลตอบแทนเป็นศูนย์แทนที่จะส่งกลับตัวชี้ไปยังการจัดสรรที่เล็กลง
calloc()
SIZE_MAX
มันได้เกิดขึ้นในอดีตที่ผ่านมามี 16 บิตsize_t
และหน่วยความจำยังคงลดราคาผมเห็นไม่มีเหตุผลมันจะไม่สามารถเกิดขึ้นได้ก้าวไปข้างหน้าถึงแม้ว่ามันจะไม่ได้พบบ่อย
SIZE_MAX
จัดสรรขนาดที่มีเกิน แน่นอนว่าไม่จำเป็นต้องมีสถานการณ์ใด ๆ ที่การจัดสรรดังกล่าวอาจประสบความสำเร็จ ฉันไม่แน่ใจว่ามีประโยชน์อย่างใดอย่างหนึ่งจากการบังคับใช้ว่าการใช้งานที่ไม่สามารถจัดการการจัดสรรดังกล่าวจะต้องส่งคืนNULL
(โดยเฉพาะอย่างยิ่งเนื่องจากเป็นเรื่องปกติสำหรับการใช้งานบางอย่างที่มีmalloc
ตัวชี้กลับไปยังพื้นที่ที่ยังไม่ได้ตกลง มัน).
size_t
ที่จะuint64_t
?
จำนวนบล็อก:
malloc () กำหนดบล็อกเดียวของหน่วยความจำที่ร้องขอ
calloc () กำหนดบล็อกหลายหน่วยความจำที่ร้องขอ
การเริ่มต้น:
malloc () - ไม่ชัดเจนและเริ่มต้นหน่วยความจำที่จัดสรร
calloc () - เริ่มต้นหน่วยความจำที่จัดสรรโดยศูนย์
ความเร็ว:
malloc () เร็ว
calloc () ช้ากว่า malloc ()
อาร์กิวเมนต์และไวยากรณ์:
malloc () รับ 1 อาร์กิวเมนต์:
ไบต์
calloc () รับ 2 อาร์กิวเมนต์:
ความยาว
void *malloc(size_t bytes);
void *calloc(size_t length, size_t bytes);
ลักษณะของการจัดสรรหน่วยความจำ:
ฟังก์ชั่น malloc จะกำหนดหน่วยความจำของ 'ขนาด' ที่ต้องการจากฮีปที่มีอยู่
ฟังก์ชัน calloc กำหนดหน่วยความจำที่มีขนาดเท่ากับอะไร 'num * size'
ความหมายเกี่ยวกับชื่อ:
ชื่อ malloc หมายถึง "การจัดสรรหน่วยความจำ"
ชื่อ calloc หมายถึง "การจัดสรรที่ต่อเนื่องกัน"
malloc
ครอบครัว