المؤشر Pointer 2 (المصفوفة، المؤشر وتمرير المؤشر إلى الدالة)
المصفوفات في لغة C++
المصفوفة عبارة عن مجموعة من العناصر من نفس النوع المخزنة في مواقع متجاورة في الذاكرة. في لغة C++، يمكن أن تكون المصفوفات من أنواع بدائية (int، float، إلخ) أو أنواع محددة من قبل المستخدم (structures, classes). المصفوفات لها حجم ثابت، ويمكن الوصول إلى العناصر باستخدام الـindex.
int numbers[5] = {1, 2, 3, 4, 5};
المؤشرات في لغة C++
المؤشر هو متغير يقوم بتخزين عنوان الذاكرة لمتغير آخر. تسمح المؤشرات بتخصيص الذاكرة الديناميكية ومعالجتها. يتم استخدامها غالبًا لإدارة الذاكرة بكفاءة وللوصول إلى العناصر الموجودة في المصفوفات.
int x = 10; int *ptr = &x; // ptr now holds the address of x
المصفوفات والمؤشرات
في العديد من السياقات، تظهر المصفوفات والمؤشرات في لغة C++ سلوكًا مشابهًا. عند استخدام اسم مصفوفة في تعبير، فإنه يتحول إلى مؤشر إلى عنصره الأول. على سبيل المثال:
int arr[3] = {1, 2, 3}; int *ptr = arr; // Equivalent to &arr[0]
ومع ذلك، هناك اختلافات:
- لا يمكن إعادة تعيين متغير المصفوفة للإشارة إلى موقع ذاكرة مختلف، بينما يمكن للمؤشر ذلك.
- تحمل المصفوفات معلومات حول حجمها، في حين أن المؤشرات لا تعرف بطبيعتها حجم الذاكرة التي تشير إليها.
- يمكن استخدام المصفوفات مع عامل التشغيل sizeof لتحديد حجمها، لكن لا يمكن استخدام المؤشرات وحدها.
المؤشر حسابيًا
يمكن زيادة المؤشرات أو إنقاصها للتنقل عبر مصفوفة أو كتلة من الذاكرة.
int arr[5] = {1, 2, 3, 4, 5}; int *ptr = arr; cout << *ptr; // Prints the first element (1) ptr++; // Moves to the next element cout << *ptr; // Prints the second element (2)
مثال 1:
#include <iostream> using namespace std; int main() { int arr[7] = {11,22,33,44,55,66,77}; for (size_t i = 0; i < 7; i++) { cout << *(arr + i) << endl; } return 0; }
يقوم الكود بطباعة عناصر المصفوفة باستخدام المؤشر الحسابي.
cout << *(arr + i) << endl;: يستخدم حساب المؤشر للوصول إلى كل عنصر في المصفوفة. يحسب التعبير arr + i عنوان الذاكرة للعنصر i، ويقوم *(arr + i) بـdereference المؤشر للوصول إلى القيمة المخزنة في هذا العنوان.
المخرجات:
إذا قمت بتشغيل هذا البرنامج، فإن المخرجات ستكون كالتالي:
11 22 33 44 55 66 77
مثال 2:
#include <iostream> using namespace std; int main() { int arr[7] = {11,22,33,44,55,66,77}; int *ptr; ptr = arr; for (size_t i = 0; i < 7; i++) { cout << *ptr << " "; ptr++; } return 0; }
يحقق هذا الكود نفس الهدف كما في المثال السابق ولكنه يستخدم المؤشر (ptr) ومؤشرًا حسابيًا للتكرار عبر المصفوفة.
المخرجات:
إذا قمت بتشغيل هذا البرنامج، فإن المخرجات ستكون كالتالي:
11 22 33 44 55 66 77
تمرير المؤشرات إلى الدوال
عند تمرير مصفوفة إلى دالة، فإنك في الواقع تقوم بتمرير مؤشر إلى العنصر الأول في المصفوفة. ويرجع ذلك إلى تحول المصفوفة إلى مؤشر في arguments الدالة.
مثال 3:
يوضح هذا الكود استخدام المؤشرات والدالة التي تعدل القيمة التي تشير إليها.
#include <iostream> using namespace std; int fun(int *p) { *p = *p + 1; return *p; } int main() { int x = 1; int *ptr = &x; cout << fun(ptr) << endl; cout << x << endl; cout << fun(&x) << endl; cout << x << endl; return 0; }
النقاط الرئيسية:
- دالة fun:
int fun(int *p): يأخذ المؤشر إلى عدد صحيح كـparameter.
*p = *p + 1;: زيادة القيمة التي يشير إليها المؤشر.
return *p;: إرجاع القيمة التي تم تحديثها. - الدالة الرئيسة main:
int x = 1;: يعلن ويفعل متغيرًا صحيحًا x.
int *ptr = &x;: يعلن عن مؤشر ptr ويعين عنوان x له.
cout << fun(ptr) << endl;: يستدعي الدالة fun باستخدام المؤشر ptr ويطبع النتيجة. قيمة x الآن هي 2.
cout << x << endl;: يطبع القيمة الحالية لـ x بعد استدعاء الدالة. وهي الآن 2.
cout << fun(&x) << endl;: يستدعي الوظيفة fun بعنوان x مباشرة ويطبع النتيجة.
أصبحت قيمة x الآن 3.cout << x << endl;: يطبع القيمة النهائية لـ x. هو الآن 3.
المخرجات:
إذا قمت بتشغيل هذا البرنامج، فإن المخرجات ستكون كالتالي:
2 2 3 3