مثل العديد من اللغات الأخرى، تحتوي ++C على المؤشرات. أنت تعرف بالفعل أن المراجع و_المؤشرات_ متشابهة، لكن اعتبرهما مستوى أقرب إلى العمل الداخلي لحاسوبك. المؤشرات متغيرات تحمل عناوين الكائنات. وهي تُستخدم للتفاعل المباشر مع الكائنات، مما يتيح تخصيص الذاكرة الديناميكي ومعالجة البيانات بكفاءة في ++C.
إذا كنت جديدًا على المؤشرات، فقد تبدو غامضة بعض الشيء، لكن بمجرد أن تعتاد عليها ستجدها واضحة تمامًا.
إنها جزء أساسي من ++C، لذا خصّص بعض الوقت لفهمها حقًا. النسخة المجرّدة في هذا المفهوم تُسمى أيضًا المؤشر الغبي أو المؤشر الخام. وفي ++C الحديثة توجد أيضًا المؤشرات الذكية، أما النوع الأساسي فليس ذكيًا على الإطلاق وعليك القيام بكل العمل يدويًا.
قبل الخوض في التفاصيل، يجدر بك فهم استخدام المؤشرات. المؤشرات طريقة لمشاركة عنوان كائن ما مع أجزاء أخرى من برنامجنا، وهذا مفيد لسببين رئيسيين:
يتضمن تعريف المؤشر في ++C تحديد نوع البيانات الذي يشير إليه المؤشر، يليه نجمة (*) واسم المؤشر.
عند تعريف المؤشرات، لا يتم تهيئتها تلقائيًا.
وبدون إسناد صريح، يحمل المؤشر عادةً قيمة غير محددة، يُشار إليها غالبًا بـ"عنوان عشوائي".
وفي حين أن بعض المترجمات قد تهيّئ المؤشرات إلى nullptr، فإن هذا السلوك غير مضمون في كل المترجمات، لذا من الضروري ألا تعتمد عليه.
من أفضل الممارسات تهيئة المؤشرات الخام صراحةً والتحقق من أنها ليست فارغة قبل استخدامها لتجنب مشكلات محتملة.
int* ptr{nullptr}; // Declares a pointer and makes sure it is not invalid
لإسناد عنوان متغير إلى مؤشر، تستخدم عامل أخذ العنوان (&).
ويتم إلغاء الإشارة إلى المؤشر باستخدام عامل الإشارة غير المباشرة (*).
std::string opponent{"Solomon Lane"};
// 'ethan' points to the address of the string opponent
std::string* ethan{&opponent};
// Instead of ethan's, the opponent's name address is given to the passPort
std::string passportName{*ethan};
انتبه: يجب إلغاء الإشارة صراحةً، بينما كانت المراجع تعمل ببساطة كاسم مستعار.
يتيح لك حساب المؤشرات إجراء عمليات حسابية على المؤشرات، وهو مفيد بشكل خاص عند التعامل مع المصفوفات. إضافة عدد صحيح إلى مؤشر تجعله يشير إلى عنصر مختلف.
// Stargate Coordinate Code
int gateCode[] = {462, 753, 218, 611, 977};
// 'ptr' points to the first element of 'gateCode'
int* ptr{&gateCode[0]};
// Accesses the third Stargate address through pointer arithmetic
int dialedAddress{*(ptr + 2)};
// Chevron encoded! Dialing Stargate address:
openStarGate(dialedAddress);
قد يؤدي حساب المؤشرات في ++C بسهولة إلى سلوك غير معرّف إذا لم يتم التعامل معه بحذر. وقد يظهر السلوك غير المعرّف في صورة نتائج غير متوقعة للبرنامج، أو انهيارات، أو حتى ثغرات أمنية. ومن أشهر الأمثلة على عواقب السلوك غير المعرّف ما حدث في انفجار صاروخ آريان 5 عام 1996، حيث أدى استثناء برمجي ناتج عن تحويل عدد عشري 64-بت إلى عدد صحيح مُوقّع 16-بت إلى فشل كارثي.
في ++C، يُستخدم العامل -> للوصول إلى أعضاء كائن عبر مؤشر إليه.
وهو اختصار يبسّط الوصول إلى أعضاء الكائنات التي تشير إليها المؤشرات.
على سبيل المثال، إذا كان ptr مؤشرًا إلى كائن له متغير عضو x، فبدلًا من استخدام (*ptr).x، يمكنك استخدام ptr->x مباشرةً.
يعزز هذا العامل وضوح الكود ويقلل الإسهاب عند التعامل مع مؤشرات إلى كائنات.
إليك مثالًا موجزًا، مع بنية Superhero لها متغير عضو superpower.
تُنشئ الدالة الرئيسية مؤشرًا dianaPrince إلى كائن Superhero (يمثّل Wonder Woman).
ويُستخدم العامل -> للوصول إلى متغير العضو superpower، مستعرضًا "حبل الحقيقة" الشهير لدى Wonder Woman.
struct Superhero {
std::string superpower;
};
Superhero wonder_woman{};
Superhero* dianaPrince = &wonder_woman;
dianaPrince->superpower = "Lasso of Truth";
// Using the -> operator to access member variable superpower:
std::cout << "Wonder Woman, possesses the mighty " << dianaPrince->superpower;
تتيح المؤشرات والمراجع معًا الوصول غير المباشر إلى الكائنات، لكنهما يختلفان في إمكاناتهما واعتبارات الأمان. توفّر المؤشرات مرونة تغيير الكائن الهدف، ويمكن إسناد القيمة الفارغة إليها. غير أن هذه المرونة تجلب مخاطر، مثل إلغاء الإشارة إلى مؤشرات فارغة أو إنشاء مؤشرات معلّقة. أما المراجع، فلا يمكن أن تكون فارغة وتُرتبط بكائنات صالحة عند إنشائها، ما يتجنب هذه المخاطر. وبالنظر إلى طبيعتها الأكثر أمانًا، يُفضّل استخدام المراجع بدلًا من المؤشرات ما لم تكن الوظائف الإضافية التي تقدمها المؤشرات ضرورية.
مرحبًا أيها المهندس! أنت أحد آخر المخضرمين في مؤسسة Speedywagon، وهي منظمة سرية ظلّت لعقود تحارب تهديدات قديمة مثل Pillar Men. وخلال هذه الجهود، أمضيت سنوات في صيانة الأنظمة التقنية للمؤسسة، المبنية على مزيج من التقنيات المتطورة والمكتبات القديمة.
غير أن المستشعرات التي تتعقّب أنشطة Pillar Men أصبحت معطّلة في الآونة الأخيرة. أنظمة المؤسسة قديمة، والكود يتفاعل مع مكتبة C++ قديمة لا يمكن تحديثها. مهمتك هي تنفيذ أربع دوال أساسية تراقب نشاط مستشعرات Pillar Men باستخدام مكتبة قديمة الطراز قائمة على المؤشرات.
بصفتك مهندس C++ عصريًا، قد تفضّل استخدام المؤشرات الذكية، لكن للأسف، الكود القديم يفرض احترام الأساليب القديمة. قد يكون مصير البشرية معلّقًا بهذه المؤشرات، فتقدّم بحذر، وليكن دليلك طاقة Hamon.
بما أن قراءات المستشعرات قد تكون ضخمة، نوفّر نسخة تجريبية من struct تُستخدم في المكتبة الفعلية. الكود مُنفَّذ بالفعل لك في ملف الترويسة.
struct pillar_men_sensor {
int activity{};
std::string location{};
std::vector<int> data{};
};
connection_check)مهمتك الأولى هي التأكد من أن مستشعر Pillar Men متصل بشكل صحيح.
لا نريد إنذارات كاذبة تُطلقها مستشعرات غير متصلة.
ستكتب دالة connection_check تتحقق من صلاحية مؤشر المستشعر عبر فحص nullptr.
pillar_men_sensor.true إذا لم يكن مؤشر المستشعر nullptr، وfalse في غير ذلك.pillar_men_sensor* sensor{nullptr};
bool isConnected = connection_check(sensor);
// isConnected => false
activity_counter)Pillar Men يتربصون في الظلال، ونحتاج إلى معرفة ما إذا كانت المستشعرات قد رصدت أي نشاط.
ستكتب دالة activity_counter التي تأخذ مصفوفة من المستشعرات وسعة تشير إلى عدد المستشعرات في المصفوفة.
pillar_men_sensor sensor_array[3] = {{0}, {101}, {22}};
int totalActivity = activity_counter(sensor_array, 3);
// totalActivity => 123
alarm_control)لا ينبغي لكل مستشعر أن يُطلق إنذارًا إلا عند وجود خطر حقيقي.
تضمن دالة alarm_control ألا يُطلق المستشعر إنذارًا إلا إذا كان مستوى نشاطه أكبر من 0.
ينبغي أن تتحقق هذه الدالة أيضًا من كون المستشعر nullptr لمنع انهيار النظام.
pillar_men_sensor.nullptr. فإن كان كذلك، أرجِع false.true؛ وإلا فأرجِع false.pillar_men_sensor db{9008, "songokunoie", {7, 7, 7}};
bool alarm = alarm_control(&db);
// alarm => true
uv_alarm
في هذه المهمة، ستنفّذ دالة uv_alarm لتحديد ما إذا كان ينبغي إطلاق إنذار بناءً على مستويات التعرّض للأشعة فوق البنفسجية ونشاط المستشعر.
ينبغي أن تستخدم دالة uv_alarm الدالة uv_light_heuristic الموفّرة، والتي تعمل على vector من البيانات وتُرجع قيمة بناءً على عتبات معيّنة.
هذه نسخة تجريبية من الكود المعقّد الذي سيعمل في بيئة الإنتاج، لذا لا تغيّر الواجهة.
عرّف دالة uv_alarm في فضاء الأسماء speedywagon. ينبغي أن:
pillar_men_sensor كمعامل لها.false إذا كان مؤشر المستشعر nullptr.uv_light_heuristic وتمرّر عنوان مصفوفة data الخاصة بالمستشعر.true إذا كانت القيمة التي أرجعتها uv_light_heuristic أكبر من مستوى sensor->activity، وإلا فأرجِع false.سجّل في Exercism لتتعلّم وتتقن C++ عبر 19 مفهومًا100 تمرين، وإرشاد بشري حقيقي، وكل ذلك مجانًا.