الكلية الجامعية للعلوم التطبيقيةبرمجة 1
English
المحاضرة 10 · 100 دقيقة

حلقات for

كيف نكتب التكرار المعدود في سطر واحد، ونبني به الجداول والأشكال؟

في نهاية هذه المحاضرة ستكون قادرًا على

  1. تكتب حلقة for وتحوّلها إلى while مكافئة
  2. تعدّ تصاعديًا وتنازليًا وبخطوات مختلفة
  3. تشرح نطاق متغير الحلقة، وتختار بين for وwhile
  4. تتتبّع الحلقات المتداخلة بالمتتبّع، وتطبع بها الأشكال
  5. تفحص هل العدد أولي، وتستخدم break وcontinue
  6. تتجنب فخ الفاصلة المنقوطة وتعديل متغير الحلقة داخلها
محتويات المحاضرة
  1. for تجمع التهيئة والشرط والتحديث في سطر واحد
  2. كل حلقة for هي حلقة while بترتيب أنيق
  3. العدّ يكون تصاعديًا أو تنازليًا أو بأي خطوة نريدها
  4. متغير الحلقة المصرَّح عنه في for لا يعيش بعدها
  5. for للعدد المعروف، وwhile لما ينتهي بحدث
  6. المجموع يبدأ من 0، وحاصل الضرب يبدأ من 1
  7. جدول الضرب حلقة واحدة وسطر طباعة واحد
  8. في الحلقة المتداخلة، تكتمل الداخلية كلها في كل دورة من الخارجية
  9. print تبقى في السطر نفسه، وprintln تنهيه، فتصنعان شبكة
  10. المستطيل: عدد النجوم ثابت في كل صف
  11. المثلث: الحلقة الداخلية تعتمد على رقم الصف
  12. الهرم: حلقة للمسافات ثم حلقة للنجوم داخل كل صف
  13. العدد أولي إذا لم نجد له قاسمًا: نفترض ذلك، ثم نبحث عن دليل ينقضه
  14. break تنهي الحلقة، وcontinue تتخطى بقية الدورة
  15. فخان شائعان: فاصلة منقوطة بعد for، وتعديل متغير الحلقة داخلها
  16. أسئلة المراجعة
الجزء الأول: تشريح for

for تجمع التهيئة والشرط والتحديث في سطر واحد

التهيئة

تُنفَّذ مرة واحدة قبل كل شيء.

int i = 1
الشرط

يُفحص قبل كل دورة، تمامًا كما في while.

i <= 3
التحديث

يُنفَّذ بعد جسم الحلقة في كل دورة.

i++

أول حلقة for

توقّع الناتج، ثم شغّل. غيّر 3 إلى 6 وشغّل مجددًا. لاحظ أن الفواصل بين الأجزاء الثلاثة فاصلة منقوطة ;.

public class FirstFor {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++) {
            System.out.println("Hello " + i);
        }
        System.out.println("Done");
    }
}
الناتج
Hello 1
Hello 2
Hello 3
Done

فواصل منقوطة، لا فواصل عادية

أصلح سطر for ليطبع البرنامج 0 و1 و2.

public class ForCommas {
    public static void main(String[] args) {
        for (int i = 0, i < 3, i++) {
            System.out.println(i);
        }
    }
}
رسالة المترجم';' expected
أظهر التصحيح
public class ForCommas {
    public static void main(String[] args) {
        for (int i = 0; i < 3; i++) {
            System.out.println(i);
        }
    }
}
الناتج
0
1
2

لماذا؟ الأجزاء الثلاثة أوامر منفصلة، والفاصلة المنقوطة هي التي تفصل بينها. ولما رأى المترجم الفاصلة العادية ظن أنك تصرّح عن متغير آخر، فلم يفهم ما بعدها.

كل حلقة for هي حلقة while بترتيب أنيق

بالصيغة while
int i = 1;
while (i <= 3) {
    System.out.println(i);
    i++;
}
بالصيغة for
for (int i = 1; i <= 3; i++) {
    System.out.println(i);
}
  1. التهيئة مرة واحدة
  2. فحص الشرطإذا كان false انتهت الحلقة.
  3. تنفيذ الجسم
  4. التحديث، ثم العودة إلى فحص الشرط

شاهد الترتيب في المتتبّع

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

public class TraceFor {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++) {
            System.out.println(i);
        }
        System.out.println("Done");
    }
}
الناتج
1
2
3
Done

