Kodax

المؤشرات والدوال — المؤشرات والذاكرة

المؤشرات والدوال

تمرير مؤشر لدالة

void addBonus(int* score, int bonus) {
    if (score == nullptr) return;   // افحص دائماً
    *score += bonus;
}

int s = 70;
addBonus(&s, 10);   // نمرر العنوان

النتيجة مثل التمرير بالمرجع int&، لكن مع فرقين:

- المستدعي يكتب &s، فيكون واضحاً في مكان الاستدعاء أن المتغير قد يتغير.

- يمكن تمرير nullptr لتعني "لا يوجد"، فيجب على الدالة الفحص.

متى تختار المؤشر بدل المرجع؟

| استخدم T& | استخدم T* |

|---|---|

| المعامل إلزامي دائماً | المعامل اختياري (قد يكون nullptr) |

| الكود الحديث العادي | واجهات مكتبات C، أو "معامل إخراج اختياري" |

إرجاع مؤشر

int* findFirstNegative(int* arr, int size) {
    for (int i = 0; i < size; i++)
        if (arr[i] < 0) return &arr[i];
    return nullptr;    // لم يوجد
}

إرجاع nullptr طريقة شائعة لقول "لم أجد".

⚠️ لا ترجع عنوان متغير محلي

int* bad() {
    int local = 5;
    return &local;   // local يُدمَّر عند انتهاء الدالة
}

المؤشر الناتج معلّق (dangling): يشير لذاكرة لم تعد صالحة. المترجم يحذر أحياناً فقط. ستفهم السبب بالتفصيل في درس Stack و Heap.

مؤشرات إلى دوال (نظرة)

int (*op)(int, int) = add; مؤشر يحمل عنوان دالة، ويُستدعى op(2, 3). في C++ الحديثة تُستخدم بدلها غالباً std::function أو lambdas (الدورة المتقدمة).

تمرين

اكتب bool divide(int a, int b, int* result) ترجع false عند القسمة على صفر، وتكتب الناتج في *result فقط إذا لم يكن result فارغاً. ثم اكتب نسخة بالمرجع وقارن.

#include <iostream>
using namespace std;

// By Value - لا يغير الأصل
void incrementByValue(int x) {
    x++;
    cout << "داخل الدالة: " << x << endl;
}

// By Pointer - يغير الأصل
void incrementByPointer(int* ptr) {
    (*ptr)++;
    cout << "داخل الدالة: " << *ptr << endl;
}

// By Reference - الأسهل
void incrementByReference(int& ref) {
    ref++;
    cout << "داخل الدالة: " << ref << endl;
}

// تبديل قيمتين باستخدام مؤشرات
void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

// إرجاع عدة قيم
void divideWithRemainder(int dividend, int divisor, 
                         int* quotient, int* remainder) {
    *quotient = dividend / divisor;
    *remainder = dividend % divisor;
}

// إرجاع أكبر عنصر (مؤشر)
int* findMax(int* arr, int size) {
    int* maxPtr = arr;
    for (int i = 1; i < size; i++) {
        if (arr[i] > *maxPtr) {
            maxPtr = &arr[i];
        }
    }
    return maxPtr;
}

int main() {
    int num = 10;
    
    cout << "=== By Value ===" << endl;
    incrementByValue(num);
    cout << "بعد الدالة: " << num << endl;  // 10
    
    cout << "\n=== By Pointer ===" << endl;
    incrementByPointer(&num);
    cout << "بعد الدالة: " << num << endl;  // 11
    
    cout << "\n=== By Reference ===" << endl;
    incrementByReference(num);
    cout << "بعد الدالة: " << num << endl;  // 12
    
    cout << "\n=== Swap ===" << endl;
    int a = 5, b = 10;
    cout << "قبل: a=" << a << ", b=" << b << endl;
    swap(&a, &b);
    cout << "بعد: a=" << a << ", b=" << b << endl;
    
    cout << "\n=== إرجاع عدة قيم ===" << endl;
    int q, r;
    divideWithRemainder(17, 5, &q, &r);
    cout << "17 ÷ 5 = " << q << " والباقي " << r << endl;
    
    cout << "\n=== إرجاع مؤشر ===" << endl;
    int arr[] = {3, 7, 2, 9, 5};
    int* maxPtr = findMax(arr, 5);
    cout << "أكبر عنصر: " << *maxPtr << endl;
    
    return 0;
}
اختبر فهمك