مؤشر (لغات البرمجة)
المؤشر في الحوسبة أو علوم الحاسوب، هو نوع من أنواع البيانات في بعض لغات البرمجة تمثل قيمته (أو تشير إلى) قيمة أخرى مخزنة في مكان آخر في ذاكرة الحاسوب، وذلك باستخدام عنوان الذاكرة لها.
عملية الحصول على القيمة التي يشير إليها المؤشر تسمى تتبع المؤشر dereferencing. يعتبر المؤشر تطبيق بسيط لنوع البيانات العام المرجع برغم أنه مختلف عن الوسيلة المسماة مرجع reference في لغة سي++.
تفيد المؤشرات إلى البيانات في تحسين الأداء للعمليات المتكررة مثل تمرير السلاسل الحرفية وتراكيب (بنيات) الأشجار. وتستخدم المؤشرات للدوال في ربط الوسائل methods في البرمجة كائنية التوجه والربط عند وقت التشغيل بمكتبات الربط الديناميكية التي يرمز لها بـ DLL.
في حين أن المؤشرات قد استخدمت لتمثل المراجع عموماً إلا أنها تنطبق بشكل أكثر ملاءمة على تراكيب البيانات التي تسمح واجهتها بوضوح للمؤشر أن يعالج بوصفه عنوان ذاكرة. ولأن المؤشرات تسمح بالوصول الغير محمي بشكل واسع لعناوين الذاكرة فإن هناك بعض الخطورة المصاحبة لاستخدامها.
عند القيام بإعداد تراكيب البيانات مثل القوائم والأشجار، فإنه من الضروري استخدام المؤشرات للمساعدة في الطريقة التي تتم بها معالجة البيانات والتحكم بها.
إن المؤشرات مدعومة مباشرة ودون قيود في لغات مثل سي، سي++، باسكال ومعظم لغات التجميع. وهي تستخدم أساساً في بناء المراجع والتي تتسع بدورها تقريباً لبناء كل تراكيب البيانات وأيضا في تمرير البيانات بين الأجزاء المختلفة من البرنامج.
في لغات البرمجة المعتمدة على الدوال والتي تستند بشكل كبير إلى القوائم؛ يتم التحكم بالمؤشرات والمراجع من اللغة باستخدام التركيبات الداخلية مثل cons.
عند التعامل مع المصفوفات، فإن عملية البحث الحيوي تشتمل على مرحلة تسمى "حساب العنوان" والتي تشمل بناء مؤشر إلى عنصر البيانات المرغوب في المصفوفة. وفي تراكيب البيانات الأخرى مثل القوائم المرتبطة تستخدم المؤشرات كمراجع لتربط قطعة معينة من الكود بأخرى.
تستخدم المؤشرات في تمرير المعاملات باستخدام مراجع لها، ويكون هذا مفيداً إذا أردنا أن يكون تعديل الدالة للمعامل مرئياً للجزء الذي قام باستدعائها. وهذا مفيد أيضا في إرجاع عدة قيم من دالة.
الصيغة الأساسية للإعلان عن مؤشر هي:
حيث يقوم هذا بالإعلان عن codice_1 كمؤشر إلى عدد صحيح.
وحيث أن محتويات الذاكرة لا يضمن ما هي القيمة التي من الممكن أن تحتويها في لغة السي، فيجب توخي الحذر للتأكد من أن العنوان الذي يشير إليه codice_1 هو عنوان صالح، ولهذا يرى البعض استهلال المؤشر بالقيمة NULL.
عندما يتم تتبع مؤشر له القيمة NULL فحينها يحدث خطأ تشغيل ويتوقف التنفيذ عادة مع segmentation fault.
وبعد الإعلان عن مؤشر فإن الخطوة المنطقية التالية هي جعله يشير إلى شيء ما.
ويقوم هذا بإسناد عنوان الذاكرة للمتغير الصحيح a إلى قيمة المؤشر money، على سبيل المثال إذا كان المتغير a مخزن في الذاكرة عند الموقع 0x8130 فستكون قيمة money هي 0x8130 بعد الإسناد.
ولتتبع المؤشر يتم استخدام علامة النجمة * مرة أخرى:
ويخبر هذا مترجم الكود بأن يأخذ محتويات المؤشر money والتي هي 0x8130، وينتقل إلى ذلك العنوان ويعين القيمة المخزنة به إلى 8.
بعد ذلك إذا تم الدخول إلى a فسنجد قيمته 8.
ربما يكون هذا المثال أكثر وضوحا إذا تم فحص الذاكرة مباشرة.
افترض أن a له عنوان الذاكرة 0x8130 و money له العنوان 0x8134، وافترض أيضا أن الحاسوب المستخدم هو حاسوب 32بت حيث سعة نوع البيانات int هي 32 بت. فإن الشكل التالي هو ما سيتكون في الذاكرة بعد تنفيذ الكود التالي:
المؤشر ذو القيمة NULL المعروضة هنا هو 0x00000000.
وبتعيين عنوان المتغير a للمؤشر money باستخدام مؤثر التعيين &
وتكون الحصيلة في الذاكرة كما يلي:
وعند تتبع المؤشر money مثل:
فإن الحاسوب سيأخذ محتويات المؤشر والتي هي 0x8130 وينتقل إلى ذلك العنوان ويعين القيمة 8 إلى ذلك الموقع وتكون حصيلة الذاكرة كما يلي:
وكما هو واضح فإن استدعاء قيمة المتغير a سوف ينتج القيمة 8 لأن التعليمة السابقة قامت بتعديل محتويات المتغير a عن طريق المؤشر money.
الخطوة التالية في الحديث عن المؤشرات في لغة السي هي المصفوفات.
في لغة سي تتم عملية فهرسة المصفوفات باستخدام حسابات المؤشرات ؛ حيث أن معايير اللغة تتطلب أن يكون
مكافئ إلى
وبهذا في لغة سي يمكن اعتبار المصفوفات كمؤشرات لمناطق متتابعة من الذاكرة (ليس بينها فجوات)، والصيغة المستخدمة في الوصول إلى المصفوفات مماثلة لتلك المستخدمة في تتبع المؤشرات، على سبيل المثال المصفوفة array يمكن الإعلان عنها واستخدامها كما يلي:
ويقوم هذا بحجز موقع في الذاكرة لخمسة أعداد صحيحة ويعلن عن array كمؤشر لهذا الموقع، ومن الاستخدامات الشائعة الأخرى للمؤشرات هي الإشارة للذاكرة المحجوزة ديناميكيا باستخدام دالة malloc والتي ترجع قطعة متصلة من الذاكرة بما لا يقل عن الحجم المطلوب الذي يمكن استخدامه كمصفوفة.
في حين أن معظم المؤثرات على المؤشرات والمصفوفات متكافئة إلا أنه من المهم أن نذكر أن دالة sizeof سوف تختلف. في هذا المثال codice_3 سوف تكون قيمتها codice_4 أي أن حجم المصفوفة 5×حجم متغير العدد الصحيح، ولكن codice_5 تكون قيمته codice_6 أي حجم المؤشر نفسه.
يمكن الإعلان عن القيم الافتراضية لمصفوفة مثل:
إذا فرضت أن array تقع في الذاكرة بدءً من العنوان 0x1000 على حاسوب 32 بت وترتيب البيانات به little-endian، إذاً سوف تحتوي الذاكرة ما يلي:
ويمثل الشكل 5 أعداد صحيحة 2 و4 و3 و1 و5.
هذه الأعداد الصحيحة الخمسة تشغل 32 بت (4بايت)، وكل منها يخزن البايت الأقل أهمية أولاً، لأن بنية الحاسوب little-endian وتخزن بالتوالي بدءً من عنوان الموقع 0x1000.
الصيغة العامة في لغة سي مع المؤشرات هي:
array[3]
مماثل إلى:
يعني
والذي يخبر المترجم بتتبع القيمة المخزنة في العنوان 0x100C والتي هي في هذه الحالة 0x0001.
فيما يلي مثال على تعريف القوائم المرتبطة في لغة سي:
يمكن استخدام المؤشرات لتمرير المتغيرات باستخدام مراجع لها، بما يسمح لقيمتها بأن تتغير، مثال: