كورس C++ المتوسط – الحلقة الرابعة: الذاكرة الديناميكية (Dynamic Memory) والمؤشرات المتقدمة
#برمجة
مقدمة
مرحباً بك في الحلقة الرابعة من المستوى المتوسط في C++.
في الحلقة السابقة تعلمنا:
- Vector
- STL
- sort
- max_element
- min_element
- Pair
واليوم سندخل إلى أحد أهم المواضيع في C++ والذي يجعلها لغة قوية جداً:
الذاكرة الديناميكية (Dynamic Memory)
وفهم هذا الدرس سيساعدك لاحقاً على تعلم:
- Linked List
- Stack
- Queue
- Trees
- Graphs
- محركات الألعاب
- أنظمة التشغيل
كيف تعمل الذاكرة؟
عندما تكتب:
int x = 10;
يقوم النظام بحجز مساحة في الذاكرة لتخزين الرقم 10.
مثال توضيحي:
Address Value
1000 10
المتغير x يشير إلى هذا المكان.
المشكلة مع الذاكرة العادية
عندما تكتب:
int numbers[100];
فإن النظام يحجز مساحة لـ100 عنصر مباشرة.
حتى لو استخدمت 5 عناصر فقط.
وهذا قد يسبب هدراً في الذاكرة.
ما هي الذاكرة الديناميكية؟
هي ذاكرة يتم حجزها أثناء تشغيل البرنامج حسب الحاجة.
مثال:
إذا احتاج المستخدم 100 عنصر نحجز 100.
إذا احتاج 1000 عنصر نحجز 1000.
الكلمة new
تستخدم لحجز ذاكرة جديدة أثناء التشغيل.
مثال:
int* p = new int;
ماذا حدث هنا؟
- النظام حجز مساحة لعدد صحيح
- أعاد عنوان هذه المساحة
- تم تخزين العنوان داخل المؤشر p
إعطاء قيمة
#include <iostream>
using namespace std;
int main()
{
int* p = new int;
*p = 50;
cout << *p;
return 0;
}
شكل الذاكرة
Pointer p
|
V
Address 2000
Value 50
تحرير الذاكرة
بعد الانتهاء يجب حذف الذاكرة المحجوزة.
نستخدم:
delete p;
مثال كامل
#include <iostream>
using namespace std;
int main()
{
int* p = new int;
*p = 100;
cout << *p << endl;
delete p;
return 0;
}
لماذا delete مهم؟
إذا لم تحذف الذاكرة المحجوزة فقد يحدث:
Memory Leak
أي تسرب للذاكرة.
ما هو Memory Leak؟
عندما يحجز البرنامج ذاكرة ولا يعيدها للنظام.
مثال خاطئ:
int* p = new int;
ثم ينتهي البرنامج أو يتم إنشاء آلاف المؤشرات بدون حذفها.
حجز مصفوفة ديناميكية
int* arr = new int[5];
مثال
#include <iostream>
using namespace std;
int main()
{
int* arr = new int[5];
for(int i = 0; i < 5; i++)
{
arr[i] = i + 1;
}
for(int i = 0; i < 5; i++)
{
cout << arr[i] << endl;
}
delete[] arr;
return 0;
}
الفرق بين delete و delete[]
متغير واحد:
delete p;
مصفوفة:
delete[] arr;
مثال عملي
برنامج يطلب حجم المصفوفة من المستخدم.
#include <iostream>
using namespace std;
int main()
{
int size;
cout << "Enter size: ";
cin >> size;
int* arr = new int[size];
for(int i = 0; i < size; i++)
{
cin >> arr[i];
}
cout << "\nValues:\n";
for(int i = 0; i < size; i++)
{
cout << arr[i] << endl;
}
delete[] arr;
return 0;
}
المؤشرات المتعددة
مؤشر يشير إلى مؤشر.
int x = 10;
int* p = &x;
int** pp = &p;
شرح
pp ---> p ---> x
مثال
#include <iostream>
using namespace std;
int main()
{
int x = 10;
int* p = &x;
int** pp = &p;
cout << **pp;
return 0;
}
الناتج
10
الفرق بين Stack و Heap
Stack
تُخزن فيها المتغيرات العادية.
int x = 5;
Heap
تُخزن فيها البيانات المحجوزة بواسطة new.
int* p = new int;
مقارنة
| Stack | Heap |
|---|---|
| سريع | أبطأ قليلاً |
| تلقائي | يدوي |
| محدود | أكبر حجماً |
| يحذف تلقائياً | يحتاج delete |
مشكلة Dangling Pointer
مثال:
int* p = new int;
delete p;
cout << *p;
هذا خطأ لأن المؤشر يشير إلى ذاكرة تم حذفها.
الحل
delete p;
p = nullptr;
ما هو nullptr؟
يعني أن المؤشر لا يشير إلى أي مكان.
int* p = nullptr;
مشروع عملي
إنشاء قائمة أرقام بحجم يحدده المستخدم
#include <iostream>
using namespace std;
int main()
{
int size;
cout << "How many numbers? ";
cin >> size;
int* numbers = new int[size];
for(int i = 0; i < size; i++)
{
cin >> numbers[i];
}
cout << "\nNumbers:\n";
for(int i = 0; i < size; i++)
{
cout << numbers[i] << endl;
}
delete[] numbers;
return 0;
}
نصيحة مهمة
في C++ الحديثة غالباً نستخدم:
vector<int>
بدلاً من:
new
delete
لأن Vector يدير الذاكرة تلقائياً.
لكن يجب أن تتعلم new و delete لفهم كيفية عمل اللغة داخلياً.
أخطاء شائعة
❌ نسيان delete
❌ استخدام delete بدلاً من delete[]
❌ استخدام مؤشر بعد حذفه
❌ عدم تعيين nullptr بعد الحذف
تمارين
التمرين 1
احجز عدداً صحيحاً باستخدام new واطبعه.
التمرين 2
احجز مصفوفة من 10 عناصر وأدخل قيماً فيها.
التمرين 3
اطلب من المستخدم تحديد حجم المصفوفة.
التمرين 4
جرّب مؤشراً لمؤشر (pointer to pointer).
التمرين 5
اكتب برنامج يحسب مجموع عناصر مصفوفة ديناميكية.
ملخص الحلقة الرابعة
في هذه الحلقة تعلمنا:
- Dynamic Memory
- new
- delete
- delete[]
- Heap
- Stack
- Memory Leak
- Dangling Pointer
- nullptr
- Pointer to Pointer
في الحلقة الخامسة من المستوى المتوسط سنتعلم:
🔥 البرمجة الكائنية المتوسطة (OOP Advanced)
وسندرس:
- Inheritance بشكل احترافي
- Polymorphism
- Virtual Functions
- Abstract Classes
- بناء نظام مستخدمين حقيقي باستخدام OOP
وهذه من أهم المراحل قبل الانتقال إلى المستوى المتقدم. 🚀

تعليقات
إرسال تعليق