اذهب إلى المحتوى

تُعتبر الحلقات التكراريّة من البنى المهمّة في لغات البرمجة، حيث نستطيع من خلالها تنفيذ عبارة أو عدّة عبارات برمجيّة لعدد من المرّات. تدعم سي شارب مثل باقي لغات البرمجة نوعين من الحلقات التكراريّة من حيث عدد التكرار، فهناك الحلقات ذات العدد المحدّد من المرّات (حلقة for) والتي نعلم فيها عدد مرّات التكرار بشكل مسبق، والحلقات ذات العدد غير المحدّد من المرّات (حلقة do-while وحلقة while) التي يكون فيها عدد مرّات التكرار غير مُحدّدًا.

learn-csharp-loops-for-while.png

حلقة for التكرارية

يمكن من خلال هذه الحلقة تكرار تنفيذ عبارة برمجيّة أو أكثر عددًا محدّدًا من المرّات، ولهذه الحلقة الشكل العام التالي:

for ([init_counter]; [loop_condition]; [counter_expression])
{
    statement1;
    statement2;
    ...
}

القسم [init_counter] هو قسم التهيئة الذي يتمّ من خلاله تهيئة متغيّر الحلقة بقيمة ابتدائيّة (وغالبًا ما يتمّ التصريح عنه في هذا القسم أيضًا)، يسمّى متغيّر الحلقة أيضًا بعدّاد الحلقة loop counter، أمّا القسم [loop_condition] فيمثّل شرط التكرار أو الاستمرار للحلقة، فهو تعبير مقارنة يعطي true أو false بحيث تستمرّ الحلقة بالتكرار طالما كان هذا الشرط محقّقًا (يعطي true). القسم الأخير [counter_expression] ويتمّ فيه عادةً إجراء عملية حسابية على متغيّر الحلقة وغالبًا ما تكون هذه العمليّة هي زيادة متغيّر الحلقة بمقدار واحد. انظر الشيفرة البسيطة التالية التي تعمل على تنفيذ العبارة التي تحوي التابع WriteLine ثلاث مرّات:

for (int i = 0; i < 3; i++)
{
    Console.WriteLine("i = {0}", i);
}

عند تنفيذ الشيفرة السابقة ستحصل على الخرج التالي:

i = 0
i = 1
i = 2

لاحظ أنّنا صرّحنا عن المتغيّر i من النوع int وأسندنا إليها القيمة 0 في قسم التهيئة، وبالنسبة لشرط الاستمرار للحلقة i < 3 فمن الواضح أنّ الحلقة ستستمرّ بالتكرار طالما كانت قيمة i أصغر تمامًا من 3. أمّا بالنسبة للقسم الأخير فنعمل على زيادة قيمة متغيّر الحلقة i بمقدار 1 في كلّ دورة عن طريق عامل الزيادة اللاحق ++i.

آلية عمل هذه الحلقة بسيطة:

  1. عندما يصل تنفيذ البرنامج إلى حلقة for يتمّ التصريح عن المتغيّر i وإسناد القيمة 0 إليه.
  2. يختبر البرنامج شرط استمرار الحلقة i < 3 فإذا كان true يبدأ بتنفيذ العبارات البرمجيّة الموجودة ضمن حاضنة for. وإلّا يخرج فورًا من الحلقة.
  3. بعد الانتهاء من تنفيذ العبارات ضمن حاضنة for، ينتقل البرنامج إلى التعبير ++i ليزيد قيمة i بمقدار 1.
  4. تتكرّر نفس الخطوتين 2 و 3.

سيتكرّر في هذا المثال البسيط تنفيذ العبارة الموجودة في الحاضنة ثلاث مرّات لأنّ العدّ يبدأ من الصفر (قيمة i الابتدائيّة تساوي الصفر).

لنتناول الآن برنامجًا عمليًّا وظيفته إيجاد مجموع سلسلة من الأعداد المتتالية. أنشئ برنامجًا جديدًا اسمه Lesson04_1 ثمّ استبدل محتويات الملف Program.cs بالشيفرة التالية:

