التخصيص الديناميكي للذاكرة في لغة سي
28 Jun 2020
بما إن لغة سي لغة هيكلية فإن لها قواعد ثابتة في البرمجة، ومن ذلك تغيير حجم مصفوفة. المصفوفة هي مجموعة من العناصر المخزنة بأماكن متصلة من الذاكرة (اي ليست بأماكن متقطعة - بأماكن مختلفة من الذاكرة).
كما ترى فإن حجم (طول) المصفوفة أعلاه هو 9. وهو ثابت في حالة المصفوفات. ولكن قد نحتاج إلى تغيير هذا الحجم في حالات مثل:
-
في حال كان هناك حاجة لإدخال خمسة عناصر فقط في المصفوفة، في هذه الحالة تكون العناصر الأربعة المتبقية والفارغة هي عبارة عن هدر للذاكرة ونحتاج لتخفيض حجم المصفوفة من 9 إلى 5.
-
في حال كانت جميع العناصر التسعة في المصفوفة ممتلئة وكنا نحتاج لإدخال 3 عناصر إضافيين. في هذه الحالة فإننا نحتاج لتوسيع حجم المصفوفة من 9 إلى 12.
عملية تغيير حجم المصفوفة في لغة سي تدعى “التخصيص الديناميكي للذاكرة” أو بالإنجليزية “Dynamic Memory Allocation” وديناميكي عموما يعني حركي أو متغير أي غير ثابت.
وبالتالي يُعرّف التخصيص الديناميكي للذاكرة على أنه عملية يتم بها تغيير حجم هيكل بيانات (مثل المصفوفة) مع الزمن.
وهناك عدة دالات في لغة سي لتحقيق هذه المهمات. وهي أربع دالات ضمن مكتبة
- ()malloc
- ()calloc
- ()free
- ()realloc
لنلقي نظرة على كل دالة فيهم بشكل أوسع
دالة malloc في لغة سي
وهي اختصار لـ “memory allocation” وتستخدم لتخصيص حجرة واحدة كبيرة من الذاكرة ديناميكيًا وبحجم محدد (هذا يعني أن الحجم الأولي لهذه الحجرة في الذاكرة يكون محددًّا لكنه قابل للتغيير فيما بعد ولهذا نقول عنه ديناميكي).
تقوم هذه الدالة بإرجاع مؤشّر من نوع void والذي يمكن تحويله لمؤشر من أي نوع آخر. كما تقوم بتهيئة كل حجرة بقيمة عشوائية افتراضية.
صيغة الدالة:
ptr = (cast-type*) malloc(byte-size)
مثال
ptr = (int*) malloc(100 * sizeof(int));
حيث أن حجم الـ int هو 4 بايت، وبالتالي ستقوم هذه العبارة بتخصيص 400 بايت في الذاكرة. وسيحمل المؤشر ptr عنوان أول بايت في الحجرة المخصصة.
إذا كانت الذاكرة غير كافية لعملية التخصيص تلك فستفشل العملية وسيتم إرجاع مؤشر NULL.
مثال
النتيجة
Enter number of elements: 5
Memory successfully allocated using malloc.
The elements of the array are: 1, 2, 3, 4, 5,
دالة calloc في لغة سي
وهي اختصار لـ “contiguous allocation” أي تخصيص مستمر (متواصل/متجاور) وتستخدم لتخصيص عدد محدد من الحجرات (blocks) في الذاكرة ومن نوع محدد (رقم صحيح أم عشري أم أحرف) ديناميكيًا. وتقوم بتهيئة كل حجرة بالقيمة الافتراضية 0.
صيغة الدالة:
ptr = (cast-type*)calloc(n, element-size);
مثال
ptr = (float*) calloc(25, sizeof(float));
تقوم هذه العبارة بتخصيص مساحة متواصلة أي متجاورة في الذاكرة لـ 25 عنصر وكل منهم بحجم الـ float (أي 4 بايت).
إذا كانت الذاكرة غير كافية لعملية التخصيص تلك فستفشل العملية وسيتم إرجاع مؤشر NULL.
مثال
النتيجة
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
دالة free في لغة سي
وتستخدم لإلغاء تخصيص الذاكرة ديناميكيًا. فعند تخصيص الذاكرة باستخدام malloc و calloc لا يتم إلغاء تخصيصهم تلقائيًا. لذا فإن هذه الدالة free تستخدم في حالة وجود ذاكرة مخصصة ديناميكيا، وتساعد في تخفيض الهدر أو الإسراف في الذاكرة من خلال إلغاء تخصيصها وجعلها حرة للاستخدام.
صيغة الدالة:
free(ptr);
مثال
النتيجة
Enter number of elements: 5
Memory successfully allocated using malloc.
Malloc Memory successfully freed.
Memory successfully allocated using calloc.
Calloc Memory successfully freed.
أي أنه في هذا المثال قمنا بتخصيص ذاكرة باستخدام malloc ثم تحريرها (إلغاء تخصيصها) باستخدام free ثم تخصيص ذاكرة أخرى باستخدام calloc وتحريرها أيضًا باستخدام free.
دالة realloc في لغة سي
أي “re-allocaion” وتعني إعادة تخصيص وتستخدم لتغيير تخصيص ذاكرة تم تخصيصها من قبل ديناميكيًا. فمثلًا إذا كانت الذاكرة التي تم تخصيصها من قبل باستخدام malloc و calloc لم تعد كافية (احتجنا لإضافة عناصر جديدة وبالتالي توسيعها) فيتم استخدام realloc لإعادة تخصيص الذاكرة ديناميكيًا.
تحافظ إعادة التخصيص هذه على الذاكرة الموجودة أصلا وقيمها وتقوم بتهئية الحجرات الجديدة بقيمة افتراضية عشوائية.
صيغة الدالة:
ptr = realloc(ptr, newSize);
حيث يتم إعادة تخصيص ptr وفق الحجم الجديد “newSize”.
إذا كانت الذاكرة غير كافية لعملية التخصيص تلك فستفشل العملية وسيتم إرجاع مؤشر NULL.
مثال
النتيجة
Enter number of elements: 5
Memory successfully allocated using calloc.
The elements of the array are: 1, 2, 3, 4, 5,
Enter the new size of the array: 10
Memory successfully re-allocated using realloc.
The elements of the array are: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
سؤال متعلق بالموضوع
ماهو الفرق بين ()malloc و ()calloc وما هي الدالة في لغة سي التي يجب أن نستخدمها بعد استخدام ()malloc لنصل لنفس وظيفة ()calloc؟
للإجابة على الشق الأول من السؤال يرجى قراءة المقال:الفرق بين calloc و malloc بالأمثلة
أما بالنسبة للدالة التي تحقق نفس وظيفة ()calloc بعد استخدام ()malloc فهي ()memset وذلك لتهيئة العناصر بالقيمة الأولية صفر كما تفعل ()calloc. للمزيد يمكنك قراءة المقال التالي عن memset هنا
يرجى مراسلتي في حال وجود أي استفسار أو إضافة.
هذا المقال مترجم وبتصرّف، المصدر