انتقل إلى المحتوى
Topos Uranos

ملخص

يفتتح هذا الدرس الوحدة الأولى من الدورة، المخصّصة للخطوات الأولى في البرمجة بلغة C++. ويشرح الغاية من الوحدة: أن تنقل من لم يبرمج قطّ من مسألة مصوغة باللغة الجارية إلى برنامج يُترجَم ويُنفَّذ ويقرأ البيانات ويكتب النتائج، مع معرفة ما فعلته كل أداة في الطريق؛ ويعرض دروسها الستة والخيط الذي يجمعها، من الخوارزمية المكتوبة بالعربية إلى تصنيف الأخطاء؛ ويحدّد القليل الذي يُفترض أنه معلوم، وهو الحساب المدرسي، وعادة اتّباع التعليمات المكتوبة، والتعامل مع الملفات والمجلدات؛ ويصوغ المسألة التي تحلّها الوحدة، وهي تحويل حساب نعرف إجراءه باليد إلى إجراء تنفّذه آلة دون أن تخطئ ودون أن تتعب؛ ويبيّن إلى أين تقود، في الوحدات اللاحقة وفي دورة البرمجة بلغة C++ II.

أهداف التعلم

  1. وصف تسلسل محتويات الوحدة، وشرح ما يقدّمه كل درس للدرس الذي يليه.
  2. التعرّف على المعارف المسبقة التي تفترضها الدورة (إجراء العمليات على الأعداد الصحيحة والعشرية، وحساب خارج القسمة والباقي، واتّباع التعليمات المكتوبة، وحفظ ملف في مجلد معيّن)، ومراجعتها عند الحاجة.
  3. شرح الطريق الذي تعلّم الوحدة اجتيازه، بمثال: من نصّ المسألة إلى المواصفات، ومن المواصفات إلى الخوارزمية، ومن الخوارزمية إلى البرنامج الذي يُترجَم ويُنفَّذ.
  4. التعرّف على ما يُنتظر إتقانه في نهاية الوحدة، وتمييزه ممّا سيُتعلَّم في الوحدات اللاحقة.

تقييم الدخول

قبل اجتياز الوحدة يحسن قياس نقطة البداية. وهذا التقييم تقييم ذاتي: لا تُمنح عليه درجة، وغايته الوحيدة توجيه الدراسة. ولمّا كانت هذه الوحدة الأولى من الدورة، فلا أسئلة عن وحدات سابقة؛ وبدلًا منها تتناول الأسئلة الثلاثة الأولى ما تفترض الدورة أنه معلوم: خارج القسمة والباقي في القسمة الصحيحة، وترتيب خطوات إجراء ما، واسم الملف وامتداده ومجلده. وتتناول الأسئلة السبعة التي تليها، بالترتيب، الأفكار المحورية في دروس الوحدة الستة. ومن لم يبرمج قطّ لا ينبغي أن يتوقّع الإصابة فيها، ولا ضير في ذلك: فكل جواب، صائبًا كان أو خاطئًا، يشرح المسألة ويسمّي الدرس الذي يعالجها. وتُقاس المهارات نفسها مرة أخرى في النهاية، في درس الخلاصة.

تقييم الدخول