1   using System;
2
3   namespace Lesson04_1
4   {
5       class Program
6       {
7           static void Main(string[] args)
8           {
9               int n, sum = 0;
10              string str_n;
11
12              Console.WriteLine("This Program calculates the series: sum = 1 + 2 + 3 + ... + n");
13              Console.Write("Input 'n' please: ");
14              str_n = Console.ReadLine();
15
16              n = int.Parse(str_n);
17
18              for (int i = 1; i <= n; i++)
19              {
20                  sum += i;
21              }
22
23              Console.WriteLine("sum = {0}", sum);
24          }
25      }
26  }

يعمل البرنامج السابق على جمع الأعداد من 1 حتى القيمة المدخلة n. أي سيحسب برنامجنا مجموع السلسلة: 1 + 2 + 3 + … + n. لاحظ القيمة الابتدائيّة للمتغيّر i (تساوي 1) وشرط استمرار الحلقة i <= n في السطر 18. تذكّر أنّ العبارة الموجودة في السطر 20 تُكافئ العبارة sum = sum + i.

نفّذ البرنامج وجرّب إدخال قيم مختلفة للمتغيّر n لتحصل على المجاميع الموافقة.

ملاحظة: المتغيّر i في البرنامج السابق مرئي فقط ضمن الحلقة التكراريّة ولا وجود له خارجها، يعرف هذا بمجال الرؤية للمتغيّر variable scope. ستؤدّي محاولة الوصول للمتغيّر i خارج الحلقة إلى خطأ أثناء بناء البرنامج.

سنكتب الآن برنامجًا آخرًا لحساب مجموع السلسلة: 2 + 4 + 6 + 8 + … + n. لن يختلف البرنامج في هذا المثال عن البرنامج Lesson04_1 باستثناء أنّنا سنجمع الأعداد الزوجية فقط. إليك البرنامج كما سيبدو:

1   using System;
2
3   namespace Lesson04_2
4   {
5       class Program
6       {
7           static void Main(string[] args)
8           {
9               int n, sum = 0;
10              string str_n;
11
12              Console.WriteLine("This Program calculates the series: sum = 2 + 4 + 6 + ... + n");
13              Console.Write("Input 'n' please: ");
14              str_n = Console.ReadLine();
15
16              n = int.Parse(str_n);
17
18              for(int i = 0; i <= n; i += 2)
19              {
20                  sum += i;
21              }
22 
23              Console.WriteLine("sum = {0}", sum);
24          }
25      }
26  }

لاحظ كيف نزيد قيمة المتغيّر i في كلّ تكرار للحلقة for بمقدار 2 باستخدام التعبير i += 2 (السطر 18)، وبالتالي نتفادى جمع الأعداد الفردية (لاحظ أنّ قيمة i بدأت من الصفر). فيما عدا ذلك يبدو هذا البرنامج مطابقًا لبنية البرنامج Lesson04_1.

حلقة while التكرارية

لهذه الحلقة التكراريّة الشكل العام التالي:

while (loop_condition)
{
    statement1;
    statement2;
    ...
}

ستتكرّر العبارات البرمجيّة الموجودة ضمن حاضنة while طالما كان الشرط loop_condition محقّقًا (أي true) وبمجرّد أن يصبح الشرط loop_condition غير محقّق تتوقّف الحلقة عن التكرار.

سنعدّل البرنامج Lesson04_1 السابق لكي يسمح باستخدام الحلقة while. أنشئ مشروعًا جديدًا وسمّه Lesson04_3 ثم استبدل محتويات Program.cs بما يلي:

