0Pricing
C Academy · درس

تسرّبات الذاكرة

اكتشاف التسربات وتجنبها

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

ما هو تسرّب الذاكرة

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

تبقى الذاكرة محجوزة حتى ينتهي البرنامج، مما يهدر الموارد.

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

int main(void) {
    int *p = malloc(sizeof(int));
    *p = 5;
    printf("%d\n", *p);
    free(p);
    return 0;
}

فقدان المؤشر

يحدث التسرّب التقليدي عند الكتابة فوق مؤشر بتخصيص جديد قبل تحرير التخصيص القديم.

تصبح الكتلة الأولى غير قابلة للوصول.

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

int main(void) {
    int *p = malloc(sizeof(int));
    free(p);
    p = malloc(sizeof(int));
    *p = 10;
    printf("%d\n", *p);
    free(p);
    return 0;
}

التسرّبات في الحلقات

يؤدي التخصيص داخل حلقة دون تحرير الذاكرة في كل تكرار إلى تضاعف التسرّب بسرعة.

والحل هو التحرير قبل أن يستبدل التكرار التالي المؤشر.

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

int main(void) {
    for (int i = 0; i < 3; i++) {
        int *p = malloc(sizeof(int));
        *p = i;
        printf("%d ", *p);
        free(p);
    }
    printf("\n");
    return 0;
}

تؤدي عمليات return المبكرة إلى تسرّب

قد يؤدي تنفيذ return مبكرًا بعد التخصيص إلى تخطي التنظيف. حرّر الذاكرة دائمًا في كل مسار خروج.

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

int process(int bad) {
    int *p = malloc(sizeof(int));
    if (bad) {
        free(p);
        return -1;
    }
    *p = 42;
    int r = *p;
    free(p);
    return r;
}

int main(void) {
    printf("%d\n", process(0));
    return 0;
}

نمط التنظيف باستخدام goto

يضمن وجود تسمية تنظيف واحدة يتم الوصول إليها باستخدام goto أن يكون تحرير كل شيء في موضع واحد، مما يتجنب استدعاءات free المكررة.

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

int main(void) {
    int rc = 1;
    int *p = malloc(sizeof(int));
    if (!p) goto done;
    *p = 7;
    printf("%d\n", *p);
    rc = 0;
done:
    free(p);
    return rc;
}

طابِق كل تخصيص

القاعدة الأبسط: يجب أن يقابل كل من malloc أو calloc أو realloc استدعاء free واحد بالضبط.

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

int main(void) {
    char *a = malloc(8);
    char *b = calloc(4, sizeof(char));
    a[0] = 'x';
    printf("%c %d\n", a[0], b[0]);
    free(a);
    free(b);
    return 0;
}

تحرير التخصيصات المتداخلة

إذا كانت بنية ما تملك ذاكرة في الكومة، فحرّر المؤشرات الداخلية قبل تحرير الكتلة الخارجية.

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

typedef struct {
    int *data;
} Box;

int main(void) {
    Box *b = malloc(sizeof(Box));
    b->data = malloc(3 * sizeof(int));
    b->data[0] = 1;
    printf("%d\n", b->data[0]);
    free(b->data);
    free(b);
    return 0;
}

تحرير مصفوفة من المؤشرات

عند تخصيص مصفوفة من المؤشرات وكان لكل عنصر تخصيصه الخاص، حرّر كل عنصر أولًا، ثم حرّر المصفوفة.

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

int main(void) {
    int n = 3;
    int **rows = malloc(n * sizeof(int *));
    for (int i = 0; i < n; i++) {
        rows[i] = malloc(2 * sizeof(int));
        rows[i][0] = i;
    }
    for (int i = 0; i < n; i++) free(rows[i]);
    free(rows);
    printf("freed all rows\n");
    return 0;
}

انضباط الملكية

حدّد من يملك كل تخصيص ومن يتحمل مسؤولية تحريره. وثّق ذلك حتى يعرف المستدعي ما إذا كان عليه تحرير مؤشر مُعاد.

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

char *make_greeting(void) {
    char *s = malloc(6);
    s[0]='h'; s[1]='i'; s[2]='\0';
    return s;
}

int main(void) {
    char *g = make_greeting();
    printf("%s\n", g);
    free(g);
    return 0;
}

أدوات تكتشف التسرّبات

تُبلغ أدوات مثل Valgrind وAddressSanitizer عن التسرّبات عبر تتبع كل تخصيص وإظهار التخصيصات التي لم تُحرَّر مطلقًا.

وتُعد ضرورية للتحقق من البرامج الفعلية.

دورة حياة تخصيص نظيفة

باختصار: خصّص، وتحقق، واستخدم، وحرّر في كل مسار، واضبط المؤشر على NULL. يحافظ هذا على خلو البرامج من تسرّبات الذاكرة.

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

int main(void) {
    int *p = malloc(4 * sizeof(int));
    if (!p) return 1;
    for (int i = 0; i < 4; i++) p[i] = i + 1;
    int sum = 0;
    for (int i = 0; i < 4; i++) sum += p[i];
    printf("sum = %d\n", sum);
    free(p);
    p = NULL;
    return 0;
}

تحقّق سريع

اختبر فهمك لتسرّبات الذاكرة.

مراجعة

تعلّمت منع تسرّبات الذاكرة:

  • طابِق كل تخصيص مع استدعاء free واحد بالضبط.
  • حرّر الذاكرة في كل مسار خروج، بما في ذلك عمليات الإرجاع المبكرة والأخطاء.
  • حرّر التخصيصات المتداخلة وتخصيصات مصفوفات المؤشرات بدءًا من العناصر الداخلية.
  • حدّد الملكية بوضوح، واستخدم أدوات مثل Valgrind للتحقق.

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

هل درس «تسرّبات الذاكرة» مجاني؟

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

ماذا ستتعلم في «تسرّبات الذاكرة»؟

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

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

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

كم من الوقت يستغرق درس «تسرّبات الذاكرة»؟

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

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

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

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

  1. malloc وfree
  2. calloc وrealloc
  3. تسرّبات الذاكرة
  4. المؤشرات المتدلية
← العودة إلى C Academy