تخصيص الذاكرة الديناميكية في لغة C باستخدام وظائف malloc() و calloc()
قبل أن تتعلم تخصيص الذاكرة الديناميكية بلغة C، دعونا نفهم:
كيف تعمل إدارة الذاكرة في لغة C؟
عندما تعلن عن متغير باستخدام نوع بيانات أساسي، يقوم مترجم C تلقائيًا بتخصيص مساحة الذاكرة للمتغير في مجموعة من الذاكرة تسمى كومة.
على سبيل المثال، يستغرق المتغير العائم عادة 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 الكومة.
ال تحتوي المكتبة على وظائف مسؤولة عن إدارة الذاكرة الديناميكية.
الوظيفة | الهدف |
---|---|
مالوك () | يخصص الذاكرة بالحجم المطلوب ويعيد المؤشر إلى البايت الأول المساحة المخصصة. |
calloc () | يخصص المساحة لعناصر المصفوفة. تهيئة العناصر إلى الصفر وإرجاع المؤشر إلى الذاكرة. |
realloc () | يتم استخدامه لتعديل حجم مساحة الذاكرة المخصصة مسبقًا. |
حر() | يحرر أو يفرغ مساحة الذاكرة المخصصة مسبقًا. |
دعونا نناقش الوظائف المذكورة أعلاه مع تطبيقها
وظيفة malloc () في C
تشير الدالة C malloc() إلى تخصيص الذاكرة. إنها وظيفة تُستخدم لتخصيص كتلة من الذاكرة ديناميكيًا. يقوم بحجز مساحة ذاكرة بالحجم المحدد ويعيد المؤشر الفارغ الذي يشير إلى موقع الذاكرة. المؤشر الذي تم إرجاعه عادة ما يكون من النوع الفارغ. هذا يعني أنه يمكننا تعيين وظيفة 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)); } }
الإخراج:
Value of the 6th integer is 480
- لاحظ أن حجم(*ptr) تم استخدامه بدلاً من حجم(كثافة العمليات) من أجل جعل الكود أكثر قوة عندما يتم تحويل إعلان *ptr إلى نوع بيانات مختلف لاحقًا.
- قد يفشل التخصيص إذا كانت الذاكرة غير كافية. في هذه الحالة، تقوم بإرجاع مؤشر NULL. لذا، يجب عليك تضمين رمز للتحقق من وجود مؤشر NULL.
- ضع في اعتبارك أن الذاكرة المخصصة متجاورة ويمكن التعامل معها كمصفوفة. يمكننا استخدام حساب المؤشر للوصول إلى عناصر المصفوفة بدلاً من استخدام الأقواس [ ]. ننصح باستخدام + للإشارة إلى عناصر المصفوفة لأن استخدام الزيادة ++ أو += يغير العنوان المخزن بواسطة مؤشر.
يمكن أيضًا استخدام دالة Malloc() مع نوع بيانات الحرف بالإضافة إلى أنواع البيانات المعقدة مثل الهياكل.
وظيفة مجانية () في 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); }
الإخراج:
Value of the 2nd integer is 50
وظيفة calloc() في C
تشير دالة C calloc() إلى التخصيص المتجاور. تُستخدم هذه الدالة لتخصيص كتل متعددة من الذاكرة. إنها دالة تخصيص ذاكرة ديناميكية تُستخدم لتخصيص الذاكرة لهياكل البيانات المعقدة مثل المصفوفات والهياكل.
يتم استخدام وظيفة Malloc() لتخصيص كتلة واحدة من مساحة الذاكرة بينما يتم استخدام calloc() في لغة C لتخصيص كتل متعددة من مساحة الذاكرة. كل كتلة مخصصة بواسطة الدالة calloc() لها نفس الحجم.
بناء جملة وظيفة calloc():
ptr = (cast_type *) calloc (n, size);
- يتم استخدام العبارة أعلاه لتخصيص كتل الذاكرة n من نفس الحجم.
- بعد تخصيص مساحة الذاكرة، تتم تهيئة كافة البايتات إلى الصفر.
- يتم إرجاع المؤشر الموجود حاليًا عند البايت الأول من مساحة الذاكرة المخصصة.
عندما يكون هناك خطأ في تخصيص مساحة الذاكرة مثل نقص الذاكرة، يتم إرجاع مؤشر فارغ.
مثال على 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() vs. malloc(): الاختلافات الرئيسية
فيما يلي الفرق الرئيسي بين مالوك () مقابل كالوك () في C:
تعتبر دالة calloc() أكثر ملاءمة وكفاءة بشكل عام من دالة malloc(). وبينما تُستخدم كلتا الدالتين لتخصيص مساحة الذاكرة، يمكن لدالة calloc() تخصيص كتل متعددة في وقت واحد. ولا يتعين عليك طلب كتلة ذاكرة في كل مرة. تُستخدم دالة calloc() في هياكل البيانات المعقدة التي تتطلب مساحة ذاكرة أكبر.
تتم دائمًا تهيئة كتلة الذاكرة المخصصة بواسطة calloc() في C إلى الصفر بينما في الدالة malloc() في C، فإنها تحتوي دائمًا على قيمة غير صحيحة.
وظيفة realloc() في C
باستخدام C realloc () وظيفة، يمكنك إضافة المزيد من حجم الذاكرة إلى الذاكرة المخصصة بالفعل. يقوم بتوسيع الكتلة الحالية مع ترك المحتوى الأصلي كما هو. Realloc() في لغة C تعني إعادة تخصيص الذاكرة.
يمكن أيضًا استخدام realloc() لتقليل حجم الذاكرة المخصصة مسبقًا.
بناء جملة وظيفة realloc():
ptr = realloc (ptr,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 على الشاشة:
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() لمسح الذاكرة المخصصة ديناميكيًا.