การจัดสรรหน่วยความจำแบบไดนามิกในภาษา C: malloc(), calloc()
⚡ สรุปอย่างชาญฉลาด
การจัดสรรหน่วยความจำแบบไดนามิกในภาษา C จะสำรองและปล่อยหน่วยความจำฮีปในระหว่างการทำงานโดยใช้ฟังก์ชัน malloc(), calloc(), realloc() และ free() จากไลบรารี stdlib.h ทำให้โปรแกรมสามารถกำหนดขนาดของอาร์เรย์และโครงสร้างได้อย่างยืดหยุ่นเมื่อไม่ทราบความต้องการก่อนการทำงาน
การจัดการหน่วยความจำใน C ทำงานอย่างไร
เมื่อคุณประกาศตัวแปรโดยใช้ชนิดข้อมูลพื้นฐาน คอมไพเลอร์ภาษาซีจะจัดสรรพื้นที่หน่วยความจำให้กับตัวแปรนั้นโดยอัตโนมัติในกลุ่มหน่วยความจำที่เรียกว่าสแต็ก
ตัวอย่างเช่น ตัวแปร float โดยทั่วไปจะใช้พื้นที่ 4 ไบต์ (ขึ้นอยู่กับแพลตฟอร์ม) เมื่อประกาศ เราสามารถตรวจสอบข้อมูลนี้ได้โดยใช้ตัวดำเนินการ sizeof ดังแสดงในตัวอย่างด้านล่าง
#include <stdio.h> int main() { float x; printf("The size of float is %d bytes", sizeof(x)); return 0;}
การส่งออกจะได้รับ:
The size of float is 4 bytes
นอกจากนี้ อาร์เรย์ที่มีขนาดที่ระบุจะถูกจัดสรรในบล็อกหน่วยความจำที่อยู่ติดกัน แต่ละบล็อกมีขนาดสำหรับหนึ่งองค์ประกอบ:
#include <stdio.h> int main() { float arr[10]; printf("The size of the float array with 10 element is %d", sizeof(arr)); return 0;}
ผลลัพธ์คือ:
The size of the float array with 10 element is 40
ดังที่ได้เรียนรู้ไปแล้ว เมื่อประกาศชนิดข้อมูลพื้นฐานหรืออาร์เรย์ หน่วยความจำจะถูกจัดการโดยอัตโนมัติ อย่างไรก็ตาม มีกระบวนการจัดสรรหน่วยความจำในภาษา C ที่จะช่วยให้คุณสามารถเขียนโปรแกรมที่ขนาดของอาร์เรย์ไม่แน่นอนจนกว่าคุณจะรันโปรแกรม (รันไทม์) กระบวนการนี้เรียกว่า "การจัดสรรหน่วยความจำแบบไดนามิก"
การจัดสรรหน่วยความจำแบบไดนามิกใน C
การจัดสรรหน่วยความจำแบบไดนามิก คือการจัดสรรและปลดปล่อยหน่วยความจำด้วยตนเองตามความต้องการในการเขียนโปรแกรม หน่วยความจำแบบไดนามิกได้รับการจัดการและให้บริการด้วยตัวชี้ที่ชี้ไปยังพื้นที่หน่วยความจำที่จัดสรรใหม่ในบริเวณที่เราเรียกว่าฮีป
ตอนนี้คุณสามารถสร้างและทำลายอาร์เรย์ขององค์ประกอบแบบไดนามิกขณะรันไทม์ได้โดยไม่มีปัญหาใดๆ โดยสรุป การจัดการหน่วยความจำอัตโนมัติใช้สแต็ก และการจัดสรรหน่วยความจำแบบไดนามิก C ใช้ฮีป
ที่ ไลบรารีมีฟังก์ชันที่รับผิดชอบในการจัดการหน่วยความจำแบบไดนามิก
| ฟังก์ชัน | จุดมุ่งหมาย |
|---|---|
| มัลลอค () | จัดสรรหน่วยความจำตามขนาดที่ร้องขอและส่งกลับตัวชี้ไปที่ไบต์แรกของ พื้นที่จัดสรร |
| การโทร () | จัดสรรพื้นที่สำหรับองค์ประกอบของอาร์เรย์ เริ่มต้นองค์ประกอบให้เป็นศูนย์และส่งกลับตัวชี้ไปยังหน่วยความจำ |
| เรียลล็อค() | ใช้เพื่อปรับเปลี่ยนขนาดของพื้นที่หน่วยความจำที่จัดสรรไว้ก่อนหน้านี้ |
| ฟรี() | เพิ่มหรือล้างพื้นที่หน่วยความจำที่จัดสรรไว้ก่อนหน้านี้ |
เรามาหารือเกี่ยวกับฟังก์ชันข้างต้นกับแอปพลิเคชันกันดีกว่า
ฟังก์ชัน malloc() ในภาษาซี
ฟังก์ชัน C malloc() ย่อมาจากการจัดสรรหน่วยความจำ เป็นฟังก์ชันที่ใช้ในการจัดสรรบล็อกหน่วยความจำแบบไดนามิก จะสงวนพื้นที่หน่วยความจำตามขนาดที่ระบุและส่งกลับตัวชี้ null ที่ชี้ไปยังตำแหน่งหน่วยความจำ ตัวชี้ที่ส่งคืนมักจะเป็นประเภทโมฆะ หมายความว่าเราสามารถกำหนดฟังก์ชัน C malloc() ให้กับพอยน์เตอร์ใดก็ได้
ไวยากรณ์ของฟังก์ชัน malloc():
ptr = (cast_type *) malloc (byte_size);
ที่นี่
- ptr เป็นตัวชี้ของ cast_type
- ฟังก์ชัน C malloc() ส่งคืนตัวชี้ไปยังหน่วยความจำที่จัดสรรขนาด byte_size
ตัวอย่างของ malloc():
Example: ptr = (int *) malloc (50)
เมื่อดำเนินการคำสั่งนี้สำเร็จ พื้นที่หน่วยความจำ 50 ไบต์จะถูกสงวนไว้ ที่อยู่ของไบต์แรกของพื้นที่สงวนถูกกำหนดให้กับตัวชี้ ptr ประเภท int
ลองพิจารณาอีกตัวอย่างหนึ่ง:
#include <stdlib.h> int main(){ int *ptr; ptr = malloc(15 * sizeof(*ptr)); /* a block of 15 integers */ if (ptr != NULL) { *(ptr + 5) = 480; /* assign 480 to sixth integer */ printf("Value of the 6th integer is %d",*(ptr + 5)); } }
Output:
Value of the 6th integer is 480
- โปรดสังเกตว่ามีการใช้ sizeof(*ptr) แทน sizeof(int) เพื่อให้โค้ดมีความเสถียรมากขึ้นเมื่อมีการแปลงชนิดของการประกาศ *ptr ไปเป็นชนิดข้อมูลอื่นในภายหลัง
- การจัดสรรอาจล้มเหลวหากหน่วยความจำไม่เพียงพอ ในกรณีนี้จะส่งกลับตัวชี้ NULL ดังนั้นคุณควรรวมโค้ดเพื่อตรวจสอบตัวชี้ NULL
- โปรดจำไว้ว่าหน่วยความจำที่จัดสรรนั้นต่อเนื่องกันและสามารถถือเป็นอาร์เรย์ได้ เราสามารถใช้เลขคณิตตัวชี้เพื่อเข้าถึงองค์ประกอบของอาร์เรย์แทนที่จะใช้เครื่องหมายวงเล็บ [ ] เราแนะนำให้ใช้ + เพื่ออ้างถึงองค์ประกอบของอาร์เรย์ เนื่องจากการใช้การเพิ่มค่า ++ หรือ += จะเปลี่ยนที่อยู่ที่เก็บโดย ตัวชี้.
ฟังก์ชัน Malloc() ยังสามารถใช้ได้กับชนิดข้อมูลอักขระและชนิดข้อมูลที่ซับซ้อน เช่น โครงสร้างอีกด้วย
ฟังก์ชั่น free() ใน C
หน่วยความจำสำหรับ ตัวแปร ถูกจัดสรรคืนโดยอัตโนมัติในเวลารวบรวม ในการจัดสรรหน่วยความจำแบบไดนามิก คุณต้องจัดสรรหน่วยความจำอย่างชัดเจน หากไม่เสร็จสิ้น คุณอาจพบข้อผิดพลาดหน่วยความจำไม่เพียงพอ
ฟังก์ชัน free() ถูกใช้เพื่อปล่อย/ยกเลิกการจัดสรรหน่วยความจำในภาษา C การปล่อยหน่วยความจำในโปรแกรมของคุณจะทำให้มีหน่วยความจำว่างมากขึ้นสำหรับการใช้งานในภายหลัง
ตัวอย่างเช่น:
#include <stdio.h> int main() { int* ptr = malloc(10 * sizeof(*ptr)); if (ptr != NULL){ *(ptr + 2) = 50; printf("Value of the 2nd integer is %d",*(ptr + 2)); } free(ptr); }
Output:
Value of the 2nd integer is 50
ฟังก์ชัน calloc() ในภาษาซี
ฟังก์ชัน C calloc() ย่อมาจาก contiguous allocation ฟังก์ชันนี้ใช้เพื่อจัดสรรหน่วยความจำหลายบล็อก เป็นฟังก์ชันการจัดสรรหน่วยความจำแบบไดนามิกซึ่งใช้เพื่อจัดสรรหน่วยความจำให้กับโครงสร้างข้อมูลที่ซับซ้อน เช่น อาร์เรย์และโครงสร้าง
ฟังก์ชัน Malloc() ใช้เพื่อจัดสรรพื้นที่หน่วยความจำบล็อกเดียว ในขณะที่ calloc() ในภาษา C ใช้เพื่อจัดสรรพื้นที่หน่วยความจำหลายบล็อก แต่ละบล็อกที่จัดสรรโดยฟังก์ชัน calloc() มีขนาดเท่ากัน
ไวยากรณ์ของฟังก์ชัน calloc()
ptr = (cast_type *) calloc (n, size);
ข้อความข้างต้นใช้เพื่อจัดสรรบล็อกหน่วยความจำที่มีขนาดเท่ากัน
หลังจากจัดสรรพื้นที่หน่วยความจำแล้ว ไบต์ทั้งหมดจะถูกเตรียมใช้งานให้เป็นศูนย์
ตัวชี้ซึ่งขณะนี้อยู่ที่ไบต์แรกของพื้นที่หน่วยความจำที่จัดสรรจะถูกส่งกลับ
เมื่อใดก็ตามที่มีข้อผิดพลาดในการจัดสรรพื้นที่หน่วยความจำ เช่น หน่วยความจำไม่เพียงพอ ตัวชี้ค่าว่างจะถูกส่งกลับ
ตัวอย่างของ calloc():
โปรแกรมด้านล่างนี้คำนวณผลรวมของลำดับเลขคณิต
#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; }
ผลลัพธ์:
Building and calculating the sequence sum of the first 10 terms
Sum = 45
calloc() กับ malloc(): ความแตกต่างที่สำคัญ
ต่อไปนี้เป็นความแตกต่างที่สำคัญระหว่าง malloc() กับ calloc() ใน C:
โดยทั่วไปแล้ว ฟังก์ชัน calloc() จะเหมาะสมและมีประสิทธิภาพมากกว่าฟังก์ชัน malloc() แม้ว่าฟังก์ชันทั้งสองจะใช้เพื่อจัดสรรพื้นที่หน่วยความจำ แต่ calloc() สามารถจัดสรรบล็อกได้หลายบล็อกในเวลาเดียวกัน คุณไม่จำเป็นต้องร้องขอบล็อกหน่วยความจำทุกครั้ง ฟังก์ชัน calloc() ใช้ในโครงสร้างข้อมูลที่ซับซ้อนซึ่งต้องการพื้นที่หน่วยความจำขนาดใหญ่
บล็อกหน่วยความจำที่จัดสรรโดย calloc() ใน C จะถูกเตรียมใช้งานเป็นศูนย์เสมอในขณะที่อยู่ในฟังก์ชัน malloc() ใน C โดยจะมีค่าขยะอยู่เสมอ
ฟังก์ชัน realloc() ใน C
การใช้ฟังก์ชัน realloc() ในภาษา C ช่วยให้คุณสามารถเพิ่มขนาดหน่วยความจำให้กับหน่วยความจำที่จัดสรรไว้แล้วได้ ฟังก์ชันนี้จะขยายบล็อกปัจจุบันโดยคงเนื้อหาเดิมไว้ realloc() ในภาษา C ย่อมาจาก reallocation of memory (การจัดสรรหน่วยความจำใหม่)
realloc() ยังสามารถใช้เพื่อลดขนาดของหน่วยความจำที่จัดสรรไว้ก่อนหน้านี้ได้
ไวยากรณ์ของฟังก์ชัน realloc():
ptr = realloc (ptr,newsize);
คำสั่งข้างต้นจัดสรรพื้นที่หน่วยความจำใหม่ด้วยขนาดที่ระบุในตัวแปร newsize หลังจากดำเนินการฟังก์ชัน ตัวชี้จะถูกส่งกลับไปยังไบต์แรกของบล็อกหน่วยความจำ ขนาดใหม่อาจใหญ่หรือเล็กกว่าหน่วยความจำก่อนหน้าได้ เราไม่สามารถแน่ใจได้ว่าหากบล็อกที่จัดสรรใหม่จะชี้ไปยังตำแหน่งเดียวกันกับบล็อกหน่วยความจำก่อนหน้า ฟังก์ชันนี้จะคัดลอกข้อมูลก่อนหน้าทั้งหมดในภูมิภาคใหม่ ทำให้แน่ใจว่าข้อมูลจะยังคงปลอดภัย
ตัวอย่างของการจัดสรรใหม่ ():
#include <stdio.h> int main () { char *ptr; ptr = (char *) malloc(10); strcpy(ptr, "Programming"); printf(" %s, Address = %u\n", ptr, ptr); ptr = (char *) realloc(ptr, 20); //ptr is reallocated with new size strcat(ptr, " In 'C'"); printf(" %s, Address = %u\n", ptr, ptr); free(ptr); return 0; }
เมื่อใดก็ตามที่ realloc() ใน C ส่งผลให้การดำเนินการไม่สำเร็จ ก็จะส่งคืนตัวชี้ค่าว่าง และข้อมูลก่อนหน้านี้ก็จะได้รับการปลดปล่อยด้วยเช่นกัน
อาร์เรย์แบบไดนามิกใน C
อาร์เรย์แบบไดนามิกในภาษา C ช่วยให้จำนวนองค์ประกอบเพิ่มขึ้นตามต้องการ อาร์เรย์แบบไดนามิกใน C ใช้กันอย่างแพร่หลายในอัลกอริทึมของวิทยาการคอมพิวเตอร์
ในโปรแกรมต่อไปนี้ เราได้สร้างและปรับขนาดอาร์เรย์ไดนามิกใน C
#include <stdio.h> int main() { int * arr_dynamic = NULL; int elements = 2, i; arr_dynamic = calloc(elements, sizeof(int)); //Array with 2 integer blocks for (i = 0; i < elements; i++) arr_dynamic[i] = i; for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]); elements = 4; arr_dynamic = realloc(arr_dynamic, elements * sizeof(int)); //reallocate 4 elements printf("After realloc\n"); for (i = 2; i < elements; i++) arr_dynamic[i] = i; for (i = 0; i < elements; i++) printf("arr_dynamic[%d]=%d\n", i, arr_dynamic[i]); free(arr_dynamic); }
ผลลัพธ์ของโปรแกรม C Dynamic Array ที่หน้าจอ:
arr_dynamic[0]=0 arr_dynamic[1]=1 After realloc arr_dynamic[0]=0 arr_dynamic[1]=1 arr_dynamic[2]=2 arr_dynamic[3]=3