قبل أن تبدأ الوحدة، قِس نقطة انطلاقك. إنه تقييم ذاتي قصير: لا يُمنح عليه درجة، وتُحفظ نتيجته في متصفحك فقط.

  1. السؤال 1من وحدات سابقةتُوزَّع 47 ورقة على 6 أشخاص، بحصص صحيحة متساوية، وتُحفظ الأوراق التي لا تكفي لجولة كاملة. كم ورقة ينال كل شخص، وكم ورقة تُحفظ؟

  2. السؤال 2من وحدات سابقةلإرسال ملف مرفق بالبريد الإلكتروني أربع خطوات: A، كتابة عنوان المرسَل إليه؛ B، الضغط على «إرسال»؛ C، فتح رسالة جديدة؛ D، إرفاق الملف. ما الترتيب المناسب؟

  3. السؤال 3من وحدات سابقةملف محفوظ في C:\Users\ana\programas\suma.cpp. ما اسمه، وما امتداده، وفي أي مجلد يوجد؟

  4. السؤال 4تقول وصفة: «إذا كانت العجينة جافة، فأضف ملعقة ماء واعجن؛ وكرّر حتى لا تبقى جافة». وتحتاج العجينة بالضبط إلى ثلاث ملاعق لتكفّ عن الجفاف. كم مرة يُسأل هل العجينة جافة؟

  5. السؤال 5أيّ هذه التعليمات يستطيع أيّ شخص، أو آلة، اتّباعها بالطريقة نفسها تمامًا؟

  6. السؤال 6برنامج يُترجَم دون أخطاء ولا تحذيرات، ويعمل جيدًا مع بيانات كثيرة، ومع معطى بعينه يتوقّف بالرسالة «division by zero». في أيّ لحظة وقع الخطأ؟

  7. السؤال 7ثُبِّت Visual Studio Code مع إضافته الخاصة بلغة C++، وعند طلب g++ --version في الطرفية تجيب بأنها لا تتعرّف على g++. ما الأرجح؟

  8. السؤال 8يكتب المترجم رسالة تبدأ بـwarning:، ومع ذلك ينتج الملف التنفيذي. ماذا يعني ذلك؟

  9. السؤال 9أين يبدأ تنفيذ برنامج بلغة C++؟

  10. السؤال 10برنامج يصرّح بـint age{};، وينفّذ std::cin >> age; ليقرأ عمرًا، فيكتب المستخدم abc. ماذا يحدث؟

محتويات الوحدة

للوحدة ستة دروس تجتاز بالترتيب الطريق من مسألة إلى برنامج يعمل. وكل درس يفترض الدرس الذي قبله، والأول لا يفترض شيئًا من اللغة.

  • من المسألة إلى الخوارزمية. تبدأ الدورة دون شيفرة، لأن الخوارزمية تسبق البرنامج. ويعلّم الدرس تحديد مواصفات مسألة بمدخلاتها ومخرجاتها والعلاقة بينهما (الشرط المسبق والشرط اللاحق)؛ ووصف خوارزمية بخطوات مرقّمة، دون لبس؛ واتّباعها باليد بجدول التتبع؛ والتعرّف فيها على التسلسل والقرار والتكرار؛ وتسويغ أن التكرار يتوقف، بكمية تتناقص في كل جولة.
  • البرامج والمترجمات ولغة C++. الخوارزمية المكتوبة لآلة برنامج، وبرنامج C++ لا يُنفَّذ كما يُكتب: فالمعالج المسبق والمترجم والرابط تحوّله إلى ملف تنفيذي. ويجتاز الدرس هذه المراحل الثلاث، ويميّز ما يُكتشف عند الترجمة ممّا لا يظهر إلا عند التنفيذ، ويقارن نموذج الترجمة بنموذج التفسير، ويضع معايير اللغة في سياقها الزمني، حتى C++23، وهو المعيار الذي تستعمله الدورة، وC++26، الذي لا يزال دعمه في المترجمات جاريًا.
  • تثبيت بيئة العمل على Windows و macOS و Linux. ثلاثة أدلّة كاملة، دليل لكل نظام، لتثبيت مترجم يدعم C++23 والمحرر Visual Studio Code مع إضافته الخاصة بلغة C++، والتحقّق من أن كل شيء يعمل ببرنامج التحقق، وحلّ المشكلات الشائعة: المترجم الذي لا تعثر عليه الطرفية، والإصدار القديم، والمعيار الذي لم يُطلَب.
  • الترجمة والتنفيذ والإعداد. دورة العمل من تحرير وحفظ وترجمة وتنفيذ وقراءة، من الطرفية ومن المحرر، بأمر الترجمة الخاص بالدورة. ويميّز الدرس الأخطاء، التي تمنع الملف التنفيذي، من التحذيرات، التي تشير إلى شيفرة مريبة؛ ويفعّل الكواشف (sanitizers)، كاشف أخطاء الذاكرة، AddressSanitizer، وكاشف السلوك غير المعرَّف، UndefinedBehaviorSanitizer، التي تراقب البرنامج أثناء تشغيله؛ ويشرح لماذا تُظهر المخرجات رموزًا غريبة بدلًا من الحروف العربية.
  • تشريح البرنامج. البرنامج الأدنى، قطعة قطعة: توجيه التضمين وملفات الترويسة، والدالة main ورمز الخروج، وفضاء الأسماء std، والتعليمات، والكتل، والتعليقات. ويعلّم الدرس تصحيح أخطاء البنية بقراءة رسائل المترجم بدءًا من الأولى، ويثبّت دليل الأسلوب الخاص بالدورة.
  • المدخلات والمخرجات والأخطاء. يتواصل البرنامج مع الخارج: يكتب بالدالتين std::print وstd::println، مع مواصفات التنسيق للعرض والمنازل العشرية، ويقرأ بـstd::cin. ويبيّن الدرس ما يحدث حين لا تكون المدخلات على الشكل المتوقَّع وكيف يُتحقَّق من القراءة، ويختم الوحدة بتصنيف الأخطاء بحسب لحظة ظهورها: أخطاء الترجمة، والربط، والتنفيذ، والأخطاء المنطقية.

