C++: أساسيات المؤشرات
آخر تحديث: 2026-08-26
في الدروس السابقة، كانت المتغيرات مخزنة في موقع ما في الذاكرة.
لكن أين يقع ذلك "الموقع" بالضبط؟ هل يمكنك الوصول إليه مباشرة؟
المؤشرات هي متغيرات تخزن عناوين — تتيح لك التعامل مع الذاكرة مباشرة.
1. ما هو المؤشر؟
(1) 1.1 المؤشرات في الحياة اليومية
| تشبيه من الحياة | المقابل البرمجي |
|---|---|
| عنوان منزلك (مثلًا "شارع الرئيسي 123...") | مؤشر (يخزن عنوانًا) |
| منزلك الفعلي (المبنى الذي يشير إليه العنوان) | متغير (مساحة الذاكرة التي يشير إليها العنوان) |
جوهر المؤشر: متغير يخزن عنوانًا.
(2) 1.2 لماذا نحتاج المؤشرات؟
- تخصيص الذاكرة الديناميكي (ستُغطى لاحقًا مع
new/delete) - الدوال تحتاج لتعديل متغيرات خارجية (تمرير المؤشرات إلى الدوال)
- العمل مع المصفوفات (أسماء المصفوفات هي مؤشرات)
- تنفيذ هياكل بيانات معقدة (القوائم المرتبطة، الأشجار، الرسوم البيانية)
2. تعريف المؤشر وتهيئته
(1) 2.1 تعريف مؤشر
الصياغة:
▶ مثال 2: مثال برمجي (صعوبة ⭐)
Type* pointerName;
الخرج:
(Program output)
مثال:
#include <iostream>
int main() {
int* pInt; // pointer to int
double* pDouble; // pointer to double
char* pChar; // pointer to char
return 0;
}
💡 نقطة مهمة: Type* تعني "مؤشر إلى ذلك النوع."
(2) 2.2 عامل العنوان (&)
& يُستخدم للحصول على عنوان متغير.
#include <iostream>
int main() {
int x = 5;
std::cout << "x 's value: " << x << std::endl;
std::cout << "x 's address: " << &x << std::endl; // Output similar to 0x7ffd4a3b
return 0;
}
الخرج (مثال):
x 's value: 5
x 's address: 0x7ffd4a3b
💡 نصيحة: التنسيق المحدد للعناوين يعتمد على النظام والمترجم.
(3) 2.3 تهيئة مؤشر
#include <iostream>
int main() {
int x = 5;
int* p = &x; // p points to x(p stores x's address)
std::cout << "x 's address: " << &x << std::endl;
std::cout << "p 's value: " << p << std::endl; // same as &x
return 0;
}
3. التحويل (الوصول غير المباشر)
(1) 3.1 عامل التحويل (*)
* يُستخدم للوصول إلى القيمة التي يشير إليها المؤشر.
#include <iostream>
int main() {
int x = 5;
int* p = &x; // p points to x
std::cout << "x = " << x << std::endl; // 5
std::cout << "*p = " << *p << std::endl; // 5(Dereference)
return 0;
}
💡 نقطة مهمة: *p هي في الجوهر x!
(2) 3.2 تعديل متغير عبر مؤشر
#include <iostream>
int main() {
int x = 5;
int* p = &x;
std::cout << "Before: x = " << x << std::endl; // 5
*p = 100; // Modify x's value via pointer
std::cout << "After: x = " << x << std::endl; // 100
return 0;
}
4. حجم المؤشرات
(1) 4.1 sizeof مؤشر
#include <iostream>
int main() {
int* pInt;
double* pDouble;
char* pChar;
std::cout << "int* size: " << sizeof(pInt) << " bytes" << std::endl;
std::cout << "double* size: " << sizeof(pDouble) << " bytes" << std::endl;
std::cout << "char* size: " << sizeof(pChar) << " bytes" << std::endl;
return 0;
}
الخرج (نظام 64 بت):
int* size: 8 bytes
double* size: 8 bytes
char* size: 8 bytes
💡 نقطة مهمة: جميع المؤشرات بنفس الحجم (8 بايت على أنظمة 64 بت، 4 بايت على أنظمة 32 بت) — لأنها جميعها تخزن عناوين.
5. المؤشرات الفارغة (nullptr)
(1) 5.1 ما هو المؤشر الفارغ؟
المؤشر الفارغ هو مؤشر لا يشير إلى أي كائن.
#include <iostream>
int main() {
int* p = nullptr; // Null pointer (recommended since C++11)
if (p == nullptr) {
std::cout << "p is null pointer" << std::endl;
}
return 0;
}
💡 نصيحة: قبل C++11، كان يُستخدم NULL (وهو في الجوهر 0)، لكن nullptr هو الموصى به الآن.
(2) 5.2 تحويل مؤشر فارغ يسبب انهيارًا
#include <iostream>
int main() {
int* p = nullptr;
std::cout << *p << std::endl; // ❌ Undefined behavior! May crash
return 0;
}
نتيجة التشغيل:
Segmentation fault (core dumped) // Linux
أو
Process finished with exit code -1073741819 // Windows
⚠️ لا تحوّل مؤشرًا فارغًا أبدًا!
6. المؤشرات كمعلمات دالة
(1) 6.1 المشكلة: الدوال تحتاج لتعديل متغيرات خارجية
#include <iostream>
void modifyValue(int x) {
x = 100; // ❌ modifying a copy, does not affect original variable
}
int main() {
int a = 5;
modifyValue(a);
std::cout << "a = " << a << std::endl; // 5(Unchanged)
return 0;
}
(2) 6.2 الحل: تمرير مؤشر
#include <iostream>
void modifyValue(int* p) {
*p = 100; // ✅ modify original variable via pointer
}
int main() {
int a = 5;
modifyValue(&a); // Pass address
std::cout << "a = " << a << std::endl; // 100(Changed!)
return 0;
}
7. تطبيق: تبديل متغيرين
▶ مثال 1: تنفيذ التبديل بالمؤشرات (صعوبة ⭐)
#include <iostream>
void swap(int* a, int* b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main() {
int x = 3, y = 5;
std::cout << "Before swap: x = " << x << ", y = " << y << std::endl;
swap(&x, &y); // Pass address
std::cout << "After swap: x = " << x << ", y = " << y << std::endl;
return 0;
}
الخرج:
Before swap: x = 3, y = 5
After swap: x = 5, y = 3
💡 نصيحة: لاحقًا ستتعلم المراجع — تنفيذ التبديل بالمراجع أبسط حتى.
8. الأخطاء الشائعة
(1) 8.1 تحويل مؤشر غير مهيأ
#include <iostream>
int main() {
int* p; // ❌ Uninitialized (wild pointer)
std::cout << *p << std::endl; // ❌ Undefined behavior!
return 0;
}
الإصلاح: هيّئه إلى nullptr، أو اجعله يشير إلى متغير موجود.
(2) 8.2 عدم تطابق نوع المؤشر
#include <iostream>
int main() {
int x = 5;
double* p = &x; // ❌ Error: int* Cannot point to int
return 0;
}
رسالة خطأ المترجم:
error: cannot convert 'int*' to 'double*' in initialization
▶ مثال 3: المؤشرات والمصفوفات (صعوبة ⭐)
#include <iostream>
int main() {
int arr[] = {10, 20, 30, 40, 50};
int* p = arr; // array name is the first element address
for (int i = 0; i < 5; i++) {
std::cout << "arr[" << i << "] = " << *(p + i) << std::endl;
}
return 0;
}
الخرج:
arr[0] = 10
arr[1] = 20
arr[2] = 30
arr[3] = 40
arr[4] = 50
arr هو عنوان العنصر الأول، مكافئ لـ &arr[0]. عند اجتياز مصفوفة بمؤشر، *(p + i) مكافئ لـ p[i] أو arr[i].
❓ أسئلة شائعة
nullptr؛ المراجع يجب تهيئتها > - المؤشرات يمكن إعادة توجيهها لمتغيرات أخرى؛ المراجع لا يمكن إعادة ربطها بعد الربط > - المؤشرات تحتاج *p للتحويل؛ المراجع تُستخدم باسم المتغير مباشرة📖 ملخص
- المؤشرات هي متغيرات تخزن عناوين
- التعريف:
Type* pointerName; - الحصول على العنوان:
&variableName - التحويل:
*pointerName - المؤشر الفارغ:
nullptr - لا تحوّل مؤشرًا فارغًا أو مؤشرًا بريًا أبدًا
📝 تمارين
-
أساسي (صعوبة ⭐): عرّف متغير
intبقيمةx = 10، ثم عرّف مؤشرint*باسمpيشير إلىx. أخرج قيمةxو*p. -
متوسط (صعوبة ⭐⭐): اكتب دالة
void addTen(int* p)تضيف 10 إلى المتغير الذي يشير إليه المؤشر. اختبرها فيmain. -
تحدي (صعوبة ⭐⭐⭐): اكتب برنامجًا يعرّف ثلاثة متغيرات
intهيa, b, c، وثلاثة مؤشرات تشير إلى كل منها. استخدم المؤشرات لتغيير المتغيرات الثلاثة جميعها إلى 100، ثم أخرجها.
- المؤشرات هي متغيرات تخزن عناوين الذاكرة
- & تحصل على العنوان، * تحوّل للوصول إلى القيمة المُشار إليها
- التعريف: Type* pointerName (مثلاً، int* p;)
- المؤشر الفارغ nullptr (C++11) يحل محل NULL
- المؤشرات التي تشير إلى نفس الذاكرة — تغيير أحدها يؤثر على الآخر
9. 🚀 الخطوة التالية
الآن بعد أن تعلمت أساسيات المؤشرات، لنتابع إلى المؤشرات والمصفوفات (الدرس 23) — فهم أن أسماء المصفوفات هي مؤشرات، وحساب المؤشرات.