فصل ۱۰: حافظه پویا (Dynamic Memory) در C++
۱. مقدمه: حافظه در C++
هر برنامه C++ که روی سیستم شما اجرا میشود، از بخشهای مختلف حافظه استفاده میکند. سه بخش مهم از این حافظه عبارتاند از:
- Stack (پشته) – برای ذخیره متغیرهای محلی.
- Heap (هیپ) – حافظهی پویا که ما خودمان مدیریت میکنیم.
- Static/Data Segment – برای متغیرهای سراسری (global) یا استاتیک.
در حالت معمولی وقتی یک متغیر داخل تابع ایجاد میکنیم:
void func() {
int x = 10; // حافظه روی Stack
}
این متغیر وقتی تابع تمام شود، اتوماتیک از بین میرود.
اما گاهی نیاز داریم حافظهای ایجاد کنیم که:
- اندازهاش در زمان کامپایل مشخص نیست.
- تا زمانی که خودمان بخواهیم باقی بماند.
اینجاست که حافظه پویا وارد عمل میشود.
۲. حافظه پویا چیست؟
به فضایی از Heap گفته میشود که در هنگام اجرای برنامه (Run Time) توسط ما ایجاد و آزاد میشود.
در C++ از دو عملگر مهم برای این کار استفاده میکنیم:
new
→ گرفتن (Allocate) حافظهdelete
→ آزاد کردن (Deallocate) حافظه
۳. استفاده از new
برای متغیر تکی
مثال:
#include <iostream>
using namespace std;
int main() {
int *p = new int; // گرفتن حافظه برای یک int
*p = 42;
cout << "Value: " << *p << endl;
delete p; // آزاد کردن حافظه
p = nullptr; // اشارهگر امن
}
توضیح:
new int
→ حافظه کافی برای یک عدد صحیح میگیرد و آدرسش را برمیگرداند.delete p
→ حافظه این آدرس را آزاد میکند.p = nullptr
→ اشارهگر را خالی میکنیم تا به آدرس نامعتبر اشاره نکند.
۴. استفاده از new
برای آرایه
int *arr = new int[5]; // گرفتن حافظه برای 5 عدد صحیح
for (int i = 0; i < 5; i++)
arr[i] = i + 1;
for (int i = 0; i < 5; i++)
cout << arr[i] << " ";
delete[] arr; // آزاد کردن کل آرایه
arr = nullptr;
نکته: برای آرایهها باید از
delete[]
استفاده کنیم، نهdelete
تکی.
۵. حافظه پویا برای انواع دیگر
double *pd = new double;
*pd = 3.14;
char *name = new char[20]; // رشته سبک C
۶. چرا حافظه پویا مهم است؟
- زمانی که اندازه داده از پیش معلوم نیست.
- کار با دادههای بزرگ که نمیخواهیم در Stack ذخیره شوند.
- ایجاد ساختارهای داده دینامیک (مثل لیست پیوندی، درخت، گراف).
۷. مشکلات و خطرات حافظه پویا
۷.۱. Memory Leak (نشت حافظه)
وقتی حافظهای با new
گرفته ولی با delete
آزاد نشود.
int *p = new int(10);
// هیچ delete p وجود ندارد → حافظه در اختیار سیستم برنمیگردد
۷.۲. Dangling Pointer
وقتی اشارهگر به حافظهای اشاره کند که آزاد شده است.
int *p = new int(5);
delete p;
cout << *p; // خطرناک
۷.۳. Double Delete
اگر یک آدرس را دو بار آزاد کنیم، ممکن است برنامه کرش کند.
delete p;
delete p; // خطرناک
۸. مدیریت درست حافظه
- همیشه بعد از
delete
، اشارهگر را بهnullptr
تنظیم کنید. - به ازای هر
new
باید یکdelete
(و برای هرnew[]
یکdelete[]
) وجود داشته باشد. - از اشارهگرهای هوشمند (در فصل ۱۱ میآید) برای مدیریت اتوماتیک حافظه استفاده کنید.
۹. مثال عملی: آرایه با اندازه ورودی کاربر
#include <iostream>
using namespace std;
int main() {
int n;
cout << "تعداد عناصر: ";
cin >> n;
int *arr = new int[n];
for (int i = 0; i < n; i++) {
cout << "عنصر " << i+1 << ": ";
cin >> arr[i];
}
cout << "آرایه شما: ";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
delete[] arr;
arr = nullptr;
}
۱۰. مثال: ماتریس پویا (۲ بعدی)
int rows, cols;
cin >> rows >> cols;
int **matrix = new int*[rows];
for (int i = 0; i < rows; i++)
matrix[i] = new int[cols];
// استفاده...
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = i + j;
}
}
// نمایش
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << matrix[i][j] << " ";
}
cout << endl;
}
// آزاد کردن
for (int i = 0; i < rows; i++)
delete[] matrix[i];
delete[] matrix;
matrix = nullptr;
۱۱. نکات پیشرفته
- میتوانید هنگام
new
مقدار اولیه دهید:
int *p = new int(100); // مقدار اولیه 100
- استفاده از عملگر
nothrow
برای جلوگیری از پرتاب استثنا:
int *p = new(nothrow) int[1000];
if (!p) {
cout << "حافظه کافی نیست";
}
- برای اشیاء کلاسها،
new
سازنده (constructor) را صدا میزند، وdelete
مخرب (destructor) را.
۱۲. تمرینها
۱. برنامهای که یک آرایه با اندازه دلخواه از کاربر بگیرد، میانگین عناصر را محاسبه کند.
۲. برنامهای که یک ماتریس پویا بسازد و ترانهاده (Transpose) آن را چاپ کند.
۳. برنامهای که اندازه آرایه را کاربر بدهد، مقادیر تصادفی در آن بریزد و بزرگترین مقدار را پیدا کند.
۴. بررسی کنید اگر new
حافظه نداد، پیغام مناسب چاپ شود.
۱۳. جمعبندی
- حافظه پویا برای دادههایی با اندازه متغیر و طول عمر قابل کنترل استفاده میشود.
new
وdelete
ابزارهای اصلی مدیریت در C++ سنتی هستند.- مدیریت اشتباه باعث نشتی حافظه، کرش یا باگهای مخفی میشود.
- در فصل بعد یاد میگیریم چگونه با اشارهگرهای هوشمند این مدیریت را اتوماتیک کنیم.