C++: أساسيات المؤشرات

آخر تحديث: 2026-08-26

في الدروس السابقة، كانت المتغيرات مخزنة في موقع ما في الذاكرة.

لكن أين يقع ذلك "الموقع" بالضبط؟ هل يمكنك الوصول إليه مباشرة؟

المؤشرات هي متغيرات تخزن عناوين — تتيح لك التعامل مع الذاكرة مباشرة.



1. ما هو المؤشر؟

(1) 1.1 المؤشرات في الحياة اليومية

تشبيه من الحياة المقابل البرمجي
عنوان منزلك (مثلًا "شارع الرئيسي 123...") مؤشر (يخزن عنوانًا)
منزلك الفعلي (المبنى الذي يشير إليه العنوان) متغير (مساحة الذاكرة التي يشير إليها العنوان)

جوهر المؤشر: متغير يخزن عنوانًا.

(2) 1.2 لماذا نحتاج المؤشرات؟

  1. تخصيص الذاكرة الديناميكي (ستُغطى لاحقًا مع new / delete)
  2. الدوال تحتاج لتعديل متغيرات خارجية (تمرير المؤشرات إلى الدوال)
  3. العمل مع المصفوفات (أسماء المصفوفات هي مؤشرات)
  4. تنفيذ هياكل بيانات معقدة (القوائم المرتبطة، الأشجار، الرسوم البيانية)


2. تعريف المؤشر وتهيئته

(1) 2.1 تعريف مؤشر

الصياغة:

▶ مثال 2: مثال برمجي (صعوبة ⭐)

TEXT 📖 للعرض فقط
Type* pointerName;

الخرج:

TEXT 📖 للعرض فقط
(Program output)

مثال:

CPP
#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 عامل العنوان (&)

& يُستخدم للحصول على عنوان متغير.

TEXT 📖 للعرض فقط
#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;
}

الخرج (مثال):

TEXT 📖 للعرض فقط
x 's value: 5
x 's address: 0x7ffd4a3b

💡 نصيحة: التنسيق المحدد للعناوين يعتمد على النظام والمترجم.


(3) 2.3 تهيئة مؤشر

CPP
#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 عامل التحويل (*)

* يُستخدم للوصول إلى القيمة التي يشير إليها المؤشر.

TEXT 📖 للعرض فقط
#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 تعديل متغير عبر مؤشر

CPP
#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 مؤشر

TEXT 📖 للعرض فقط
#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 بت):

TEXT 📖 للعرض فقط
int* size: 8 bytes
double* size: 8 bytes
char* size: 8 bytes

💡 نقطة مهمة: جميع المؤشرات بنفس الحجم (8 بايت على أنظمة 64 بت، 4 بايت على أنظمة 32 بت) — لأنها جميعها تخزن عناوين.



5. المؤشرات الفارغة (nullptr)

(1) 5.1 ما هو المؤشر الفارغ؟

المؤشر الفارغ هو مؤشر لا يشير إلى أي كائن.

CPP
#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 تحويل مؤشر فارغ يسبب انهيارًا

TEXT 📖 للعرض فقط
#include <iostream>

int main() {
 int* p = nullptr;
 std::cout << *p << std::endl; // ❌ Undefined behavior! May crash
 return 0;
}

نتيجة التشغيل:

CPP
Segmentation fault (core dumped) // Linux

أو

TEXT 📖 للعرض فقط
Process finished with exit code -1073741819 // Windows

⚠️ لا تحوّل مؤشرًا فارغًا أبدًا!



6. المؤشرات كمعلمات دالة

(1) 6.1 المشكلة: الدوال تحتاج لتعديل متغيرات خارجية

CPP
#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 الحل: تمرير مؤشر

TEXT 📖 للعرض فقط
#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: تنفيذ التبديل بالمؤشرات (صعوبة ⭐)

CPP
#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;
}
▶ جرّب الكود

الخرج:

TEXT 📖 للعرض فقط
Before swap: x = 3, y = 5
After swap: x = 5, y = 3

💡 نصيحة: لاحقًا ستتعلم المراجع — تنفيذ التبديل بالمراجع أبسط حتى.



8. الأخطاء الشائعة

(1) 8.1 تحويل مؤشر غير مهيأ

TEXT 📖 للعرض فقط
#include <iostream>

int main() {
 int* p; // ❌ Uninitialized (wild pointer)
 std::cout << *p << std::endl; // ❌ Undefined behavior!
 return 0;
}

الإصلاح: هيّئه إلى nullptr، أو اجعله يشير إلى متغير موجود.


(2) 8.2 عدم تطابق نوع المؤشر

CPP
#include <iostream>

int main() {
 int x = 5;
 double* p = &x; // ❌ Error: int* Cannot point to int
 return 0;
}

رسالة خطأ المترجم:

TEXT 📖 للعرض فقط
error: cannot convert 'int*' to 'double*' in initialization

▶ مثال 3: المؤشرات والمصفوفات (صعوبة ⭐)

CPP
#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;
}
▶ جرّب الكود

الخرج:

TEXT 📖 للعرض فقط
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 للتحويل؛ المراجع تُستخدم باسم المتغير مباشرة

📖 ملخص


📝 تمارين

  1. أساسي (صعوبة ⭐): عرّف متغير int بقيمة x = 10، ثم عرّف مؤشر int* باسم p يشير إلى x. أخرج قيمة x و *p.

  2. متوسط (صعوبة ⭐⭐): اكتب دالة void addTen(int* p) تضيف 10 إلى المتغير الذي يشير إليه المؤشر. اختبرها في main.

  3. تحدي (صعوبة ⭐⭐⭐): اكتب برنامجًا يعرّف ثلاثة متغيرات int هي a, b, c، وثلاثة مؤشرات تشير إلى كل منها. استخدم المؤشرات لتغيير المتغيرات الثلاثة جميعها إلى 100، ثم أخرجها.


9. 🚀 الخطوة التالية

الآن بعد أن تعلمت أساسيات المؤشرات، لنتابع إلى المؤشرات والمصفوفات (الدرس 23) — فهم أن أسماء المصفوفات هي مؤشرات، وحساب المؤشرات.

Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%