📘 شرح الدرس الوحدة 6: قراءة الأخطاء وتصحيحها · الدرس 16 من 17
الدرس 16
📋 في الخطة: الوحدة 12. تصحيح الأخطاء والوقاية منها

تصحيح الأخطاء والوقاية منها

نتتبّع البرنامج خطوة بخطوة لنجد مصدر المشكلة، ونصحّحها، ونتعلّم ممارسات تقلّل الأخطاء من البداية.

12345 continue 12345 STOPbreak
بعد هذا الدرس ستستطيع أن:
  • تتبع منهجية من خمس خطوات لتصحيح الأخطاء.
  • تتتبّع تنفيذ البرنامج خطوة بخطوة بجدول التتبّع لتحديد مصدر المشكلة.
  • تعدّل البرنامج لتصحيح الخطأ ثم تعيد اختباره بجدول حالات.
  • تطبّق ممارسات برمجة جيدة تقلل حدوث الأخطاء.

١منهجية التصحيح: خمس خطوات

التصحيح العشوائي، أي تغيير الكود على أمل أن يعمل، يضيّع الوقت وقد يضيف أخطاء جديدة. المبرمج المنظّم يتبع خطوات ثابتة:

الخطوةماذا تفعل؟
١. أعِد إنتاج الخطأحدّد المدخلات التي تُظهر الخطأ بثبات. خطأ لا تستطيع تكراره لا تستطيع إصلاحه.
٢. حدّد المكاناقرأ رسالة الخطأ، أو استخدم الطباعة ونقاط التوقف لتضييق المكان إلى سطر أو بضعة أسطر.
٣. افهم السببلماذا حدث؟ لا تكتفِ بإخفاء العَرَض. مثلًا: لماذا أصبح المقسوم عليه صفرًا؟
٤. أصلحعدّل أقل قدر ممكن من الكود، وتغييرًا واحدًا في كل مرة.
٥. أعِد الاختبارجرّب المدخلات التي أظهرت الخطأ، ثم بقية الحالات للتأكد أنك لم تُفسد شيئًا آخر.

٢تتبّع التنفيذ خطوة بخطوة

البرنامج التالي يجب أن يعدّ الأعداد الزوجية من 1 إلى 6، ويطبع 3، وهو فعلًا يطبع 3! هل هو صحيح؟ تتبّعه خطوة بخطوة:

🔎 تتبّع: عدّ الأعداد الزوجية
snippet
int count = 0;for (int i = 1; i <= 6; i++) {    if (i % 2 == 1)        count++;}System.out.println("عدد الزوجيات = " + count);
Variables · المتغيّرات في الذاكرة
Output×

الدرس المهم: نتيجة صحيحة مع مدخلات واحدة لا تعني أن البرنامج صحيح. جرّب الحدّ 7 بدل 6: الصحيح 3 زوجيات، والبرنامج يطبع 4.

جدول التتبّع اليدوي Dry Run

بدون حاسب نستطيع تتبّع البرنامج بجدول: عمود لكل متغير وعمود للشرط وعمود للناتج. هذه أقوى أداة تصحيح لأنها تجبرك على التفكير مثل الحاسب.

ii % 2الشرط i % 2 == 1count
11true1
20false1
31true2
40false2
51true3
60false3

الجدول يكشف فورًا أن count يزيد مع 1 و 3 و 5، أي الفرديات. الإصلاح: i % 2 == 0.

٣مثال كامل: تصحيح برنامج الفاتورة

المطلوب: اقرأ السعر والكمية، فإذا كان الإجمالي 1000 فأكثر يحصل العميل على خصم 10%. والسعر والكمية يجب أن يكونا أكبر من صفر.

١. نختبر بجدول حالات

المدخلاتالمتوقعالناتج الفعليالحكم
100 و 5الإجمالي: 500.0الإجمالي: 500.0✓
250 و 4الإجمالي: 900.0الإجمالي: 1000.0✗
300 و 4الإجمالي: 1080.0الإجمالي: 1080.0✓
-50 و 2قيمة غير صحيحةالإجمالي: -100.0✗
Main.java
import java.util.Scanner;public class Main {    public static void main(String[] args) {        Scanner in = new Scanner(System.in);        double price = in.nextDouble();        int qty = in.nextInt();        double total = price * qty;        double discount = 0;        if (total > 1000)            discount = total * 0.1;        total = total - discount;        System.out.println("الإجمالي: " + total);    }}

٢. نحدد المكان ونفهم السبب

٣. نصلح ثم نعيد الاختبار

