ฟังก์ชัน calloc() ในไลบรารี C พร้อมตัวอย่างโปรแกรม
⚡ สรุปอย่างชาญฉลาด
ฟังก์ชัน `calloc()` ในภาษา C จะจองบล็อกหน่วยความจำที่อยู่ติดกันหลายบล็อกบนฮีป และกำหนดค่าเริ่มต้นให้กับทุกไบต์เป็นศูนย์ โดยส่งคืนพอยเตอร์แบบ void ซึ่งช่วยให้โปรแกรมสามารถสร้างอาร์เรย์และโครงสร้างข้อมูลที่สะอาดและพร้อมใช้งานได้ในขณะรันไทม์

calloc ใน C คืออะไร?
ฟังก์ชัน `calloc()` ในภาษาซีใช้สำหรับจัดสรรบล็อกหน่วยความจำหลายบล็อกที่มีขนาดเท่ากัน เป็นฟังก์ชันการจัดสรรหน่วยความจำแบบไดนามิกที่จัดสรรพื้นที่หน่วยความจำให้กับโครงสร้างข้อมูลที่ซับซ้อน เช่น อาร์เรย์และโครงสร้างข้อมูล และส่งคืนพอยเตอร์แบบไม่มีพารามิเตอร์ไปยังหน่วยความจำนั้น `calloc` ย่อมาจาก `contiguous allocation` (การจัดสรรแบบต่อเนื่อง)
ฟังก์ชันมัลลอค ใช้เพื่อจัดสรรพื้นที่หน่วยความจำบล็อกเดียวในขณะที่ฟังก์ชัน calloc ใน C ใช้เพื่อจัดสรรพื้นที่หน่วยความจำหลายบล็อก แต่ละบล็อกที่จัดสรรโดย calloc ในการเขียนโปรแกรม C มีขนาดเท่ากัน
เหตุใดจึงต้องใช้ calloc() ในภาษา C?
ตัวแปรธรรมดาและอาร์เรย์ขนาดคงที่ จะล็อกขนาดของมันเมื่อโปรแกรมถูกคอมไพล์ ซึ่งทำให้สิ้นเปลืองพื้นที่เมื่อต้องการองค์ประกอบน้อยกว่า และจะล้มเหลวโดยสิ้นเชิงเมื่อต้องการมากกว่านั้น ฟังก์ชัน `calloc()` จะขจัดข้อจำกัดนั้นโดยการจองหน่วยความจำในขณะรันไทม์ และแตกต่างจาก `malloc()` ตรงที่มันจะล้างทุกไบต์ให้เป็นศูนย์ก่อนที่จะส่งบล็อกกลับคืน ทำให้ `calloc()` เป็นตัวเลือกที่เหมาะสมที่สุดเมื่อใดก็ตามที่โปรแกรมต้องการพื้นที่หน่วยความจำที่สะอาดและคาดเดาได้สำหรับอาร์เรย์หรือโครงสร้างที่มีขนาดที่ทราบเฉพาะในขณะที่โค้ดกำลังทำงานอยู่
การจัดสรรหน่วยความจำแบบไดนามิกด้วย calloc() เหมาะสำหรับสถานการณ์ทั่วไปหลายประการ:
- อาร์เรย์ตัวเลขที่ควรเริ่มต้นที่ศูนย์ เช่น ตัวนับ ฮิสโตแกรม หรือตัวสะสมค่าที่กำลังเพิ่มขึ้น
- โครงสร้างข้อมูลที่ค่าขยะที่เหลืออยู่จะก่อให้เกิดปัญหาที่ยากต่อการแก้ไขtracและแมลง
- Buffers ซึ่งความยาวขึ้นอยู่กับการป้อนข้อมูลของผู้ใช้หรือไฟล์ที่อ่านขณะที่โปรแกรมทำงาน
- บล็อกมีขนาดใหญ่เกินกว่าจะเก็บไว้ในสแต็กที่มีจำกัด เนื่องจากฟังก์ชัน calloc() ดึงข้อมูลจากฮีปที่มีขนาดใหญ่กว่ามาก
เนื่องจากบล็อกที่สงวนไว้เป็นบล็อกต่อเนื่องและมีค่าเป็นศูนย์อยู่แล้ว จึงสามารถใช้งานได้ทันทีเหมือนกับอาร์เรย์ทั่วไป โดยไม่ต้องมีลูปการเริ่มต้นแยกต่างหาก
calloc() ไวยากรณ์:
ptr = (cast_type *) calloc (n, size);
- ตัวอย่างคำสั่งข้างต้นของ calloc ในภาษา C ใช้ในการจัดสรรบล็อกหน่วยความจำ n ขนาดเท่ากัน
- หลังจากจัดสรรพื้นที่หน่วยความจำแล้ว ไบต์ทั้งหมดจะถูกเตรียมใช้งานให้เป็นศูนย์
- การขอ ตัวชี้ ซึ่งปัจจุบันอยู่ที่ไบต์แรกของพื้นที่หน่วยความจำที่จัดสรรจะถูกส่งกลับ
เมื่อใดก็ตามที่มีข้อผิดพลาดในการจัดสรรพื้นที่หน่วยความจำ เช่น หน่วยความจำไม่เพียงพอ ตัวชี้ null จะถูกส่งกลับดังแสดงในตัวอย่าง calloc ด้านล่าง
วิธีการใช้งาน calloc
โปรแกรม calloc ด้านล่างในภาษา C จะคำนวณผลรวมของลำดับเลขคณิต
#include <stdio.h> int main() { int i, * ptr, sum = 0; ptr = calloc(10, sizeof(int)); if (ptr == NULL) { printf("Error! memory not allocated."); exit(0); } printf("Building and calculating the sequence sum of the first 10 terms \ n "); for (i = 0; i < 10; ++i) { * (ptr + i) = i; sum += * (ptr + i); } printf("Sum = %d", sum); free(ptr); return 0; }
ผลลัพธ์ของ calloc ในตัวอย่าง C:
Building and calculating the sequence sum of the first 10 terms
Sum = 45
ความแตกต่างระหว่าง calloc() และ malloc()
ทั้ง calloc() และ malloc() ต่างก็จองหน่วยความจำบนฮีปและส่งคืนพอยเตอร์แบบไม่มีเงื่อนไข หรือ NULL ในกรณีที่ล้มเหลว แต่ทั้งสองฟังก์ชันมีความแตกต่างกันในสามประเด็นสำคัญที่จะเป็นตัวกำหนดว่าควรใช้ฟังก์ชันใด
- การเริ่มต้นใช้งาน: ฟังก์ชัน calloc() จะกำหนดค่าไบต์ทุกไบต์ในบล็อกใหม่ให้เป็นศูนย์ ในขณะที่ฟังก์ชัน malloc() จะปล่อยให้เนื้อหาภายในไม่มีการกำหนดค่าเริ่มต้น ดังนั้นบล็อก malloc() จึงเก็บค่าขยะที่ไม่สามารถคาดเดาได้จนกว่าโปรแกรมจะเขียนข้อมูลลงไปในบล็อกนั้น
- อาร์กิวเมนต์: ฟังก์ชัน calloc() รับอาร์กิวเมนต์สองตัว คือ จำนวนองค์ประกอบและขนาดของแต่ละองค์ประกอบ เขียนว่า calloc(n, size); ฟังก์ชัน malloc() รับอาร์กิวเมนต์เดียว คือ จำนวนไบต์ทั้งหมด เขียนว่า malloc(n * size)
- ความเร็ว: ฟังก์ชัน malloc() เร็วกว่าเล็กน้อย เนื่องจากข้ามขั้นตอนการกำหนดค่าเป็นศูนย์ ซึ่งเป็นเหตุผลว่าทำไมโค้ดที่เขียนทับหน่วยความจำทันทีจึงมักเลือกใช้ฟังก์ชันนี้
ฟังก์ชันทั้งสองถูกประกาศไว้ใน stdlib.h และทั้งคู่ปล่อยหน่วยความจำด้วยฟังก์ชัน free() เดียวกัน เลือกใช้ calloc() เมื่อต้องการบล็อกที่สะอาดและมีค่าเป็นศูนย์ และเลือกใช้ malloc() เมื่อต้องการความเร็วเป็นหลักและโปรแกรมจัดการการเริ่มต้นใช้งานเอง
วิธีการคืนหน่วยความจำที่จัดสรรโดย calloc()
หน่วยความจำที่จองโดยฟังก์ชัน calloc() จะอยู่บนฮีปและจะไม่ถูกปล่อยโดยอัตโนมัติ เมื่อโปรแกรมทำการจัดสรรหน่วยความจำโดยไม่ปล่อยหน่วยความจำ มันจะค่อยๆ ใช้หน่วยความจำที่มีอยู่ทั้งหมด ซึ่งเป็นข้อบกพร่องที่เรียกว่าหน่วยความจำรั่วไหล ฟังก์ชัน free() จะส่งคืนบล็อกที่เสร็จสมบูรณ์แล้วให้กับระบบ เพื่อให้สามารถนำพื้นที่นั้นกลับมาใช้ใหม่ได้โดยการจัดสรรในภายหลัง
ฟังก์ชัน free() รับอาร์กิวเมนต์เพียงตัวเดียว คือพอยเตอร์ที่ฟังก์ชัน calloc() ส่งคืน และปล่อยบล็อกทั้งหมดในคราวเดียว:
int *ptr; ptr = calloc(10, sizeof(int)); if (ptr != NULL) { /* use the allocated memory here */ free(ptr); /* release the block */ ptr = NULL; /* avoid a dangling pointer */ }
ปฏิบัติตามกฎเหล่านี้เพื่อจัดการหน่วยความจำของ calloc() อย่างปลอดภัย:
- เรียกฟังก์ชัน free() เพียงครั้งเดียวสำหรับการเรียก calloc() ที่สำเร็จแต่ละครั้ง การปลดปล่อยบล็อกเดียวกันสองครั้งจะทำให้เกิดพฤติกรรมที่ไม่แน่นอน
- หลังจากปล่อยหน่วยความจำแล้ว ให้ตั้งค่าตัวชี้เป็น NULL เพื่อป้องกันไม่ให้ถูกนำกลับมาใช้ใหม่เป็นตัวชี้ที่ชี้ไปยังตำแหน่งที่ไม่ถูกต้อง (dangling pointer)
- ห้ามใช้ free() กับพอยเตอร์ที่ calloc() ไม่ได้ส่งคืนมา รวมถึงพอยเตอร์ที่ถูกเลื่อนด้วยการคำนวณเลขคณิตของพอยเตอร์ด้วย
- ทุกครั้งที่มีการจัดสรรหน่วยความจำ จะต้องปล่อยหน่วยความจำก่อนที่ตัวชี้จะอยู่นอกขอบเขตการใช้งาน
เนื่องจากทั้ง calloc() และ malloc() ดึงข้อมูลจากฮีปเดียวกัน ดังนั้นกระบวนการปล่อยหน่วยความจำจึงเหมือนกันสำหรับทั้งสองฟังก์ชัน กล่าวคือ เรียก free() หนึ่งครั้งสำหรับการจัดสรรหน่วยความจำที่สำเร็จแต่ละครั้ง และจะไม่สามารถเข้าถึงบล็อกนั้นได้อีกต่อไป (Kee)ping การจัดสรรและการปล่อยหน่วยความจำอย่างสมดุลเป็นหัวใจสำคัญของการจัดการหน่วยความจำด้วยตนเองในภาษาซี และช่วยป้องกันทั้งการรั่วไหลและการหยุดทำงานที่เกิดจากการนำหน่วยความจำที่ถูกส่งคืนไปแล้วกลับมาใช้ซ้ำ
