مفهوم – تعتبر المؤشرات Pointers من أقوى المزايا التي تمتاز بها لغات البرمجة مثل ++C وكذلك لغة C عن باقي اللغات المشهورة مثل جافا وغيرها من اللغات الشهيرة.
تستخدم المؤشرات Pointers للوصول لأي شيء يتم تعريفه في الذاكرة وهي تعطينا المزيد من المزايا في التحكم.
لفهم عمل المؤشرات واستخدامها لابد أولًا أن يكون لديك معرفة عن ما هو العنوان Address في ذاكرة الحاسوب.
تُقسم ذاكرة الحاسوب إلى أجزاء من bytes وكل بايت لديه العنوان الخاص به على سبيل المثال في ذاكرة حجمها 1 KB يوجد 1024 bytes وكل بايت يعطي عنوان (أي أن مجال العناوين من 0 – 1023).
فالمؤشرات إذًا هي متغيرات تختزن عناوين متغيرات أخرى في الذاكرة بالـ hexadecimal النظام الست عشري، يمكن للمؤشرات أن تؤشر على متغير من نوع primitive أو عنصر من مصفوفة array أو غرض object.
لتعريف مؤشر جديد نستخدم الرمز * مع الإشارة إلى أن نوع المؤشر يجب أن يكون نفس نوع الشيء الذي سيشير له في الذاكرة.
إذا اردنا تعريف مؤشر نوعه int و إسمه x فعندنا ثلاث خيارات كالتالي.
int* x أو int *x أو int * x
معنى المؤشر Pointer
المؤشر أو الـ Pointer هو عبارة عن متغير تحتوي قيمته على عنوان متغير آخر في الذاكرة، ومن الإسم فهو يشير إلى عنوان متغير آخر.
حجم المتغير من النوع Pointer يكون ثابت أي كان حجم أو نوع البيانات التي يقوم بالإشارة إليها، ويتم تحديد الحجم الخاص بالمؤشر طبقا لمعمارية وحدة المعالجة المركزية وبالتبعية نظام التشغيل المستهدف، عادة ما يتم حجز مساحة 4-Byte في المعمارية 32-bit ويتم حجز مساحة 8-Byte في المعمارية 64-bit.
في لغة البرمجة C لا توجد الكلمة Pointer كنوع للبيانات كما هو الحال مع باقي الأنواع مثل int أو char، ولكن يتم إضافة رمز النجمة * مع نوع البيانات لتحديد أن هذا المتغير هو مؤشر.
تعتبر المؤشرات من أهم المواضيع التي يجب أن تتعلمها وتفهمها جيدا حتى تصبح مبرمج محترف بلغة الـ C، ولكي تتمكن من فهم المؤشرات يجب أولا أن تتعرف على المكونات الأساسية للذاكرة.
اقرأ ايضًا:
- كل ما تريد معرفته عن Data Structure هياكل البيانات
- نصائح للنجاح في الحياة من ستيف هارفي steve harvey
- نصائح تعلم لغة جديدة
- معنى مفتوح المصدر Open source
- كل ما تريد معرفته عن فلاتر Flutter
مكونات الذاكرة العشوائية RAM
تتكون الذاكرة من عدد كبير جدا من الوحدات القابلة لتخزين البيانات الثنائية (إما صفر أو واحد) تسمى هذه الوحدات بـ بت أو bit، ونظرا لصغر حجم هذه الوحدة يتم التعامل مع الذاكرة بوحدة أكبر قليلا تسمى بـ بايت أو Byte وهي مكونة من 8 بت، وتعد وحدة البايت هي أصغر وحدة يمكن حجزها لتخزين المتغيرات في أجهزة الحاسوب.
حتى يتمكن جهاز الحاسوب من التعامل مع الذاكرة يتم تقسيم الذاكرة المتاحة في الجهاز إلى وحدات بايت، ويتم ترقيم كل وحدة برقم مسلسل يبدأ بـ صفر، ويسمى هذا الرقم بعنوان وحدة الذاكرة أو الـ Memory Address.
فإذا كان جهاز الحاسوب يحتوي على ذاكرة بقدرة تخزينية واحد كيلو بايت 1KB (وهي قدرة صغيرة جدا فقط لتسهيل الفكرة) في هذه الحالة سوف تحتوي الذاكرة على 1024 بايت بما يعني وجود 1024 عنوان للذاكرة، بحيث يمثل العنوان صفر أول وحدة في الذاكرة والعنوان 1023 آخر عنوان في الذاكرة.
تقيد معمارية الحاسوب عدد عناويين الذاكرة التي يمكن التعامل معها، على سبيل المثال المعمارية 32-bit يمكنها التعامل مع عناوين للذاكرة تصل إلى 4,294,967,296 عنوان وهي تساوي 4 جيجا بايت من الذاكرة، هذا العدد من العناويين يمكن تمثيله أو تخزينه في 32 بت أو 4 بايت وهو حجم المتغير من النوع Pointer في هذه المعمارية.
يعتبر العنوان صفر في الذاكرة ذو معنى خاص، حيث يتم حجزه بواسطة نظام التشغيل وعادة ما يشار إليه بالقيمة NULL و يفضل أن يتم تخصيص هذه القيمة أثناء الإعلان عن المؤشرات.
الإعلان عن المؤشرات Declaration
يقصد بالإعلان عن المؤشرات أن يتم إنشاء متغير جديد من النوع Pointer، في هذه العملية يتم حجز مساحة في الذاكرة حجمها 4 بايت في المعمارية 32-bit أو 8 بايت في المعمارية 64-bit وعند تخصيص هذه المساحة تكون قيمتها الإفتراضية أي قيمة ثنائية عشوائية موجودة في لحظة تخصيصها للمتغير وتسمى هذه القيمة بـ Garbage أو قمامة، لذلك يفضل تهيئة المتغير الجديد بتخصيص القيمة NULL.
لكي يتم إنشاء متغير من النوع Pointer يجب تحديد نوع البيانات الخاص بالمتغير الذي سوف يتم إنشاء المؤشر ليتعامل معه، ثم يتم إستخدام رمز النجمة * ويسمى بـ Asterisk قبل إسم المتغير، والشكل التالي يمثل القاعدة العامة لإنشاء متغير من النوع Pointer
تحديد عنوان المتغير Address Of
كما علمنا فالمؤشر يستخدم ليشير إلى عنوان متغير آخر كقيمة له، ولذلك يجب معرفة كيفية إيجاد عنوان متغير في الذاكرة ليتم تخصيص هذا العنوان كقيمة للمؤشر، ويتم ذلك في لغة البرمجة C عن طريق كتابة الرمز & قبل إسم المتغير الذي سبق الإعلان عنه، ويسمى هذا الرمز بـ Address Of Operator.
المثال التالي هو برنامج متكامل كما شرحنا في مقالة الأكواد الأساسية لكتابة برنامج بلغة البرمجة C هذا البرنامج يقوم بإنشاء متغير ثم يقوم بطباعة قيمة المتغير وطباعة عنوان المتغير عن طريق إستخدام الدالة printf، عند تشغيل الكود في المثال التالي سوف تلاحظ أن عنوان المتغير سوف يتغير في كل مرة تقوم بتشغيل الكود.
تحديد قيمة المتغير المستخدم مع المؤشر Dereferencing
تعرفنا حتى الآن أن المؤشر يقوم بتخزين عنوان متغير آخر في الذاكرة، وبالتالي عند طباعة متغير من النوع Pointer سوف تحصل على عنوان المتغير الآخر وليس القيمة المخزنة في هذا المتغير، ولكي تتمكن من قراءة القيمة المخزنة للمتغير عن طريق المؤشر نقوم بإستخدام الرمز * قبل إسم المؤشر، ويعرف هذا الرمز في هذه العملية بـ Dereferencing أو إلغاء التأشير.
أهمية إستخدام المؤشرات في لغة البرمجة C
تمتاز لغة البرمجة C بقدرتها على التعامل مع الذاكرة بشكل مباشر ما يتيح إنشاء برمجيات ذات كفاءة عالية في إستخدام الذاكرة، ويرجع الفضل بشكل كبير إلى المؤشرات، حيث يمكن أن يتم التعامل مع أي متغير أي كان حجمه بمجرد معرفة عنوانه.
وتستخدم المؤشرات بشكل كبير للتعامل مع المصفوفات، حيث تعتبر المصفوفة نوع من أنواع المؤشرات وبالتالي يتم إستخدام العمليات الحسابية على المؤشرات (Pointer Arithmetic) للتنقل بين عناصر المصفوفة كما سنتعرف عليه لاحقا.
يتم إستخدام المؤشرات لتمرير المتغيرات ذات الحجم الكبير بين الدوال، فعند تمرير أي متغير لأي دالة عادة ما يتم إعادة نسخ المتغير في المساحة المخصصة من الذاكرة للدالة (بإستثناء المصفوفات).
وتسبب هذه العملية إهدار للوقت المستغرق في عملية النسخ وإهدار للذاكرة المتاحة حيث يتم نسخ المتغير والإحتفاظ بالمتغير الأصلي أي أن المتغير يوجد في الذاكرة مرتين، وتعرف عملية تمرير المؤشرات للدوال بالتمرير عن طريق المرجع أو العنوان Pass By Reference.
تعتبر المؤشرات موضوع حيوي و أساسي عند التحدث عن هياكل البيانات والتي تعرف بـ Data Structures، حيث تستخدم المؤشرات للربط بين وحدات البيانات أو كما تعرف بـ Nodes.
تستخدم المؤشرات لإنشاء متغيرات ديناميكية أو كما تعرف بـ Dynamic-Variables والتي تمكن المبرمج من إنشاء متغيرات أثناء تشغيل البرنامج عند الحاجة إليها، أو إنشاء مصفوفات بالحجم الذي يحدده مستخدم البرنامج، فكما تعلمنا أن المصفوفات في لغة البرمجة C يجب أن يتم تحديد عدد عناصرها بشكل ثابت أثناء إنشاؤها، ولكن بإستخدام المؤشرات يمكنك إنشاء مصفوفات بأي حجم يحدده المستخدم أثناء التشغيل وهو ما يعرف بـ Dynamic Arrays.