متى يُنفَّذ الجزء i++ في حلقة for؟

العدّ يكون تصاعديًا أو تنازليًا أو بأي خطوة نريدها

الهدفالسطرالقيم
تصاعديًاfor (int i = 1; i <= 5; i++)1 2 3 4 5
تنازليًاfor (int i = 5; i >= 1; i--)5 4 3 2 1
بخطوة 5for (int i = 0; i <= 20; i += 5)0 5 10 15 20
الأعداد الفرديةfor (int i = 1; i < 10; i += 2)1 3 5 7 9

ثلاث حلقات في برنامج واحد

نستخدم print لتبقى القيم على سطر واحد، ثم println() الفارغة لننتقل إلى السطر التالي. عدّل الحلقة الثالثة لتطبع مضاعفات 3 حتى 30.

public class Countings {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            System.out.print(i + " ");
        }
        System.out.println();

        for (int i = 5; i >= 1; i--) {
            System.out.print(i + " ");
        }
        System.out.println();

        for (int i = 0; i <= 20; i += 5) {
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
الناتج
1 2 3 4 5
5 4 3 2 1
0 5 10 15 20

تنازليًا بخطوة 3. ماذا يطبع البرنامج؟

public class DownByThree {
    public static void main(String[] args) {
        for (int i = 10; i > 0; i -= 3) {
            System.out.println(i);
        }
    }
}
أظهر الناتج
الناتج
10
7
4
1

لماذا؟ بعد 1 تصبح i مساوية -2، فيكون الشرط i > 0 قيمته false قبل الطباعة، ولذلك لا تظهر -2.

متغير الحلقة المصرَّح عنه في for لا يعيش بعدها

نطاق المتغير هو الجزء من البرنامج الذي يُعرف فيه اسمه. والمتغير المصرَّح عنه في سطر for يُعرف داخل الحلقة فقط، ولهذا تستطيع كل حلقة أن تصرّح عن i خاصة بها، كما رأيت في البرنامج Countings.

اسم لم يعد موجودًا

نريد طباعة قيمة i بعد انتهاء الحلقة. أصلح البرنامج حتى يطبع 1 و2 و3، ثم After: 4.

public class AfterLoop {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++) {
            System.out.println(i);
        }
        System.out.println("After: " + i);
    }
}
رسالة المترجمcannot find symbol
أظهر التصحيح
public class AfterLoop {
    public static void main(String[] args) {
        int i;
        for (i = 1; i <= 3; i++) {
            System.out.println(i);
        }
        System.out.println("After: " + i);
    }
}
الناتج
1
2
3
After: 4

لماذا؟ بعد القوس الأخير للحلقة لا وجود لـ i. فإذا احتجت إلى قيمته بعد الحلقة، فصرّح عنه قبلها.

الاسم نفسه مرتين

أصلح البرنامج ليطبع 5 ثم 0 و1، دون تغيير الأعداد.

public class TwoNames {
    public static void main(String[] args) {
        int i = 5;
        System.out.println(i);
        for (int i = 0; i < 2; i++) {
            System.out.println(i);
        }
    }
}
رسالة المترجمvariable i is already defined
أظهر التصحيح
public class TwoNames {
    public static void main(String[] args) {
        int total = 5;
        System.out.println(total);
        for (int i = 0; i < 2; i++) {
            System.out.println(i);
        }
    }
}
الناتج
5
0
1

لماذا؟ i الأولى ما زالت حية عند سطر for، فلا يمكن التصريح عن متغير آخر بالاسم نفسه داخل نطاقها. غيّر أحد الاسمين.

for للعدد المعروف، وwhile لما ينتهي بحدث

الموقفالأنسبمثال
عدد الدورات معروف قبل البدءforاطبع جدول ضرب 7
تتوقف الحلقة عند حدث ماwhileاقرأ حتى -1، أو حتى يصير العدد 0
يجب التنفيذ مرة على الأقلdo-whileاسأل حتى تكون الإجابة صحيحة

أي حلقة تناسب جمع أرقام عدد أدخله المستخدم؟

أي حلقة تناسب قراءة علامات 30 طالبًا بالضبط؟

الجزء الثاني: المجاميع والحلقات المتداخلة

المجموع يبدأ من 0، وحاصل الضرب يبدأ من 1

المجموع وحاصل الضرب معًا