والخيط الذي يجمعها هو البرنامج نفسه. فالدرس الأول يتصوّره، والثاني يشرح ما يتحوّل إليه، والثالث يثبّت الأدوات التي تحوّله، والرابع يعلّم استعمالها والإصغاء إلى ما تقوله، والخامس يشرّحه، والسادس يجعله يتحاور مع من يستعمله. وإذا كان الأمر كذلك، فإن الطالب في نهاية الوحدة لا يعرف بعدُ عن C++ إلا القليل جدًا، لكنه يعرف كيف يُعمَل بها، وهذا ما تفترضه بقية الدورة.

ما يُفترض أنه معلوم

لا تفترض الدورة أيّ خبرة سابقة في البرمجة. لكنها تفترض ثلاث مهارات تحسن مراجعتها الآن، إن كشف تقييم الدخول عن شكّ ما.

الأولى هي الحساب المدرسي: إجراء العمليات على الأعداد الصحيحة والعشرية، واحترام ترتيب العمليات (الضرب والقسمة قبل الجمع والطرح، ما لم توجد أقواس)، وقبل كل شيء حساب خارج القسمة والباقي في القسمة الصحيحة. وهذه الأخيرة أهمّ ممّا تبدو. فقسمة 47 ورقة على 6 أشخاص تعطي كل واحد 7 ويفضل 5، وهو ما يُكتب 47=6⋅7+547 = 6 \cdot 7 + 5، والباقي 55 أصغر من المقسوم عليه 66. ولـC++ عامل لخارج القسمة وآخر للباقي، وجزء كبير من الحسابات على الأعداد الصحيحة (تحويل الثواني إلى ساعات، وفصل أرقام عدد، وتقرير ما إذا كان العدد زوجيًا) يرجع إليهما. ومن أراد دراستها بتأنٍّ يجدها، مع برهانها، في دورة الجبر والهندسة 1: الأعداد والدوال وهندسة المستوى؛ وهنا يكفي أن نعرف كيف نحسبها.

الثانية هي عادة اتّباع التعليمات المكتوبة حرفيًا، والتعرّف على اللحظة التي لا تكفي فيها التعليمة لمعرفة ما ينبغي فعله. وليس الأمر معرفةً، بل موقفًا: أن نقرأ «أضف الملح حسب الذوق» فننتبه إلى أن هذه التعليمة تتوقّف على من ينفّذها. والدرس الأول من الوحدة يحوّل هذا الموقف إلى منهج.

الثالثة هي التعامل الأساسي مع الحاسوب: إنشاء مجلد، وحفظ ملف فيه باسم مختار، والتعرّف على امتداد الاسم (.cpp، .txt، .exe)، ومعرفة المجلد الذي يوجد فيه كل ملف. ويحسن ضبط النظام منذ الآن ليُظهر الامتدادات، التي تخفيها بعض الأنظمة افتراضيًا، مثل Windows: فالشيفرة المصدرية suma.cpp والملف التنفيذي suma.exe ملفان مختلفان تمامًا، والخلط بينهما مصدر لأخطاء عبثية. وتعلّم الوحدة أيضًا استعمال الطرفية، فلا حاجة إلى معرفته مسبقًا؛ ويكفي أن نكون مستعدّين لكتابة الأوامر بدلًا من الضغط على الأزرار. وأخيرًا، يقتضي تثبيت البرامج القدرة على فعل ذلك في الحاسوب الخاص؛ ويشير درس التثبيت إلى بديل عبر الإنترنت لمن لا يستطيع.

