فصل ۹: اشارهگرها (Pointers) — مقدمات، عملیات، و خطرات
۱. مقدمه: چرا اشارهگرها؟
در C++، متغیرها دادههای ما را در خانههای حافظه ذخیره میکنند، اما گاهی لازم است:
- به جای مقدار داده، مستقیماً آدرس آن در حافظه را ذخیره یا منتقل کنیم.
- بتوانیم به طور غیر مستقیم به دادهها دسترسی داشته باشیم.
- حافظه پویا (dynamic memory) مدیریت کنیم.
- ساختارهایی مثل آرایهها، رشتهها و کلاسها را بهینه منتقل کنیم.
اینجاست که Pointer (اشارهگر) به کار میآید:
تعریف ساده: اشارهگر متغیری است که آدرس یک متغیر دیگر را ذخیره میکند.
۲. مفاهیم اولیه
آدرس (Address) در حافظه چیست؟
هر خانهٔ حافظه یک شماره دارد، این شماره را آدرس مینامیم.
- در C++ میتوانیم آدرس یک متغیر را با عملگر
&
بگیریم.
مثال:
#include <iostream>
using namespace std;
int main() {
int x = 10;
cout << "Value of x: " << x << endl;
cout << "Address of x: " << &x << endl;
}
خروجی نمونه:
Value of x: 10
Address of x: 0x61ff14
(آدرس در هر اجرا ممکن است فرق کند.)
۳. تعریف اشارهگر
ساختار کلی:
نوع_داده *نام_اشارهگر;
نوع_داده نوع متغیری است که اشارهگر باید به آن اشاره کند.
مثال:
int *ptr;
یعنی ptr
یک اشارهگر به متغیرهای int
است.
۴. مقداردهی به اشارهگر
برای این کار، به آدرس یک متغیر نیاز داریم:
int x = 10;
int *ptr = &x; // ptr = آدرس x
۵. دسترسی به مقدار از طریق اشارهگر (Dereferencing)
برای رفتن به “خانه” و گرفتن مقدار ذخیرهشده، از *
قبل از اشارهگر استفاده میکنیم.
مثال:
#include <iostream>
using namespace std;
int main() {
int x = 5;
int *ptr = &x;
cout << "Pointer stores address: " << ptr << endl;
cout << "Value at that address: " << *ptr << endl;
*ptr = 20; // تغییر مقدار x از طریق اشارهگر
cout << "New value of x: " << x << endl;
}
۶. اشارهگر و تغییر متغیرها
اشارهگرها میتوانند متغیرها را مستقیماً تغییر بدهند:
void changeValue(int *p) {
*p = 100;
}
int main() {
int num = 5;
changeValue(&num);
cout << num; // نتیجه: 100
}
۷. اشارهگر و انواع داده
اشارهگر باید نوع درست را داشته باشد:
int*
→ به اعداد صحیحdouble*
→ به اعداد اعشاریchar*
→ به کاراکتر یا رشته C-Style
اشارهگر با نوع متفاوت ممکن است خطا یا رفتار نامشخص ایجاد کند.
۸. اشارهگر و آرایهها
نام آرایه در C++ معمولاً به آدرس اولین عنصر تبدیل میشود:
int arr[3] = {10, 20, 30};
int *p = arr;
cout << *p << endl; // 10
cout << *(p + 1) << endl; // 20
p + 1
به خانه بعدی میرود.
۹. اشارهگرها و عملگرهای حسابی
اشارهگرها میتوانند با عملگرهای:
+
و-
برای جابهجایی بین عناصر آرایه- مقایسه (
==
,<
,>
) استفاده شوند (در آرایه)
مثال:
for (int *ptr = arr; ptr < arr + 3; ptr++) {
cout << *ptr << endl;
}
۱۰. اشارهگرها به اشارهگر (Pointer to Pointer)
ممکن است اشارهگری داشته باشیم که خودش آدرس یک اشارهگر دیگر را نگه دارد.
مثال:
int x = 5;
int *p = &x;
int **pp = &p;
cout << **pp; // نتیجه: 5
۱۱. اشارهگر NULL و nullptr
اشارهگری که به هیچ آدرسی اشاره نکند:
int *p = nullptr; // امنتر از NULL
قبل از استفاده حتماً بررسی خالی بودن:
if (p != nullptr) { ... }
۱۲. خطرات اشارهگرها
- Dangling Pointer: اشارهگر به آدرسی که دیگر معتبر نیست.
- Memory Leak: فراموش کردن آزاد کردن حافظه پویا.
- Wild Pointer: استفاده از اشارهگر قبل از مقداردهی.
۱۳. مثال عملی: جابهجایی دو عدد با اشارهگر
void swapNumbers(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 5, y = 10;
swapNumbers(&x, &y);
cout << x << " " << y; // 10 5
}
۱۴. مثال پیشرفته: پیمایش آرایه با اشارهگر
int arr[] = {1, 2, 3, 4, 5};
for (int *p = arr; p < arr + 5; p++) {
cout << *p << " ";
}
۱۵. تمرینها
- برنامهای که یک عدد از کاربر بگیرد، آدرس آن را چاپ کند، مقدارش را از طریق اشارهگر تغییر دهد.
- برنامهای که یک آرایه بگیرد و با اشارهگر همه عناصر را دوبرابر کند.
- برنامهای که با اشارهگر دو عدد را جابهجا کند (بدون متغیر سوم).
- برنامهای که با اشارهگر طول یک رشته C-Style را محاسبه کند.
۱۶. جمعبندی
- اشارهگر ابزار بسیار قدرتمندی است ولی باید با احتیاط استفاده شود.
- مهمترین نکات: مقداردهی اولیه، بررسی
nullptr
، رعایت نوعداده. - در فصول بعد، اشارهگرها را در حافظه پویا و اشارهگرهای هوشمند ادامه میدهیم.