تتبّع البرنامج وراقب الصندوقين sum وproduct. غيّر 5 إلى 10 وتوقّع أيهما سيكبر أسرع. لماذا اخترنا long لحاصل الضرب؟

public class SumAndProduct {
    public static void main(String[] args) {
        int sum = 0;
        long product = 1;
        for (int i = 1; i <= 5; i++) {
            sum += i;
            product *= i;
        }
        System.out.println("Sum: " + sum);
        System.out.println("Product: " + product);
    }
}
الناتج
Sum: 15
Product: 120

مجموع الأعداد الزوجية

اقرأ عددًا n، ثم اطبع مجموع الأعداد الزوجية من 2 إلى n. لا تطبع نصًا آخر. إذا كان n أصغر من 2 فالناتج 0.

import java.util.Scanner;

public class SumOfEvens {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Add the even numbers from 2 to n, then print the sum

    }
}
stdin
10
الناتج المتوقع
30
تلميح 1

يمكنك أن تبدأ من 2 وتزيد بخطوة 2، فلا تحتاج إلى if.

تلميح 2

سطر الحلقة: for (int i = 2; i <= n; i += 2).

الحل
import java.util.Scanner;

public class SumOfEvens {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        int sum = 0;
        for (int i = 2; i <= n; i += 2) {
            sum += i;
        }
        System.out.println(sum);
    }
}

جدول الضرب حلقة واحدة وسطر طباعة واحد

اختر عددًا

شغّل البرنامج وأدخل عددًا بنفسك، ثم عدّل الحلقة لتطبع الجدول تنازليًا من 10 إلى 1.

import java.util.Scanner;

public class TimesTable {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.print("Number: ");
        int n = input.nextInt();
        for (int i = 1; i <= 10; i++) {
            System.out.println(n + " x " + i + " = " + n * i);
        }
    }
}

الأقواس والدمج من المحاضرات السابقة. ماذا يطبع البرنامج؟

public class TimesTrap {
    public static void main(String[] args) {
        for (int i = 1; i <= 2; i++) {
            System.out.println("Result: " + 3 + i);
            System.out.println("Result: " + (3 + i));
        }
    }
}
أظهر الناتج
الناتج
Result: 31
Result: 4
Result: 32
Result: 5

لماذا؟ دون أقواس يصبح "Result: " + 3 نصًا فتُلصق به i. ومع الأقواس تُجمع 3 + i أولًا. أما n * i في البرنامج السابق فلا تحتاج إلى أقواس، لأن الضرب يسبق +.

جدول الضرب

اقرأ عددًا n دون طباعة رسالة طلب إدخال، ثم اطبع جدول ضربه من 1 إلى 10 بالشكل 3 x 1 = 3.

import java.util.Scanner;

public class TimesExercise {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Print ten lines

    }
}
stdin
3
الناتج المتوقع
3 x 1 = 3
3 x 2 = 6
3 x 3 = 9
3 x 4 = 12
3 x 5 = 15
3 x 6 = 18
3 x 7 = 21
3 x 8 = 24
3 x 9 = 27
3 x 10 = 30
تلميح 1

راقب المسافات: n + " x " + i + " = " + n * i.

الحل
import java.util.Scanner;

public class TimesExercise {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        for (int i = 1; i <= 10; i++) {
            System.out.println(n + " x " + i + " = " + n * i);
        }
    }
}

في الحلقة المتداخلة، تكتمل الداخلية كلها في كل دورة من الخارجية

فكّر في الساعة: عقرب الدقائق يدور دورة كاملة كلما تقدّم عقرب الساعات خطوة واحدة. الحلقة الخارجية هي عقرب الساعات، والداخلية هي عقرب الدقائق.

تتبّع i وj

اضغط «تتبّع سطرًا سطرًا»، ثم «السطر التالي» مرات كثيرة. قبل كل ضغطة توقّع قيمتي i وj. لاحظ أن j تبدأ من 1 من جديد في كل مرة تتغير فيها i. ثم غيّر 3 إلى 2 واحسب عدد الأسطر قبل التشغيل.

public class NestedTrace {
    public static void main(String[] args) {
        for (int i = 1; i <= 2; i++) {
            for (int j = 1; j <= 3; j++) {
                System.out.println("i=" + i + " j=" + j);
            }
            System.out.println("end of i=" + i);
        }
    }
}
الناتج
i=1 j=1
i=1 j=2
i=1 j=3
end of i=1
i=2 j=1
i=2 j=2
i=2 j=3
end of i=2
iقيم j في هذه الدورةj عند انتهاء الداخليةأسطر الطباعة
11 2 343 + 1
21 2 343 + 1