ولا تُفترض الإنجليزية. فرسائل المترجم بالإنجليزية، والدورة تعلّم قراءتها حقلًا حقلًا، بحيث يُفهم ما يهمّ منها (الملف، والسطر، ونوع العيب) دون إتقان اللغة. ولا تُفترض كذلك أيّ رياضيات تتجاوز الرياضيات المدرسية: فالأمثلة تستعمل القسمة، والمتوسطات، وجداول الضرب، والتواريخ، والساعات.

المسألة التي تحلّها الوحدة

الحساب الذي نعرف إجراءه باليد ليس بعدُ برنامجًا. والمسافة بينهما هي ما تعلّم الوحدة اجتيازه، ومسألة بسيطة تتيح قياسها.

مثالمدة بالساعات والدقائق والثواني

تسجّل ساعة إيقاف مدة كل نشاط عددًا من الثواني، مثل 7384، ونريد كتابتها بالصيغة المعتادة للساعات والدقائق والثواني، مع الدقائق والثواني دائمًا برقمين: 2:03:04. والحساب باليد سلسلة من القسمات: 7384=3600⋅2+1847384 = 3600 \cdot 2 + 184، ومنه ساعتان و184 ثانية؛ 184=60⋅3+4184 = 60 \cdot 3 + 4، ومنه 3 دقائق و4 ثوانٍ. ولمدة واحدة يُنجَز ذلك في دقيقة. أما لألف مدة في سجلّ، فالحساب باليد طويل وعرضة للأخطاء، والمهمة تصلح لأن تنفّذها آلة.

غير أن الآلة لا تستطيع تلقّي الشرح المتقدّم. فهي تتلقّى نصًّا بلغة برمجة، ولكتابة هذا النص يجب أن نكون قد حسمنا قبلُ ثلاث مسائل تركها الحساب اليدوي ضمنية. الأولى هي المواصفات: ما يدخل (عدد صحيح من الثواني، غير سالب)، وما يخرج (ثلاثة أعداد صحيحة: الساعات والدقائق والثواني)، وما العلاقة التي تربطها: إذا كان tt هو المجموع، فإن t=3600h+60m+st = 3600 h + 60 m + s، مع 0≤m<600 \leq m < 60 و0≤s<600 \leq s < 60. والثانية هي الخوارزمية: الخطوات الدقيقة التي تنتج ذلك المخرج لأيّ مدخل مقبول.

  1. hh يأخذ قيمة خارج قسمة tt على 36003600.
  2. mm يأخذ قيمة خارج القسمة على 6060 لباقي قسمة tt على 36003600.
  3. ss يأخذ قيمة باقي قسمة tt على 6060.
  4. اكتب hh، ثم نقطتين، ثم mm برقمين، ثم نقطتين، ثم ss برقمين.

والثالثة هي كتابة الخوارزمية بلغة C++، بالشكل الدقيق الذي تقتضيه اللغة، وترجمتها إلى ملف تنفيذي بالأدوات المناسبة. والبرنامج الآتي يفعل ذلك. وفيه أشياء كثيرة لم تُشرح بعد: المتغيرات (الدرس 2.1)، والعاملان / و%، اللذان يعطيان خارج القسمة والباقي في القسمة الصحيحة (الدرس 3.1)، والقراءة بـstd::cin ومواصفات التنسيق (الدرس 1.6)؛ ومواصفة التنسيق {:02} في هذا البرنامج، التي تكتب عددًا في خانتين وتكمل بالأصفار من اليسار، صيغة من العرض الذي يعلّمه ذلك الدرس والذي سيستعمله الدرس 3.1. ويكفي الآن أن نتعرّف فيه على خطوات الخوارزمية الأربع.

برنامج بلغة C++
#include <iostream>#include <print>​int main(){    int total{};  // سيأتي شرح المتغيرات في الدرس 2.1    std::print("المدة بالثواني: ");    std::cin >> total;    const int hours{total / 3600};    const int minutes{total % 3600 / 60};    const int seconds{total % 60};    std::println("{} s = {}:{:02}:{:02}", total, hours, minutes, seconds);}
مدخلات البرنامج
7384
المخرجات
المدة بالثواني: 7384 s = 2:03:04

