المؤشرات والمصفوفات — المؤشرات والذاكرة
المؤشرات والمصفوفات
اسم المصفوفة يتحول إلى مؤشر
int nums[4] = {10, 20, 30, 40};
int* p = nums; // مثل &nums[0]
cout << *p; // 10في معظم التعابير يتحول اسم المصفوفة إلى مؤشر لأول عنصر. لهذا عند تمرير مصفوفة لدالة تستلم مؤشراً وتفقد معرفة حجمها.
حساب المؤشرات (Pointer Arithmetic)
p + 1 لا تعني العنوان التالي بايتاً، بل العنصر التالي: يتقدم بمقدار sizeof(int).
int arr[] = {10, 20, 30};
int* p = arr;
cout << *(p + 2) << '\n'; // 30
cout << p[2] << '\n'; // 30 — الصيغتان متطابقتان حرفياً
p++; // يشير الآن لـ 20arr[i] هي في الحقيقة اختصار لـ *(arr + i).
المرور بالمؤشرات
for (int* it = nums; it != nums + 4; ++it) {
cout << *it;
}nums + 4 يشير "بعد آخر عنصر": مسموح أن تحسبه وتقارن به، غير مسموح أن تقرأ منه. هذا هو أساس فكرة begin() و end() في المكتبة القياسية.
sizeof والمصفوفات
داخل نفس النطاق sizeof(nums) / sizeof(nums[0]) يعطي عدد العناصر. لكن داخل دالة استلمت int* arr فإن sizeof(arr) حجم المؤشر فقط (8 بايت عادة)! لذلك يُمرَّر الحجم دائماً مع المصفوفة.
النصوص بأسلوب C
const char* name = "Ali"; مصفوفة أحرف تنتهي بالحرف '\0'. ستراها في الكود القديم ومكتبات C. في الكود الجديد استخدم std::string.
⚠️ تجاوز الحدود
حساب مؤشر يخرج من المصفوفة ثم القراءة منه سلوك غير معرّف، تماماً كفهرس خارج الحدود.
البديل الحديث
std::vector و std::span (C++20) يحملان المؤشر والحجم معاً، فيحلان مشكلة فقدان الحجم.
تمرين
اكتب int sumArray(const int* arr, int size) تمر على العناصر بمؤشر متحرك (بدون أقواس [ ])، و void reverse(int* arr, int size) تعكس المصفوفة بمؤشرين من الطرفين.
#include <iostream>
using namespace std;
// دالة تستقبل مصفوفة (تتحول لمؤشر)
void printArray(int* arr, int size) {
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
}
// المرور باستخدام مؤشر
void printWithPointer(int* start, int* end) {
while (start != end) {
cout << *start << " ";
start++;
}
cout << endl;
}
int main() {
int arr[] = {10, 20, 30, 40, 50};
int size = 5;
// اسم المصفوفة = مؤشر للعنصر الأول
cout << "arr = " << arr << endl;
cout << "&arr[0] = " << &arr[0] << endl;
cout << "نفس العنوان! ✓" << endl;
// الوصول بعدة طرق
cout << "\n=== طرق الوصول ===" << endl;
cout << "arr[0] = " << arr[0] << endl;
cout << "*arr = " << *arr << endl;
cout << "*(arr+0) = " << *(arr+0) << endl;
cout << "arr[2] = " << arr[2] << endl;
cout << "*(arr+2) = " << *(arr+2) << endl;
// Pointer Arithmetic
cout << "\n=== Pointer Arithmetic ===" << endl;
int* ptr = arr;
cout << "*ptr = " << *ptr << endl; // 10
cout << "*(ptr+1) = " << *(ptr+1) << endl; // 20
cout << "*(ptr+2) = " << *(ptr+2) << endl; // 30
ptr++; // يتحرك بحجم int (4 bytes)
cout << "بعد ptr++: *ptr = " << *ptr << endl; // 20
ptr += 2;
cout << "بعد ptr+=2: *ptr = " << *ptr << endl; // 40
// المسافة بين مؤشرين
int* start = arr;
int* end = arr + 4;
cout << "\nالمسافة: " << (end - start) << " عناصر" << endl;
// المرور على المصفوفة
cout << "\n=== المرور ===" << endl;
cout << "بالفهرس: ";
for (int i = 0; i < size; i++) {
cout << arr[i] << " ";
}
cout << endl;
cout << "بالمؤشر: ";
for (int* p = arr; p < arr + size; p++) {
cout << *p << " ";
}
cout << endl;
// استخدام الدوال
cout << "\nباستخدام دالة: ";
printArray(arr, size);
cout << "بمؤشري البداية والنهاية: ";
printWithPointer(arr, arr + size);
return 0;
}اختبر فهمك