كم مرة يُنفَّذ السطر count++؟

for (int i = 0; i < 4; i++) {
    for (int k = 0; k < 5; k++) {
        count++;
    }
}

print تبقى في السطر نفسه، وprintln تنهيه، فتصنعان شبكة

هذا هو سر كل الأشكال القادمة: الحلقة الداخلية تكتب سطرًا واحدًا بالأمر print، وprintln() بعدها تنهيه، والحلقة الخارجية تكرر السطور.

شبكة جدول الضرب

نستخدم \t لتصطف الأعمدة. تتبّع صفًا واحدًا فقط، ثم اضغط «متابعة». بعدها كبّر الشبكة إلى 5 صفوف و5 أعمدة، ثم احذف println() وشاهد ما يحدث.

public class MultiplicationGrid {
    public static void main(String[] args) {
        for (int row = 1; row <= 3; row++) {
            for (int col = 1; col <= 4; col++) {
                System.out.print(row * col + "\t");
            }
            System.out.println();
        }
    }
}
الناتج
1	2	3	4
2	4	6	8
3	6	9	12

نقلنا println إلى داخل الحلقة الداخلية. ماذا يطبع البرنامج؟

public class InnerPrintln {
    public static void main(String[] args) {
        for (int row = 1; row <= 2; row++) {
            for (int col = 1; col <= 2; col++) {
                System.out.print("*");
                System.out.println();
            }
        }
    }
}
أظهر الناتج
الناتج
*
*
*
*

لماذا؟ تنفَّذ println() بعد كل نجمة، فتحصل كل نجمة على سطر خاص بها، أي 2 × 2 = 4 أسطر. مكان println هو ما يقرر شكل الناتج.

الجزء الثالث: الأشكال والأعداد الأولية والتحكم في الحلقة

المستطيل: عدد النجوم ثابت في كل صف

  1. كم صفًا؟هذا عدد دورات الحلقة الخارجية.
  2. كم نجمة في الصف رقم row؟هذا شرط الحلقة الداخلية، وهو السؤال المفتاح في كل شكل.
  3. أنهِ كل صف بالأمر println()

مستطيل من النجوم

توقّع الشكل قبل التشغيل. ثم عدّله ليصير صفين و7 أعمدة، وبعدها غيّر النجمة إلى #.

