ملخص
يفتتح هذا الدرس الوحدة الثامنة والأخيرة من الدورة، وهي مخصّصة للبرامج الأكبر. ويشرح غايتها: تنظيم البرامج التي لم تعد تتّسع لملف واحد ولا للذهن، والتحقق من صحتها، وتصحيح أخطائها؛ ويقدّم دروسها الثلاثة والخيط الذي يجمعها، وهو خيط يُغلق الدائرة التي فُتحت في أول درس من الدورة (التوصيف، والبناء، والتحقق)؛ ويذكّر بما تفترض الوحدة أنه معلوم، وهو الدورة كلها؛ ويصوغ المسألة التي تحلّها الوحدة، وهي مسألة برنامج من ملف واحد يعمل مع البيانات التي اختُبر بها ويسكت عن خطأ عند حدّ مواصفاته؛ ويستبق الفرق بين الاختبار والبرهان؛ ويبيّن إلى أين تقود، في المشروع النهائي وفي دورة البرمجة بلغة C++ II.
أهداف التعلم
- وصف تسلسل محتويات الوحدة وشرح ما يقدّمه كل درس للدرس الذي يليه.
- التذكير، بمثال، بالفرق بين التصريح بدالة وتعريفها، وبالعقد الذي يحدّد مواصفاتها، وبالمرحلتين (الترجمة والربط) اللتين تحوّلان عدة ملفات إلى برنامج.
- استباق الفرق، بمثال، بين اختبار برنامج ببعض الحالات والبرهنة على أنه صحيح لجميع الحالات المقبولة.
- التعرّف على ما يُنتظر إتقانه عند إنهاء الوحدة والدورة، وتمييزه ممّا سيُتعلَّم في دورة البرمجة بلغة C++ II.
تقييم الدخول
قبل اجتياز الوحدة يحسن قياس نقطة البداية. وهذا التقييم لا تُمنح عليه درجة: إنما يوجّه الدراسة. وتتناول الأسئلة السبعة الأولى ما تفترض الوحدة أنه معلوم (التصريح والتعريف، والشرط المسبق، وعقد دالة من الوحدة 6، ورسائل الرابط، وحالات البحث الثنائي، وجدول التتبع، والقراءة خارج متجه)؛ وتتناول الأسئلة الثلاثة التي تليها، بترتيب الدروس، الأفكار المحورية في الوحدة، وفيها يكون «لا أعرف بعدُ» جوابًا صادقًا. وكل جواب يشرح المسألة ويسمّي الدرس الذي يعالجها؛ وتُقاس المهارات نفسها مرة أخرى في درس الخلاصة.
قبل أن تبدأ الوحدة، قِس نقطة انطلاقك. إنه تقييم ذاتي قصير: لا يُمنح عليه درجة، وتُحفظ نتيجته في متصفحك فقط.
السؤال 1من وحدات سابقةماذا يفعل السطر
int gcd(int a, int b);المكتوب قبلmain؟يخلط بين التصريح والتعريف: بلا جسم لا يوجد ما يُنفَّذ، ولا تُنفَّذ أي دالة لأنها مكتوبة، بل حين تُستدعى.يخلط بين التصريح والاستدعاء: الاستدعاء لا يحمل أنواع الوسائط.يغفل عن أن التوقيع يكفي المترجم للتحقق من الاستدعاء؛ أما غياب الجسم، إن لم يكتبه أحد، فيكتشفه الرابط لا المترجم.يكفي التصريح ليتحقق المترجم من كل استدعاء؛ أما التعريف، بجسمه، فيمكن أن يأتي أدنى أو في ملف آخر. ودرس ملفات متعددة ومكتبات خاصة كله يقوم على هذا الفصل: ملف الترويسة يصرّح، وملف التنفيذ يعرّف.راجِع: الدوال
السؤال 2من وحدات سابقةللدالة
toBase(n, base)الشرط المسبق «n >= 0و2 <= base <= 10». من الذي يجب أن يضمنه؟يخلط بين الشرط المسبق والتحقق من صحة المدخلات: التحقق من المدخلات مهمة حدّ البرنامج، لا مهمة كل دالة.يظن أن التعليقات يُتحقَّق منها؛ والمترجم يتجاهلها.لا يرى أن العقد يوزّع الالتزامات؛ وبدونه لا يعرف أحد من أخطأ حين يتعطّل شيء.الشرط المسبق هو جزء العقد الذي يُلزم المستدعي؛ وفي المقابل تضمن الدالة شرطها اللاحق. وإذا خُرق الشرط المسبق فلا تعد الدالة بشيء. وسيعلّم درس اختبار البرامج كيف يُتحقَّق منه بـassertأثناء تطوير البرنامج.راجِع: الدوال
السؤال 3من وحدات سابقةالدالة
binarySearch(values, target)من الدرس 6.4 تعيد موضعًا لـtargetأوvalues.size()إن لم يكن موجودًا. ما شرطها المسبق؟مع المتجه الفارغ لا تؤدي الحلقة أي جولة وتعيد الدالة 0، وهوvalues.size(): فالحالة يغطيها الشرط اللاحق.الدالة تبلّغ عن الغياب؛ واشتراط الوجود يجعلها عديمة الفائدة.مع التكرار تعيد الدالة أحد مواضع القيمة، وهذا ما يسمح به الشرط اللاحق.كل جولة تُسقط نصف الفترة بالمقارنة مع العنصر الأوسط، وهذا لا يصحّ إلا إذا كان المتجه مرتّبًا. ومع بيانات غير مرتّبة تجيب الدالة، دون أي تنبيه، بشيء خاطئ. ويُكتب الشرط المسبق في العقد، حيث يراه المستدعي.راجِع: البحث والترتيب
السؤال 4من وحدات سابقةبرنامج يُترجَم دون أخطاء، وعند بناء الملف التنفيذي يظهر
undefined reference to `tetrahedral(int)'. أي مرحلة فشلت؟لا يميّز رسائل المترجم، التي تذكر ملفًا وسطرًا، من رسائل الرابط، التي تذكر ملفات كائنية وأسماء.البرنامج لم يُوجد أصلًا: بلا ملف تنفيذي لا تنفيذ.غياب#includeيُنتجwas not declared in this scopeعند الترجمة، لا هذه الرسالة.قبل المترجم كل استدعاء لأنه رأى تصريحًا؛ وبحث الرابط عن التعريف في جميع الملفات الكائنية وفي المكتبات فلم يجده. ويشرح درس ملفات متعددة ومكتبات خاصة أسبابه المعتادة: ملف لم يُترجَم، أو تصريح نُسخ بنوع آخر.راجِع: البرامج والمترجمات ولغة C++
السؤال 5من وحدات سابقةأي هذه المجموعات من الحالات يختبر البحث الثنائي على أفضل وجه؟
يخلط بين الكمّ والتغطية: لا يختبر الغياب أبدًا ولا الحدود، حيث تكمن الأخطاء عادةً.الحالة التي نجحت من قبل هي الأقل احتمالًا لأن تكشف شيئًا جديدًا.إنها لانهائية، أو كثيرة كثرة فلكية ضمن حدود النوع: الاختبار يقتضي الاختيار.كل حالة تمتحن حدًّا مختلفًا من الفترة : الفترة الفارغة منذ البداية، والفترة التي تتقلّص إلى عنصر واحد، والطرفان، والطرق الثلاث لغياب القيمة. واختيار الحالات انطلاقًا من المواصفات، بحسب المناطق والحدود، هو موضوع درس اختبار البرامج.راجِع: البحث والترتيب
السؤال 6من وحدات سابقةما قيمتا
aوbبعدint a{0}; int b{1}; for (int i{0}; i < 4; ++i) { const int t{a + b}; a = b; b = t; }؟يعدّ جولة زائدة: معi < 4يُنفَّذ الجسم أربع مرات لا خمسًا.يعدّ جولة ناقصة، وهو خطأ الفرق بواحد في الاتجاه المقابل.ينسى أنtيحفظ المجموع المحسوب قبل أن يتغيّرa: في الجولة الأخيرة يتلقىaالقيمة 3 منb، لكنbيتلقى ذلك المجموع، 5، لا القيمة الجديدة لـa.جدول التتبع، جولة بعد جولة، يعطي : أربع جولات، وiمن 0 إلى 3. إنه الجدول الذي يملؤه مصحّح الأخطاء نيابةً عمّن يبرمج، ويستعمله درس تصحيح أخطاء البرامج للحكم على الحالة عند كل نقطة توقف.راجِع: الحلقات
السؤال 7من وحدات سابقةلماذا يتوقف
std::vector<int> v{1, 2}; std::println("{}", v[2]);مع خيارات الدورة، ويمكن، إذا تُرجم بـ-O2وحده ودون الكاشفات، أن يكتب أي عدد كان؟يظن أن التحسين يصلح الأخطاء؛ وهو لا يفعل إلا أن يزيل وسائل التحقق ويفترض أن البرنامج لا يخالف المعيار.يعكس الأثر: التحقق الذي يوقف البرنامج هو تحقق المكتبة دون تحسين.إنه خطأ الفرق بواحد في الفهارس: فهارس متجه من عنصرين هي 0 و1.الفهرس 2 غير موجود في متجه من عنصرين. وما يُلاحَظ يتوقف على المترجم والخيارات، ولذلك تُنفَّذ الاختبارات وجميع وسائل التحقق مفعّلة، كما يعلّم درس اختبار البرامج.راجِع: المتجهات
السؤال 8ملف ترويسة ذو حرّاس تضمين يعرّف (لا يصرّح فقط)
double scale(double x)، دونinline، ويضمّنهmain.cppوreport.cpp. ماذا يحدث عند بناء البرنامج؟يظن أن الحرّاس يعملون بين الملفات؛ وهم يعملون داخل كل وحدة ترجمة.يخلط بين الملف الذي يُترجَم والبرنامج كله: في داخل كل ملف تعريف واحد فقط.هذا جواب صادق: الدرس 8.1 يبيّنه برسالة الرابط الحقيقية.الحرّاس يمنعون دخول ملف الترويسة مرتين في الملف الواحد، لكن كل.cppيُترجَم منفصلًا ويتلقى نسخته من التعريف: فيجد الرابط تعريفين. إنها قاعدة التعريف الواحد، من درس ملفات متعددة ومكتبات خاصة.راجِع: ملفات متعددة ومكتبات خاصة
السؤال 9دالة تجتاز خمسمئة اختبار آلي اختيرت بعناية. ماذا يمكن أن يُقال؟
يخلط بين الوفرة والبرهان؛ فالخطأ عند حدّ لم تمسّه أي حالة يبقى مهما كثرت الحالات الداخلية.الحالات ليست عيّنة عشوائية من الأخطاء الممكنة، وتواتر النجاح لا يقيس احتمال أن يكون البرنامج سليمًا.هذا جواب صادق: الدرس 8.2 يبدأ بهذا السؤال.يمكن للاختبار أن يُظهر وجود خطأ، ولا يُظهر غيابه أبدًا: فالقول بالصحة في جميع الحالات يقتضي حجة، كاللامتغير في الدرس 4.3، لا قائمة حالات. والاختبارات المختارة جيدًا تجعل مرور خطأ شائع أمرًا بعيد الاحتمال، ولذلك قيمتها كبيرة. ويطوّر درس اختبار البرامج هذا التمييز.راجِع: اختبار البرامج
السؤال 10نقطة توقف موضوعة في السطر
total += k;، داخل حلقة، والبرنامج يتوقف عندها للمرة الثالثة. ماذا يدلّ عليه السطر المظلَّل؟يخلط بين التوقف والخطوة التي تمّت.يخلط بين الموضع الذي يتوقف فيه البرنامج، وهو ما يختاره مَن يصحّح الأخطاء، وسبب العطل.هذا جواب صادق: الدرس 8.3 يعالج نقاط التوقف والخطوات.يتوقف مصحّح الأخطاء قبل السطر المعلَّم؛ وقيمةtotalالتي يعرضها هي قيمة الجولتين الماضيتين. والخلط في ذلك يُنتج جداول تتبع مُزاحة بصفّ واحد. ويطوّر ذلك درس تصحيح أخطاء البرامج.راجِع: تصحيح أخطاء البرامج
جارٍ تحميل المحتوى…