الأسطر من 9 إلى 11 هي الخطوات من 1 إلى 3، والسطر 12 هو الخطوة 4. وتطابق النتيجة مع ما حُسب باليد ليس مصادفة، بل هو الفحص الذي يستحقه كل برنامج: أن يُجرَّب أولًا بمعطى معروف الجواب.

البرنامج يحلّ المسألة، لكن الوحدة تعلّم أيضًا الارتياب فيه. فإذا كتب المستخدم abc بدلًا من عدد، فشلت القراءة، وبقي total صفرًا، وكتب البرنامج، دون أيّ إشارة إنذار، أن المدة 0:00:00: استنتاج خاطئ في مظهر الصحيح. وإذا كتب مدة سالبة، فالمواصفات لا تقول ما يجب أن يحدث، والنتيجة بلا معنى. وإذا كُتب total / 360 بدلًا من total / 3600، فالبرنامج يُترجَم ويُنفَّذ ويعطي نتيجة خاطئة، ولا تنبّه إلى ذلك أيّ أداة. وكل واحد من هذه العيوب ينتمي إلى نوع مختلف من الأخطاء، يُكتشَف في لحظة مختلفة ويُبحث عنه بطريقة مختلفة؛ والدرس الأخير من الوحدة يصنّفها. ويترتّب على ذلك أن المسألة التي تحلّها الوحدة ليست كتابة هذا البرنامج فحسب، بل معرفة لماذا يعمل، ومع أيّ بيانات يكفّ عن العمل، وأيّ أداة ستنبّه، أو لن تنبّه، إلى كل عيب.

ولذلك، في نهاية الوحدة سيستطيع الطالب أن يكتب برامج من هذا النوع ويترجمها وينفّذها: بضعة مدخلات، وبضع عمليات حسابية متتالية، وبضع نتائج مكتوبة بتنسيق. ولن يستطيع بعدُ اتّخاذ القرارات ولا تكرار التعليمات بلغة C++ (وإن استطاع ذلك في خوارزمية مكتوبة بالعربية)، ولا اختيار نوع كل معطى عن بصيرة؛ فذلك ما تأتي به الوحدات اللاحقة.

إلى أين تقود

الوحدة هي عتبة الدورة. وما يُستعمل فيها دون شرح يُشرح لاحقًا، بهذا الترتيب. فالوحدة 2، «البيانات والأنواع»، تشرح المتغيرات وكيف تُخزَّن في الذاكرة، وحدود الأعداد الصحيحة (ولماذا قد يفيض حساب سليم)، وتقريب الأعداد ذات الكسور العشرية، والتحويلات بين الأنواع. والوحدة 3، «التعابير والعوامل»، تشرح الحساب في C++، مع خارج القسمة والباقي للأعداد السالبة، ومنطق الشروط، وما يتركه المعيار غير معرَّف في تعبير ما. والوحدة 4، «التحكم في التدفق»، تنقل إلى C++ القرارات والتكرارات التي يكتبها الدرس الأول بالعربية، وتعلّم تسويغ أن الحلقة صحيحة وأنها تتوقف. والوحدة 5 تقسّم البرامج إلى دوال؛ والوحدة 6 تقدّم البيانات المركبة (المصفوفات، والمتجهات، والجداول، والسجلات)، مع خوارزميات البحث والترتيب وكلفتها؛ والوحدة 7 تتناول النصوص، والقراءة المحكمة للمدخلات، والملفات؛ والوحدة 8 تتناول البرامج متعددة الملفات، والاختبارات المنهجية، ومصحّح الأخطاء.

وبعد هذه الدورة، تواصل دورة البرمجة بلغة C++ II ما تتركه هذه الدورة عمدًا: المؤشرات والذاكرة الديناميكية، والأصناف ذات الطرائق، والقوالب الخاصة، والدوال المجهولة، والاستثناءات. ولا يلزم أيّ من هذه الموضوعات لحلّ مسائل هذه الدورة، وتأجيلها يتيح التركيز على ما يصحّ في أي لغة: تحديد المواصفات، وتصميم الخوارزمية، وكتابتها بوضوح، والتحقّق من صحّتها. وسيجمع درس الخلاصة في هذه الوحدة هذا التمييز تحديدًا، بين ما هو خاص بلغة C++ وما سيُنقل إلى أيّ لغة أخرى.