public class Rectangle {
    public static void main(String[] args) {
        for (int row = 1; row <= 3; row++) {
            for (int col = 1; col <= 5; col++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
الناتج
*****
*****
*****

المثلث: الحلقة الداخلية تعتمد على رقم الصف

الفرق الوحيد عن المستطيل أن شرط الحلقة الداخلية صار col <= row بدل عدد ثابت: الصف 1 فيه نجمة، والصف 2 فيه نجمتان، وهكذا.

مثلث قائم

تتبّع الصفين الأولين وراقب عدد دورات الحلقة الداخلية. ثم اطبع رقم الصف row بدل النجمة، وبعدها اطبع col: ما الفرق؟

public class Triangle {
    public static void main(String[] args) {
        for (int row = 1; row <= 4; row++) {
            for (int col = 1; col <= row; col++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
الناتج
*
**
***
****

مثلث مقلوب

اقرأ عددًا n، ثم اطبع مثلثًا مقلوبًا: n نجوم في الصف الأول، وتنقص نجمة في كل صف حتى نجمة واحدة. لا تطبع نصًا آخر.

import java.util.Scanner;

public class InvertedTriangle {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // Print the triangle using two nested for loops

    }
}
stdin
4
الناتج المتوقع
****
***
**
*
تلميح 1

اجعل الحلقة الخارجية تنازلية: row تبدأ من n وتنتهي عند 1.

تلميح 2

يبقى عدد النجوم في الصف مساويًا لقيمة row.

الحل
import java.util.Scanner;

public class InvertedTriangle {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        for (int row = n; row >= 1; row--) {
            for (int col = 1; col <= row; col++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

الهرم: حلقة للمسافات ثم حلقة للنجوم داخل كل صف

الصف rowالمسافات n - rowالنجوم 2 * row - 1
131
223
315
407

الهرم

تتبّع الصف الأول فقط، ثم اضغط «متابعة». غيّر n إلى 6. ثم احذف حلقة المسافات واشرح الشكل الناتج.

public class Pyramid {
    public static void main(String[] args) {
        int n = 4;
        for (int row = 1; row <= n; row++) {
            for (int s = 1; s <= n - row; s++) {
                System.out.print(" ");
            }
            for (int star = 1; star <= 2 * row - 1; star++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}
الناتج
   *
  ***
 *****
*******

مثلث إلى اليمين

اقرأ n واطبع مثلثًا ملاصقًا لليمين: الصف رقم row فيه n - row مسافة، ثم row نجمة. لا تطبع نصًا آخر.

import java.util.Scanner;

public class RightAligned {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // One outer loop, with two loops inside it

    }
}
stdin
3
الناتج المتوقع
  *
 **
***
تلميح 1

انسخ هيكل الهرم، وغيّر عدد النجوم فقط.

تلميح 2

شرط حلقة النجوم هو star <= row.

الحل
import java.util.Scanner;

public class RightAligned {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        for (int row = 1; row <= n; row++) {
            for (int s = 1; s <= n - row; s++) {
                System.out.print(" ");
            }
            for (int star = 1; star <= row; star++) {
                System.out.print("*");
            }
            System.out.println();
        }
    }
}

العدد أولي إذا لم نجد له قاسمًا: نفترض ذلك، ثم نبحث عن دليل ينقضه

العدد الأولي أكبر من 1 ولا يقبل القسمة إلا على 1 وعلى نفسه. النمط هو المتغير الراية: boolean نفترض قيمته true، ونغيّره إلى false عند أول دليل.

افحص العدد

تتبّع البرنامج وراقب i وprime. ثم غيّر n إلى 21 وتتبّعه مجددًا: عند أي قيمة لـ i يتغير prime؟ وهل تفيد بقية الدورات بعد ذلك؟ سنعود إلى هذا السؤال في القسم التالي.

public class PrimeCheck {
    public static void main(String[] args) {
        int n = 7;
        boolean prime = n > 1;
        for (int i = 2; i < n; i++) {
            if (n % i == 0) {
                prime = false;
            }
        }
        System.out.println(n + " prime? " + prime);
    }
}
الناتج
7 prime? true

الأعداد الأولية حتى n

اقرأ n واطبع الأعداد الأولية من 2 إلى n في سطر واحد، بعد كل عدد مسافة. ستحتاج إلى حلقة خارجية للأعداد، وحلقة داخلية تفحص كل عدد.

import java.util.Scanner;

public class PrimesUpTo {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        // For each number from 2 to n, check it, then print it if it is prime

        System.out.println();
    }
}
stdin
10
الناتج المتوقع
2 3 5 7
تلميح 1

صرّح عن boolean prime = true; داخل الحلقة الخارجية، لتعود إلى true مع كل عدد جديد.

تلميح 2

اختر للحلقة الداخلية اسمًا آخر مثل d، فالقاسم غير العدد المفحوص.

الحل
import java.util.Scanner;

public class PrimesUpTo {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        int n = input.nextInt();
        for (int number = 2; number <= n; number++) {
            boolean prime = true;
            for (int d = 2; d < number; d++) {
                if (number % d == 0) {
                    prime = false;
                }
            }
            if (prime) {
                System.out.print(number + " ");
            }
        }
        System.out.println();
    }
}

break تنهي الحلقة، وcontinue تتخطى بقية الدورة

توقف عند أول دليل

هذا جواب سؤال القسم السابق: بعد العثور على قاسم لا فائدة من البحث. تتبّع البرنامج ولاحظ أن الحلقة تنتهي عند i = 3، دون أن تكمل حتى 20. احذف break وتتبّعه مجددًا لتقارن.

public class PrimeBreak {
    public static void main(String[] args) {
        int n = 21;
        boolean prime = n > 1;
        for (int i = 2; i < n; i++) {
            if (n % i == 0) {
                prime = false;
                System.out.println("Divisor: " + i);
                break;
            }
        }
        System.out.println(n + " prime? " + prime);
    }
}
الناتج
Divisor: 3
21 prime? false

continue تقفز إلى التحديث مباشرة. ماذا يطبع البرنامج؟

public class ContinueSkip {
    public static void main(String[] args) {
        for (int i = 1; i <= 5; i++) {
            if (i == 3) {
                continue;
            }
            System.out.print(i + " ");
        }
        System.out.println();
        for (int i = 1; i <= 5; i++) {
            if (i == 3) {
                break;
            }
            System.out.print(i + " ");
        }
        System.out.println();
    }
}
أظهر الناتج
الناتج
1 2 4 5
1 2

لماذا؟ continue تتخطى طباعة 3 وتكمل الحلقة بالتحديث. أما break فتنهي الحلقة كلها عند 3، فلا يُطبع بعدها شيء.

int i = 1;
while (i <= 5) {
    if (i == 3) {
        continue;
    }
    System.out.println(i);
    i++;
}
تنبيه: في while تقفز continue إلى الشرط، فإذا جاء التحديث بعدها لم يتغير i وصارت الحلقة لا نهائية. اكتب هذا الجزء داخل main في المختبر السابق بدل أسطرها الحالية، ثم اضغط «إيقاف».

للاطلاع: break المسمّاة

break العادية تخرج من الحلقة الداخلية فقط. وإذا أردت الخروج من الحلقتين معًا، فضع اسمًا قبل الخارجية. احذف الاسم outer من سطر break وقارن الناتج. قلّما نحتاج إلى هذا.

public class LabelledBreak {
    public static void main(String[] args) {
        outer:
        for (int i = 1; i <= 3; i++) {
            for (int k = 1; k <= 3; k++) {
                if (i * k == 4) {
                    break outer;
                }
                System.out.println(i + " x " + k);
            }
        }
    }
}
الناتج
1 x 1
1 x 2
1 x 3
2 x 1

فخان شائعان: فاصلة منقوطة بعد for، وتعديل متغير الحلقة داخلها

انظر جيدًا إلى آخر سطر for. كم مرة تُطبع Hello؟

public class SemicolonTrap {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++);
        {
            System.out.println("Hello");
        }
    }
}
أظهر الناتج
الناتج
Hello

لماذا؟ الفاصلة المنقوطة هي جسم الحلقة: أمر فارغ يتكرر 3 مرات. أما القوسان بعدها فليسا من الحلقة، فتُطبع Hello مرة واحدة دون أي رسالة من المترجم.

رسالة تبدو بعيدة عن السبب

الرسالة تشكو من i، لكن i مصرَّح عنها أمامك. أين الخطأ؟

public class SemicolonError {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++);
        {
            System.out.println(i);
        }
    }
}
رسالة المترجمcannot find symbol
أظهر التصحيح
public class SemicolonError {
    public static void main(String[] args) {
        for (int i = 1; i <= 3; i++) {
            System.out.println(i);
        }
    }
}
الناتج
1
2
3

لماذا؟ الفاصلة المنقوطة أنهت الحلقة، فانتهى معها نطاق i، وصار سطر الطباعة خارج الحلقة. لذلك لا يعرف المترجم i هناك، مع أن السبب الحقيقي في السطر الذي قبله.

نزيد i داخل الجسم أيضًا. ماذا يطبع البرنامج؟

public class ModifyLoopVar {
    public static void main(String[] args) {
        for (int i = 0; i < 6; i++) {
            System.out.println(i);
            i++;
        }
    }
}
أظهر الناتج
الناتج
0
2
4

لماذا؟ تزيد i مرتين في كل دورة: مرة في الجسم ومرة في التحديث، فتتخطى الأعداد الفردية. ومن يقرأ سطر for وحده يظن أن الحلقة تدور 6 مرات.

أسئلة المراجعة

كم مرة يدور جسم الحلقة for (int i = 3; i < 15; i += 3)؟

داخل حلقتين متداخلتين، من أي حلقة تُخرجك break العادية؟

ما شرط الحلقة الداخلية الذي يجعل الشكل مثلثًا لا مستطيلًا؟

تتبّع على الورق، ثم تأكد بالمتتبّع. ماذا يطبع البرنامج؟

public class ReviewNested {
    public static void main(String[] args) {
        int total = 0;
        for (int i = 1; i <= 3; i++) {
            for (int k = 1; k <= i; k++) {
                total += k;
            }
        }
        System.out.println(total);
    }
}
أظهر الناتج
الناتج
10

لماذا؟ عند i = 1 نضيف 1، وعند i = 2 نضيف 1 + 2، وعند i = 3 نضيف 1 + 2 + 3. والمجموع 1 + 3 + 6 = 10.