การจัดสรรหน่วยความจำแบบไดนามิกในภาษา C โดยใช้ฟังก์ชัน malloc(), calloc()
ก่อนที่คุณจะเรียนรู้การจัดสรร C Dynamic Memory มาทำความเข้าใจกันก่อน:
การจัดการหน่วยความจำใน C ทำงานอย่างไร
เมื่อคุณประกาศตัวแปรโดยใช้ชนิดข้อมูลพื้นฐาน คอมไพเลอร์ C จะจัดสรรพื้นที่หน่วยความจำสำหรับตัวแปรในกลุ่มหน่วยความจำที่เรียกว่า กอง.
ตัวอย่างเช่น ตัวแปร float โดยทั่วไปจะใช้เวลา 4 ไบต์ (ตามแพลตฟอร์ม) เมื่อมีการประกาศ เราสามารถตรวจสอบข้อมูลนี้ได้โดยใช้ ขนาดของ ตัวดำเนินการดังแสดงในตัวอย่างด้านล่าง
#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
- สังเกตว่า ขนาดของ(*ptr) ถูกใช้แทน ขนาดของ(int) เพื่อให้โค้ดมีความแข็งแกร่งมากขึ้นเมื่อคำประกาศ *ptr ถูกแปลงชนิดข้อมูลเป็นชนิดข้อมูลอื่นในภายหลัง
- การจัดสรรอาจล้มเหลวหากหน่วยความจำไม่เพียงพอ ในกรณีนี้จะส่งกลับตัวชี้ NULL ดังนั้นคุณควรรวมโค้ดเพื่อตรวจสอบตัวชี้ NULL
- โปรดจำไว้ว่าหน่วยความจำที่จัดสรรนั้นต่อเนื่องกันและสามารถถือเป็นอาร์เรย์ได้ เราสามารถใช้เลขคณิตตัวชี้เพื่อเข้าถึงองค์ประกอบของอาร์เรย์แทนที่จะใช้เครื่องหมายวงเล็บ [ ] เราแนะนำให้ใช้ + เพื่ออ้างถึงองค์ประกอบของอาร์เรย์ เนื่องจากการใช้การเพิ่มค่า ++ หรือ += จะเปลี่ยนที่อยู่ที่เก็บโดย ตัวชี้.
ฟังก์ชัน Malloc() ยังสามารถใช้ได้กับชนิดข้อมูลอักขระและชนิดข้อมูลที่ซับซ้อน เช่น โครงสร้างอีกด้วย
ฟังก์ชั่น free() ใน C
หน่วยความจำสำหรับ ตัวแปร ถูกจัดสรรคืนโดยอัตโนมัติในเวลารวบรวม ในการจัดสรรหน่วยความจำแบบไดนามิก คุณต้องจัดสรรหน่วยความจำอย่างชัดเจน หากไม่เสร็จสิ้น คุณอาจพบข้อผิดพลาดหน่วยความจำไม่เพียงพอ
ฟรี() ฟังก์ชันนี้ถูกเรียกใช้เพื่อปลดปล่อย/จัดสรรหน่วยความจำใน 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() ยังสามารถใช้เพื่อลดขนาดของหน่วยความจำที่จัดสรรไว้ก่อนหน้านี้ได้
ไวยากรณ์ของฟังก์ชัน 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
สรุป
- เราสามารถจัดการหน่วยความจำแบบไดนามิกโดยการสร้างบล็อกหน่วยความจำตามต้องการในฮีป
- ในการจัดสรรหน่วยความจำแบบไดนามิก C หน่วยความจำจะถูกจัดสรร ณ รันไทม์
- การจัดสรรหน่วยความจำแบบไดนามิกทำให้สามารถจัดการสตริงและอาร์เรย์ที่มีขนาดยืดหยุ่นและสามารถเปลี่ยนแปลงได้ตลอดเวลาในโปรแกรมของคุณ
- จำเป็นเมื่อคุณไม่รู้ว่าโครงสร้างใดจะใช้หน่วยความจำจำนวนเท่าใด
- Malloc() ใน C เป็นฟังก์ชันการจัดสรรหน่วยความจำแบบไดนามิกซึ่งย่อมาจากการจัดสรรหน่วยความจำที่บล็อกหน่วยความจำที่มีขนาดเฉพาะซึ่งเริ่มต้นเป็นค่าขยะ
- Calloc() ใน C เป็นฟังก์ชันการจัดสรรหน่วยความจำที่อยู่ติดกันซึ่งจัดสรรบล็อกหน่วยความจำหลายบล็อกในแต่ละครั้งซึ่งเริ่มต้นเป็น 0
- Realloc() ในภาษา C ใช้เพื่อจัดสรรหน่วยความจำใหม่ตามขนาดที่ระบุ
- ฟังก์ชัน Free() ใช้เพื่อล้างหน่วยความจำที่จัดสรรแบบไดนามิก