1   using System;
2
3   namespace Lesson04_3
4   {
5       class Program
6       {
7           static void Main(string[] args)
8           {
9               int n, sum = 0, i = 1;
10              string str_n;
11 
12              Console.WriteLine("This Program calculates the series: sum = 1 + 2 + 3 + ... + n");
13              Console.Write("Input 'n' please: ");
14              str_n = Console.ReadLine();
15
16              n = int.Parse(str_n);
17
18              while (i <= n)
19              {
20                  sum += i;
21
22                  i++;
23              }
24
25              Console.WriteLine("sum = {0}", sum);
26          }
27      }
28  }

صرّحنا عن المتغيّر i وأسندنا له القيمة 1 في السطر 9 والذي سيمثّل متغيّر حلقة while. استبدلنا حلقة for بحلقة while في السطر 18 مع ملاحظة أنّ شرط استمرار الحلقة i <= 5 بقي دون تعديل. لاحظ العبارة المهمّة في السطر 22 والتي تحوي التعبير ++i الذي سيزيد قيمة i بمقدار واحد في كلّ دورة. إنّ إغفال هذه العبارة سيؤدّي إلى الدخول في حلقة لا نهائيّة، لأنّ شرط الاستمرار في هذه الحالة لن يعطي false أبدًا لأنّ قيمة i لن تتغيّر.

نفّذ البرنامج وأدخل قيم مختلفة للمتغيّر n لاختبار البرنامج. جرّب الآن إدخال القيمة 0 للمتغيّر n ستحصل في الخرج على المجموع sum = 0 وهذا منطقيّ. إذ أنّنا نخبر البرنامج بأنّنا لا نريد جمع أي عدد. سبب الحصول على هذا الخرج في الواقع هو أنّ البرنامج أثناء التنفيذ لن يدخل إلى حلقة while مطلقًا لأنّ شرط الاستمرار i <= n سيكون غير محقّقًا منذ البداية (تذكّر أنّ قيمة i الابتدائيّة هي 1).

حلقة do-while التكرارية

لهذه الحلقة الشكل العام التالي:

do
{
    statement1;
    statement2;
    ...
}

while (loop_condition)

وهي تشبه الحلقة while باستثناء أنّ شرط استمرار الحلقة loop_condition يجري اختباره في نهايتها وليس في بدايتها كما هو الحال مع حلقة while. قد لا يبدو هذا الأمر مهمًّا في البداية ولكنّه في الحقيقة عكس ذلك تمامًا. لفهم الفرق أنشئ مشروعًا جديدًا وسمّه Lesson04_04 ثمّ استبدل الشيفرة الموجودة في Program.cs بالشيفرة التالية:

1   using System;
2
3   namespace Lesson04_4
4   {
5       class Program
6       {
7           static void Main(string[] args)
8           {
9               int n, sum = 0, i = 1;
10              string str_n;
11
12              Console.WriteLine("This Program calculates the series: sum = 1 + 2 + 3 + ... + n");
13              Console.Write("Input 'n' please: ");
14              str_n = Console.ReadLine();
15
16              n = int.Parse(str_n);
17
18              Do
19              {
20                  sum += i;
21 
22                  i++;
23              }
24              while (i <= n);
25 
26              Console.WriteLine("sum = {0}", sum);
27          }
28      }
29  }

لا يختلف هذا البرنامج عن سابقيه في حساب مجموع السلسلة 1 + 2 + 3 + … + n، نفّذ البرنامج وأدخل القيمة 0 للمتغيّر n ستحصل في الخرج على المجموع sum = 1 وهذا خطأ بالطبع!

السبب في ذلك أنّ اختبار شرط الاستمرار في حلقة do-while يجري بعد انتهاء الحلقة من تنفيذ أوّل دورة لها، حيث تؤدّي هذه الدورة إلى جعل قيمة المتغيّر sum تساوي 1 وقيمة i تساوي 2، وبعد ذلك يأتي اختبار الشرط i <= n والذي سيعطي false بالطبع وتتوقف الحلقة عن التكرار ولكن بعد فوات الأوان.

