0Pricing
C Academy · درس

التوسعة باستخدام realloc

غيّر حجم مصفوفة ديناميكية

التوسعة باستخدام realloc درس مجاني في C Academy على CoddyKit. هذا هو الدرس 2 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في C Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة C Academy 4 دروس في المجموع.

عندما لا تكفي malloc واحدة

قد تخصصون أحيانًا مصفوفة وتملؤونها، ثم تكتشفون أنكم تحتاجون إلى مساحة أكبر. لا يمكنكم الكتابة بعد نهايتها ببساطة.

تتيح لكم realloc تغيير حجم كتلة موجودة في الكومة، مع الحفاظ على البيانات الموجودة فيها.

توقيع realloc

تتلقى realloc(ptr, new_bytes) المؤشر القديم والحجم الكلي الجديد بالبايت.

وتعيد مؤشرًا إلى كتلة بالحجم الجديد. ويُحافَظ على الجزء الأول من البيانات حتى أصغر الحجمين، القديم والجديد.

int *bigger = realloc(a, new_n * sizeof(*a));

قد تنقل الكتلة

قد توسّع realloc الكتلة في موضعها، أو قد تخصص كتلة جديدة، وتنسخ بياناتكم إليها، ثم تحرر القديمة.

وفي كلتا الحالتين، قد يصبح المؤشر القديم غير صالح. لذلك يجب استخدام المؤشر المُعاد من الآن فصاعدًا.

a = realloc(a, new_n * sizeof(*a));
/* the old value of a may no longer be valid */

فخ الإسناد إلى المتغير نفسه

تبدو كتابة a = realloc(a, ...) مرتبة، لكنها خطيرة: فإذا أعادت realloc القيمة NULL، تكونون قد استبدلتم قيمة a وفقدتم المؤشر الأصلي، مما يؤدي إلى تسريب الكتلة القديمة.

استخدموا متغيرًا مؤقتًا بدلًا من ذلك.

int *tmp = realloc(a, new_n * sizeof(*a));
if (tmp == NULL) { /* a is still valid */ return 1; }
a = tmp;

توسيع مصفوفة بأمان

يخصص هذا البرنامج مساحة لثلاثة أعداد صحيحة، ثم يوسّعها إلى ستة باستخدام realloc، مع الحفاظ على القيم الثلاث الأولى.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = malloc(3 * sizeof(*a));
    if (!a) return 1;
    for (int i = 0; i < 3; i++) a[i] = i + 1;

    int *tmp = realloc(a, 6 * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;

    for (int i = 3; i < 6; i++) a[i] = i + 1;
    for (int i = 0; i < 6; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

البايتات الجديدة غير مهيّأة

عند توسيع كتلة، تحتوي المساحة الإضافية في نهايتها على قيم عشوائية، مثل ذاكرة malloc الجديدة تمامًا.

تحافظ realloc على بياناتكم القديمة، لكنها لا تصفّر المنطقة الجديدة. هيّئوها قبل قراءتها.

a = realloc(a, 6 * sizeof(*a));
for (int i = 3; i < 6; i++) a[i] = 0;  /* clear new slots */

استراتيجية المضاعفة

يُعد استدعاء realloc لكل عنصر على حدة بطيئًا. ومن الحيل الشائعة مضاعفة السعة كلما نفدت المساحة.

يُبقي ذلك عدد عمليات إعادة التخصيص صغيرًا مع نمو المصفوفة، ويوفر أداءً جيدًا في المتوسط.

if (count == cap) {
    cap = cap ? cap * 2 : 4;
    int *tmp = realloc(a, cap * sizeof(*a));
    if (!tmp) { free(a); return 1; }
    a = tmp;
}

بناء مصفوفة باستخدام الإلحاق

يبدأ هذا البرنامج بمصفوفة فارغة، ثم يُلحق بها الأعداد، ويضاعف السعة عند الحاجة.

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int *a = NULL;
    size_t count = 0, cap = 0;
    for (int v = 1; v <= 5; v++) {
        if (count == cap) {
            cap = cap ? cap * 2 : 2;
            int *tmp = realloc(a, cap * sizeof(*a));
            if (!tmp) { free(a); return 1; }
            a = tmp;
        }
        a[count++] = v;
    }
    for (size_t i = 0; i < count; i++) printf("%d\n", a[i]);
    free(a);
    return 0;
}

تعمل realloc(NULL, n) مثل malloc

إذا مررتم NULL كمؤشر، تتصرف realloc تمامًا مثل malloc.

ولهذا ينجح البدء بـ a = NULL في حلقة المضاعفة؛ إذ تخصص أول عملية realloc الكتلة الأولية.

int *a = NULL;
a = realloc(a, 4 * sizeof(*a));  /* same as malloc(4 * sizeof(*a)) */

تقليص كتلة

يمكن لـ realloc أيضًا تصغير الكتلة. ويُحافَظ على البيانات حتى الحجم الجديد، أما الباقي فيُهمل.

قد يؤدي التقليص إلى إعادة الذاكرة إلى النظام، مع أن التطبيقات حرة في الاحتفاظ بالكتلة الأكبر.

int *tmp = realloc(a, 2 * sizeof(*a));  /* down from more */
if (tmp) a = tmp;

تجنّب تجاوز السعة أثناء الحساب

عندما تكبر السعة، قد تؤدي العملية cap * sizeof(*a) إلى تجاوز سعة النوع size_t والالتفاف إلى قيمة صغيرة جدًا.

بالنسبة إلى المصفوفات الضخمة، تحقّق من عملية الضرب، أو استخدم reallocarray في الأنظمة التي توفرها.

if (cap > SIZE_MAX / sizeof(*a)) { /* overflow */ return 1; }
int *tmp = realloc(a, cap * sizeof(*a));

تحقّق سريع

اختبر مدى فهمك للدالة realloc.

مراجعة

تغيّر realloc حجم كتلة في الذاكرة المُدارة، وقد تنقلها؛ لذلك استخدم المؤشر المُعاد دائمًا.

أسند النتيجة إلى متغير مؤقت حتى لا يؤدي فشل العملية إلى فقدان الكتلة الأصلية. ضاعف السعة لتحسين السرعة، وهيّئ الخانات الجديدة، وتذكّر أن realloc(NULL, n) تعادل malloc. بعد ذلك ستضع هذه المنطقية داخل نوع متجه قابل لإعادة الاستخدام.

الأسئلة الشائعة

هل درس «التوسعة باستخدام realloc» مجاني؟

نعم — نص درس «التوسعة باستخدام realloc» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة C Academy، انتقل إلى CoddyKit PRO. تتضمن دورة C Academy 4 دروس في المجموع.

ماذا ستتعلم في «التوسعة باستخدام realloc»؟

غيّر حجم مصفوفة ديناميكية تتمرن على C Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ C Academy؟

لا تُشترط خبرة سابقة. C Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 4.

كم من الوقت يستغرق درس «التوسعة باستخدام realloc»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس C Academy هذا؟

نعم. كل درس في C Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. تخصيص مصفوفة
  2. التوسعة باستخدام realloc
  3. نوع Vector قابل لإعادة الاستخدام
  4. تحرير الذاكرة وتجنّب التسريبات
← العودة إلى C Academy