المصفوفات الديناميكية (Dynamic Arrays) — إدارة الذاكرة في C++ باستخدام new و delete

في الدروس السابقة تعلمت المصفوفات العادية (Static Arrays) مثل:

int arr[10];

هذه المصفوفات مفيدة…
لكن عندها أكبر مشكلة في تاريخ البرمجة:

عدد عناصرها يجب أن يكون ثابت وقت الترجمة (Compile-Time)
لا تستطيع تغيير حجمها أثناء التشغيل
تستخدم الـ Stack — مساحة صغيرة جدًا مقارنة بالـ Heap

ولأن C++ لغة منخفضة المستوى…
فهي تعطيك قوة كاملة للتحكم بالذاكرة باستخدام الذاكرة الديناميكية (Dynamic Memory).

وهذا بالضبط موضوع هذا الدرس 🔥


🎯 ما هي المصفوفات الديناميكية؟

هي مصفوفات يتم إنشاؤها أثناء تشغيل البرنامج (Runtime)
وليس أثناء الترجمة.

تُخزّن في منطقة Heap بدلاً من Stack.

بمعنى آخر:
أنت الذي تحدد حجمها وقت التشغيل، سواء من المستخدم، أو من بيانات خارجية.


🧩 الصيغة الأساسية للذاكرة الديناميكية

🔸 إنشاء متغير بشكل ديناميكي

int* p = new int;

🔸 إنشاء مصفوفة ديناميكية

int* arr = new int[size];

هذا السطر يحجز size عنصر في الذاكرة Heap.


لماذا نستخدم Dynamic Arrays؟

  1. ✔ حجمها يُحدد أثناء تشغيل البرنامج
  2. ✔ يمكن تغيير حجمها (بعمليات خاصة)
  3. ✔ مناسبة للبيانات الكبيرة
  4. ✔ ضرورية للـ Data Structures المتقدمة مثل:
    • Linked List
    • Dynamic Vector
    • Binary Trees
    • Graphs
  5. ✔ لأن المكتبات القياسية STL كلها مبنية على الذاكرة الديناميكية

🚀 أولًا: استخدام new لإنشاء مصفوفة ديناميكية

📘 مثال أساسي:

#include <iostream>
using namespace std;

int main() {
    int n;
    cout << "أدخل حجم المصفوفة: ";
    cin >> n;

    int* arr = new int[n]; // إنشاء مصفوفة ديناميكية

    for(int i = 0; i < n; i++) {
        cin >> arr[i];
    }

    cout << "العناصر المدخلة: ";
    for(int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    delete[] arr; // تحرير الذاكرة
}

🔍 شرح مهم جدًا:

🔸 new int[n]

  • ينشئ مصفوفة ديناميكية حجمها n
  • يخزنها في Heap
  • يعيد مؤشر لأول عنصر
  • المتغير arr هو pointer وليس array حقيقية

🔸 delete[] arr

يحذف المصفوفة الديناميكية كاملة من الذاكرة.

💥 إذا نسيت delete → صار عندك Memory leak
يعني ذاكرة محجوزة لكن غير مستخدمة.


🧠 ثانيًا: الفرق بين Stack و Heap

الخاصيةStackHeap
مكان المصفوفةداخل إطار الدالةخارج الدالة
الحجمصغيركبير جدًا
سرعة الوصولسريعأبطأ
التحكمتلقائييدوي باستخدام new/delete
غض الطرف يؤديخطأ compile/runtimememory leak

🧱 ثالثًا: مثال عملي كبير — بناء مصفوفة ديناميكية وتعديلها

#include <iostream>
using namespace std;

int main() {
    int n;
    cout << "أدخل حجم المصفوفة: ";
    cin >> n;

    int* arr = new int[n];

    for (int i = 0; i < n; i++) {
        arr[i] = i * 2;
    }

    cout << "محتوى المصفوفة: ";
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }

    delete[] arr;
}

🎯 رابعًا: تعديل حجم المصفوفة الديناميكية (Dynamic Resize)

C++ لا تملك دالة جاهزة مثل realloc() في C،
لكن يمكنك زيادة حجم المصفوفة يدويًا:

📘 الطريقة:

  1. إنشاء مصفوفة جديدة بالحجم الجديد
  2. نقل البيانات إليها
  3. حذف القديمة

📦 مثال: زيادة حجم المصفوفة من n إلى n+5

int* resizeArray(int* arr, int oldSize, int newSize) {
    int* newArr = new int[newSize];

    for (int i = 0; i < oldSize; i++) {
        newArr[i] = arr[i];
    }

    delete[] arr;

    return newArr;
}

خامسًا: المصفوفات الديناميكية متعددة الأبعاد

🎯 مصفوفة 2D ديناميكية:

int** arr = new int*[rows];

for(int i = 0; i < rows; i++) {
    arr[i] = new int[cols];
}

📘 وطبعًا لا تنسى حذفها:

for(int i = 0; i < rows; i++) {
    delete[] arr[i];
}
delete[] arr;

🧩 سادسًا: new vs malloc (مهم جدًا)

المقارنةnewmalloc
اللغةC++C
تعيد النوع الصحيح؟نعملا، void*
تستدعي constructor؟
تستخدم مع delete
سهلة الاستخدام

🔥 سابعًا: أخطاء الذاكرة الشائعة — والحلول

1️⃣ نسيان delete

❌ خطير جدًا → Memory Leak
✔ الحل: استخدم دائمًا delete بعد new


2️⃣ استخدام delete بدون new

int x;
delete &x;  // كارثة

📛 هذا يدمر الذاكرة.


3️⃣ استخدام delete بدلاً من delete[]

❌ خطأ شائع جدًا

int* arr = new int[10];
delete arr; // خطأ

✔ يجب:

delete[] arr;

🧠 ثامنًا: dynamic arrays vs vector

الميزةdynamic arrayvector
سرعةأسرع قليلًاقريب جدًا
سهولة الاستخدامصعبسهل جدًا
تغيير الحجميدويتلقائي
أمانأقلأعلى
حذف الذاكرةيدويتلقائي

💬 نصيحتي كمبرمج محترف:
استخدم vector دائمًا…
واستخدم new فقط لو كنت تبني نظام كبير جدًا أو embedded أو memory-oriented.


🧪 تاسعًا: مثال مشروع صغير كامل — حساب القيم باستخدام المصفوفات الديناميكية

#include <iostream>
using namespace std;

int main() {
    int n;
    cout << "أدخل عدد الطلاب: ";
    cin >> n;

    double* grades = new double[n];

    for (int i = 0; i < n; i++) {
        cout << "أدخل علامة الطالب " << i+1 << ": ";
        cin >> grades[i];
    }

    double sum = 0;
    for (int i = 0; i < n; i++) {
        sum += grades[i];
    }

    cout << "المعدل: " << (sum / n) << endl;

    delete[] grades;
}

🌍 روابط خارجية موثوقة

🔗 cppreference – new/delete
https://en.cppreference.com/w/cpp/language/new


🎯 الخلاصة النهائية

المصفوفات الديناميكية هي:

✔ أساس مفهوم إدارة الذاكرة
✔ تستخدم new و delete للتحكم الكامل
✔ تخزّن على Heap
✔ يمكن تغيير حجمها
✔ هي الأساس لكل تراكيب البيانات الكبيرة (Vector, Map, Graph, Trees)
✔ تعطيك قوة ومرونة لا تملكها لغات كثيرة

إذا فهمت هذا الدرس صح…
فأنت الآن قادر تتعامل مع الذاكرة في C++ مثل المحترفين.


اكتشاف المزيد من كود التطور

اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.

اترك رد

Scroll to Top