Main.java
import java.util.Scanner;public class Main {    public static void main(String[] args) {        Scanner in = new Scanner(System.in);        double price = in.nextDouble();        int qty = in.nextInt();        if (price <= 0 || qty <= 0) {            System.out.println("قيمة غير صحيحة");            return;        }        double total = price * qty;        double discount = 0;        if (total >= 1000)            discount = total * 0.1;        total = total - discount;        System.out.println("الإجمالي: " + total);    }}
Output – JavaApplication (run)×
run:
250
4
الإجمالي: 900.0
BUILD SUCCESSFUL (total time: 0 seconds)
Main.java
import java.util.Scanner;public class Main {    public static void main(String[] args) {        Scanner in = new Scanner(System.in);        double price = in.nextDouble();        int qty = in.nextInt();        if (price <= 0 || qty <= 0) {            System.out.println("قيمة غير صحيحة");            return;        }        double total = price * qty;        double discount = 0;        if (total >= 1000)            discount = total * 0.1;        total = total - discount;        System.out.println("الإجمالي: " + total);    }}
Output – JavaApplication (run)×
run:
-50
2
قيمة غير صحيحة
BUILD SUCCESSFUL (total time: 0 seconds)

أعدنا تشغيل كل حالات الجدول، فأصبحت كلها ✓. الكلمة return داخل main تنهي البرنامج مبكرًا.

٤الوقاية: ممارسات البرمجة الجيدة

أفضل خطأ هو الذي لا يحدث. هذه الممارسات تقلل الأخطاء وتجعل اكتشافها أسهل:

الممارسةبدلًا منالأفضل
أسماء واضحةdouble x = a * b;double total = price * qty;
تنسيق ومسافات بادئةكود متلاصق غير مرتبAlt + Shift + F في NetBeans
ثوابت بدل الأرقام السحريةtotal * 0.15final double VAT = 0.15;
دوال صغيرةmain طويلة من 100 سطردالة لكل مهمة، كما في التفكيك
التحقق من المدخلاتالقسمة مباشرةif (count != 0) قبل القسمة
البناء التدريجيكتابة البرنامج كاملًا ثم تشغيلهاكتب جزءًا صغيرًا وشغّله، ثم أضف
تعليقات مفيدةi++; // زيادة iتعليق يشرح السبب لا الواضح

التحقق من المدخلات قبل القراءة

الدالة hasNextInt() تخبرنا هل ما كتبه المستخدم رقم صحيح قبل قراءته، فنتجنب InputMismatchException:

snippet
Scanner in = new Scanner(System.in);System.out.println("ادخل عمرك:");while (!in.hasNextInt()) {    System.out.println("أدخل رقمًا صحيحًا من فضلك:");    in.next();          // تجاهل الإدخال الخاطئ}int age = in.nextInt();System.out.println("عمرك " + age);
Output – JavaApplication (run)×
run:
ادخل عمرك:
عشرون
أدخل رقمًا صحيحًا من فضلك:
20
عمرك 20
BUILD SUCCESSFUL (total time: 0 seconds)

٥قائمة فحص قبل تسليم أي برنامج

توقّع وتحقّق

ما أول خطوة في منهجية التصحيح؟

لا نستطيع إصلاح خطأ لا نستطيع تكراره.

برنامج أعطى نتيجة صحيحة مع مدخل واحد. هذا يعني:

نختبر عدة حالات، خصوصًا الحدّية.

ما فائدة hasNextInt()؟

تمنع InputMismatchException.

أي اسم متغير أفضل لمجموع الفاتورة؟

الاسم الواضح يقلل الأخطاء.

الخلاصة

تحدٍّ برمجي: أصلح حاسبة المعدل

متقدم

البرنامج يقرأ عدد المواد ثم درجاتها ويطبع المعدل، لكنه يعطي نتيجة خاطئة، ويتوقف إذا كان عدد المواد صفرًا.

المطلوب:
  • استخدم جدول تتبّع أو الطباعة التشخيصية لإيجاد الخطأ المنطقي.
  • أضف تحققًا يمنع القسمة على صفر ويطبع: لا توجد مواد
  • مع المدخلات 3 ثم 80 90 70 يجب أن يطبع: المعدل = 80.0

ابدأ من هذا الكود، واضغط ▶ شغّل هنا لتكتب حلّك وتجرّبه مباشرة:

Main.java
import java.util.Scanner;public class Main {    public static void main(String[] args) {        Scanner in = new Scanner(System.in);        int n = in.nextInt();        int sum = 0;        for (int i = 1; i < n; i++) {            sum = sum + in.nextInt();        }        double avg = sum / n;        System.out.println("المعدل = " + avg);    }}
Output – المطلوب×
المعدل = 80.0
💡 تلميح 1
كم مرة تتكرر الحلقة عندما n = 3؟
💡 تلميح 2
sum / n قسمة صحيحة؛ استخدم (double) sum / n. وضع الشرط if (n == 0) قبل الحلقة.

حاول بنفسك أولًا؛ للمسألة أكثر من حلّ صحيح.

Main.java
import java.util.Scanner;public class Main {    public static void main(String[] args) {        Scanner in = new Scanner(System.in);        int n = in.nextInt();        if (n == 0) {            System.out.println("لا توجد مواد");            return;        }        int sum = 0;        for (int i = 1; i <= n; i++) {            sum = sum + in.nextInt();        }        double avg = (double) sum / n;        System.out.println("المعدل = " + avg);    }}
انتقل إلى تقييم الدرسأسئلة الاختيار، وصح وخطأ، وأكمل الفراغات، والأسئلة العملية.ابدأ التقييم ←