في حلقة while (وحتى في حلقة for) لم نواجه هذه المشكلة لأنّ شرط استمرارها يجري اختباره في بداية الحلقة وقبل تنفيذ أي دورة تكراريّة.

تمارين داعمة

تمرين 1

اكتب برنامجًا يطبع الأعداد من 1 حتى 100 على الشاشة باستثناء الأعداد من مضاعفات العدد 5 أي على الشكل التالي:

1, 2, 3, 4, 6, 7, 8, 9, 11, … , 14, 16, …

تلميح: ستحتاج في هذا التمرين إلى استخدام بنية if ضمن حلقة for واختبار قيمة التعبير المنطقي i % 5 == 0 على افتراض أنّ i هو عدّاد الحلقة.

تمرين 2

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

تلميح: تذكّر أنّ مضروب عدد يُعبّر عن الجداءات للقيم المتناقصة لهذا العدد فمثلًا لإيجاد مضروب 5 (!5) نكتب:

5! = 5 * 4 * 3 * 2 * 1

تذكّر أيضًا أنّ !1 =1 و !0 = 1.

الخلاصة

تحدثنا في هذا الدرس عن الحلقات التكراريّة بأنواعها المختلفة. تدعم سي شارب عدة حلقات تكراريّة تُعتبر حلقة for من أهمّها. في الحقيقة توجد حلقة تكراريّة أخرى لم نتحدّث عنها في هذا الدرس، وهي حلقة foreach، وهي حلقة مفيدة جدًّا أجلّت الحديث عنها إلى أن نتعرّف على المجموعات Collections بأنواعها ونتعلّم التعامل معها.


تفاعل الأعضاء

أفضل التعليقات

Ameen Badleh

نشر

كل التحيات لك سيد حسام , وأيضاًَ كل الشكر على جهودك.. 

 في المثال الخاص بالحلقة Do While (Lesson04_4( k

نجد ان الخرج صريح وصحيح ..  لان قيمة i ستصبح 1+1 أي 2 وهي اصغر من N في حال فرضنا ان N=9 . 

فيبقى الشرط صحيح , ولن يخرج قبل ان تصبح قيمة i<=n ولكن لو كان الشرط مرتبطاً ب i  لخرج من الحلقة بعد تنفيذ أول عملية. 

كل الشكر والمحبة لك .. 

 

أهلًا أخي الكريم. أعتذر عن التأخر في الرد. بسبب أنّ الموقع لا يُشعرني عندما يتم إدراج تعليق مع الأسف.

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

شيخه جمال

نشر

شكرا لك استاذ حسام 

ولكن عندي سؤال 

اذا كنت حابة أظيف متغير int من قاعدة البيانات في الحلقة التكرارية ايش احتاج ؟ 

 

Wael Aljamal

نشر

بتاريخ On 9/20/2021 at 16:54 قال شيخه جمال:

اذا كنت حابة أظيف متغير int من قاعدة البيانات في الحلقة التكرارية ايش احتاج ؟ 

كمثل، لنفرض استعلام من قاعدة البيانات يعيد عدد المنتجات مع بياناتهم، ثم نريد حلقة تكرارية لطباعة بياناتهم..

$data = "select count(1) as cnt , * from products where cutomer_id = 5";

$count = $data["cnt"];

for ( $i = 0 ; $i < $count ; $i++ ) {
	.....                          
}

 

حسام برهان

نشر

أنت تريد أن تحصل على بيانات من قاعدة بيانات، ثم تريد أن تمر على هذه البيانات بواسطة حلقة تكرارية for. الحقيقة هذا الموضوع منفصل وغير مغطى مع الأسف في هذه السلسلة.

توجد عدة طرق للتواصل مع قاعدة بيانات في سي شارب، ويعتمد ذلك على الإصدار الذي تستخدمه من اللغة، بالإضافة إلى نوع قاعدة البيانات المراد القراءة منها.

زودني بمثل هذه المعلومات كي أستطيع إعطائك مثال عن ذلك.

Wael Aljamal

نشر

بتاريخ 20 ساعات قال Maryam Mohamed2:

طريقة الحل ؟ 

يمكنك مشاركة الشيفرة التي قمت بكتابتها لنساعدك على تصحيح الأخطاء.

Kais Hasan

نشر

بتاريخ 13 ساعة قال امنة النجار:

لو بدي أستخدم do while بكتابة برنامج 1-2+3-4+5-6+7-8....n 

n من نوع int بدي اطلب من المستخدم يدخلها ممكن مساعدة 

مرحباً آمنة،

يمكننا كتابة ذلك بالطريقة التالية:

using System;

public class Test
{
	public static void Main()
	{
		string str_n = Console.ReadLine();
		int n = int.Parse(str_n);
		
		int i = 0;
		int sum = 0;
		do {
			i++;
			if (i % 2 == 1) sum -= i;
			else sum += i;
		} while(i < n);
		
		Console.WriteLine(sum);
	}
}

لاحظي هنا أننا نمر في الحلقة طالما i أصغر من n لأنه عندما يصبح n نكون فعلياً قد أضفنا (أو طرحنا) قيمته، و لذلك لا داعي للإكمال بعد ذلك.

و في كل مرة نقوم بزيادة i في البداية (لاحظي أنا بدأت من الصفر و نحن لا نريده فلا خطأ في الزيادة من البداية).

ثم نقوم في كل مرة باختبار فيما إذا كان i فردي عن طريق حساب باقي قسمته مع ال 2، في حال كان باقي القسمة 1 فهذا يعني أن العدد فردي، و إلا يكون زوجي، في حال كان فردي نقوم بطرح قيمته من المجموع و إلا نقوم بإضافته إلى المجموع.

في حال كان هناك أي جزء آخر غير مفهوم في الكود من فضلك قومي بذكره حتى أستطيع شرحه لك.

تحياتي لك.

Omar Dorgham

نشر (معدل)

السلام عليكم ورحمة الله وبركاته .. 

انا جديد هنا في تعلم ال C# والنتائج طلعت مضبوطة بس هل طريقة حلي صحيحي ام عندي خطأ ؟! وهل من الممكن حلها بطريقة اخرى غير طريقتي ؟!

هذا حل للتمرين الأول : 

for (int i = 1; i <= 100; i++)
{
    if (i % 5 != 0)
    {
        Console.Write(i + ",");
    }
}

وهذا حل التمرين الثاني :

 

int sum = 1;
int n = int.Parse(Console.ReadLine());

for (int i = 1; i <= n; i++)
{
    sum = sum * i;
    Console.WriteLine(sum);
}

Untitledpg.png

تم التعديل في بواسطة Omar Dorgham

نسيت اضع اذا ادخل المستخدم قيمة أقل من 0 او 0 ينهي التطبيق
 

int sum = 1;
int n = int.Parse(Console.ReadLine());

if (n <= 0)
{
    Console.WriteLine("n must be > 0");
    return;
}

for (int i = 1; i <= n; i++)
{
    sum = sum * i;
    Console.WriteLine(sum);
}

 

بتاريخ On 5‏/6‏/2024 at 15:05 قال Omar Dorgham:

نسيت اضع اذا ادخل المستخدم قيمة أقل من 0 او 0 ينهي التطبيق
 

int sum = 1;
int n = int.Parse(Console.ReadLine());

if (n <= 0)
{
    Console.WriteLine("n must be > 0");
    return;
}

for (int i = 1; i <= n; i++)
{
    sum = sum * i;
    Console.WriteLine(sum);
}
 

 

جيد جدًا، نقوم أيضًا استخدام TryParse بدلاً من Parse لتجنب حدوث استثناءات في حالة إدخال قيم غير صحيحة.

using System;

class Program
{
    static void Main()
    {
        Console.WriteLine("Please enter a positive integer:");

        if (!int.TryParse(Console.ReadLine(), out int n) || n <= 0)
        {
            Console.WriteLine("Invalid input. Please enter a positive integer greater than 0.");
            return;
        }

        CalculateAndPrintFactorial(n);
    }

    static void CalculateAndPrintFactorial(int n)
    {
        int sum = 1;

        for (int i = 1; i <= n; i++)
        {
            sum *= i;
            Console.WriteLine(sum);
        }
    }
}

إن  أدخل المستخدم قيمة أقل من أو تساوي 0، يتم عرض رسالة "n must be > 0" ويتم إنهاء التطبيق باستخدام return.

و int.TryParse يحاول تحويل الإدخال إلى عدد صحيح، وفي حال فشل التحويل، يعود false ويتجنب حدوث استثناء.

إن كانت القيمة المدخلة أكبر من 0، يتم تنفيذ الحلقة التكرارية لحساب وعرض القيم المتتابعة للمتغير sum.

بتاريخ On 5‏/6‏/2024 at 13:26 قال Omar Dorgham:

السلام عليكم ورحمة الله وبركاته .. 

انا جديد هنا في تعلم ال C# والنتائج طلعت مضبوطة بس هل طريقة حلي صحيحي ام عندي خطأ ؟! وهل من الممكن حلها بطريقة اخرى غير طريقتي ؟!

هذا حل للتمرين الأول : 

for (int i = 1; i <= 100; i++)
{
    if (i % 5 != 0)
    {
        Console.Write(i + ",");
    }
}
 
 

الحل صحيح، تستطيع تحسينه بتجنب طباعة فاصلة زائدة في النهاية، الفكرة هي التأكد من أن الفاصلة تُطبع فقط بين الأرقام وليس بعد آخر رقم في السلسلة.

for (int i = 1; i <= 100; i++)
{
    if (i % 5 != 0)
    {
        if (i > 1 && (i - 1) % 5 != 0) 
        {
            Console.Write(",");
        }
        Console.Write(i);
    }
}

استخدمت شرطًا إضافيًا داخل الحلقة للتحقق في حال كان الرقم الحالي ليس الأول في السلسلة (i > 1) وأن الرقم السابق لم يكن مضاعفًا للـ 5 ((i - 1) % 5 != 0).

بالتالي طباعة الفاصلة فقط بين الأرقام التي ليست مضاعفات للـ 5، وتجنب الفاصلة الزائدة في النهاية.

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

using System;
using System.Collections.Generic;

class Program
{
    static void Main()
    {
        List<int> numbers = new List<int>();

        for (int i = 1; i <= 100; i++)
        {
            if (i % 5 != 0)
            {
                numbers.Add(i);
            }
        }

        Console.WriteLine(string.Join(",", numbers));
    }
}

 

بتاريخ On 5‏/6‏/2024 at 13:26 قال Omar Dorgham:

وهذا حل التمرين الثاني :

 

int sum = 1;
int n = int.Parse(Console.ReadLine());

for (int i = 1; i <= n; i++)
{
    sum = sum * i;
    Console.WriteLine(sum);
}

تسلسل الخطوات مضبوط، أحييك على تفكيرك المنطقي، ولكن يوجد خطأ بسيط وهو في الجملة الشرطية حيث يجب إزالة علامة = وذلك لأننا لا نريد استبعاد الصفر حيث أن مضروب الصفر يساوي 1 ليصير الأمر

if (n < 0)

وكذلك نقل أمر الطباعة خارج الحلقة التكرارية، لأننا نريد طباعة الناتج النهائي وليس الناتج بعد كل عملية ضرب، بالإضافة إلى أنه لن يتم الطباعة في حال n = 0

for (int i = 1; i <= n; i++)
{
    sum = sum * i;
}

Console.WriteLine(sum);

 



انضم إلى النقاش

يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.

زائر
أضف تعليق

×   لقد أضفت محتوى بخط أو تنسيق مختلف.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   جرى استعادة المحتوى السابق..   امسح المحرر

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • أضف...