C: هياكل التكرار
الحلقات كالجري على مضمار — استمر حتى تصل خط النهاية. عندما يتحقق الشرط، تتوقف. بالحلقات، يمكن للبرامج أن تفعل أكثر من مجرد التنفيذ مرة واحدة.
1. حلقة while
while هي أبسط حلقة: تتحقق من الشرط أولًا، وتنفّذ جسم الحلقة إذا كان صحيحًا، ثم تتحقق مجددًا، وتكرر حتى يصبح الشرط خاطئًا.
#include <stdio.h>
int main(void) {
int count = 1;
while (count <= 5) {
printf("Lap %d\n", count);
count++;
}
printf("Done!\n");
return 0;
}
Lap 1
Lap 2
Lap 3
Lap 4
Lap 5
Done!
count++). وإلا ستتحصل على حلقة لا نهائية ولن يتوقف البرنامج أبدًا.
(1) متى تستخدم while
عما يكون عدد التكرارات غير محدد ويعتمد على شرط وقت التنفيذ، تكون while الخيار الأكثر طبيعية. مثلًا، قراءة المدخلات حتى قيمة معينة:
#include <stdio.h>
int main(void) {
int sum = 0;
int num = 0;
printf("Enter positive integers to sum, 0 to finish: ");
scanf("%d", &num);
while (num != 0) {
sum += num;
scanf("%d", &num);
}
printf("Sum: %d\n", sum);
return 0;
}
Enter positive integers to sum, 0 to finish: 10 20 30 0
Sum: 60
2. حلقة do-while
تنفِّذ do-while جسم الحلقة أولًا، ثم تتحقق من الشرط. هذا يضمن تنفيذ جسم الحلقة مرة واحدة على الأقل، وهو الفرق الجوهري عن while.
#include <stdio.h>
int main(void) {
int num;
do {
printf("Enter a number 1-10: ");
scanf("%d", &num);
} while (num < 1 || num > 10);
printf("You entered: %d\n", num);
return 0;
}
Enter a number 1-10: 15
Enter a number 1-10: 0
Enter a number 1-10: 7
You entered: 7
do-while يجب ألا تُحذف: } while (condition); نسيانها يسبب خطأ تجميع.
(1) الاختيار بين while و do-while
- الحاجة لتنفيذ واحد على الأقل ←
do-while(مثلًا: التحقق من المدخلات) - احتمال عدم التنفيذ ←
while(مثلًا: البحث حيث قد لا يُعثر على شيء)
3. حلقة for
تجمع for بين التهيئة والتحقق من الشرط والتحديث في الرأس، مما يجعلها أكثر أشكال الحلقات شيوعًا.
for (initialization; condition; update) {
loop body;
}
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 5; i++) {
printf("%d ", i);
}
printf("\n");
return 0;
}
1 2 3 4 5
(1) سير تنفيذ حلقة for
- تنفيذ التهيئة (مرة واحدة فقط)
- التحقق من الشرط — إذا كان خاطئًا، الخروج من الحلقة
- تنفيذ جسم الحلقة
- تنفيذ التحديث
- العودة إلى الخطوة 2
(2) مرونة for
يمكن حذف الأجزاء الثلاثة في for، لكن الفواصل المنقوطة يجب أن تبقى:
#include <stdio.h>
int main(void) {
int i = 1;
for (; i <= 5; ) {
printf("%d ", i);
i++;
}
printf("\n");
return 0;
}
حذف الشرط يُنشئ حلقة لا نهائية: for (;;) {} تكافئ while (1) {}.
for — متغير الحلقة وشرط الحد وطريقة التحديث كلها مرئية بنظرة، مما يصعّب كتابة حلقة لا نهائية بالخطأ.
(3) اعتبارات النطاق
يسمح C99 بتعريف المتغيرات في تهيئة for. هذه المتغيرات نطاقها يقتصر على حلقة for فقط:
#include <stdio.h>
int main(void) {
for (int i = 0; i < 3; i++) {
printf("i = %d\n", i);
}
return 0;
}
بعد انتهاء الحلقة، لم يعد i متاحًا. إذا كنت تحتاج استخدام i خارج الحلقة، عرّفه قبل for.
4. الحلقات المتداخلة
حلقة داخل حلقة أخرى هي حلقة متداخلة. كل تكرار للحلقة الخارجية يشغل الحلقة الداخلية بالكامل.
(1) طباعة مستطيل من النجوم
#include <stdio.h>
int main(void) {
int rows = 3;
int cols = 5;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("* ");
}
printf("\n");
}
return 0;
}
* * * * *
* * * * *
* * * * *
(2) جدول الضرب
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
printf("%d*%d=%-4d", j, i, i * j);
}
printf("\n");
}
return 0;
}
1*1=1
1*2=2 2*2=4
1*3=3 2*3=6 3*3=9
1*4=4 2*4=8 3*4=12 4*4=16
1*5=5 2*5=10 3*5=15 4*5=20 5*5=25
1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36
1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49
1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64
1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
5. جملة break
تخرج break فورًا من الحلقة الحالية (مستوى واحد فقط). تُتجاوز التكرارات المتبقية.
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i == 5) {
break;
}
printf("%d ", i);
}
printf("\nStopped at 5\n");
return 0;
}
1 2 3 4
Stopped at 5
(1) إيجاد أول عنصر يحقق شرطًا
#include <stdio.h>
int main(void) {
int nums[] = {3, 7, 2, 9, 5, 1};
int target = 9;
int found = 0;
for (int i = 0; i < 6; i++) {
if (nums[i] == target) {
printf("Found %d at index %d\n", target, i);
found = 1;
break;
}
}
if (!found) {
printf("%d not found\n", target);
}
return 0;
}
Found 9 at index 3
6. جملة continue
تتجاوز continue الجمل المتبقية في التكرار الحالي وتنتقل إلى التكرار التالي (العودة إلى خطوة التحقق أو التحديث).
#include <stdio.h>
int main(void) {
for (int i = 1; i <= 10; i++) {
if (i % 3 == 0) {
continue;
}
printf("%d ", i);
}
printf("\nMultiples of 3 skipped\n");
return 0;
}
1 2 4 5 7 8 10
Multiples of 3 skipped
continue في حلقتي while و do-while، تأكد أن جملة التحديث تأتي قبل continue، وإلا قد تُنشئ حلقة لا نهائية.
7. أنماط التكرار الشائعة
(1) نمط العد
عدّ عدد العناصر التي تحقق شرطًا:
#include <stdio.h>
int main(void) {
int nums[] = {12, 45, 3, 67, 89, 23, 56};
int count = 0;
for (int i = 0; i < 7; i++) {
if (nums[i] > 50) {
count++;
}
}
printf("Numbers greater than 50: %d\n", count);
return 0;
}
Numbers greater than 50: 3
(2) نمط التراكم
جمع سلسلة من القيم:
#include <stdio.h>
int main(void) {
int sum = 0;
for (int i = 1; i <= 100; i++) {
sum += i;
}
printf("Sum from 1 to 100: %d\n", sum);
return 0;
}
Sum from 1 to 100: 5050
(3) نمط البحث
إيجاد أول عنصر يحقق شرطًا، ثم الخروج بـ break:
راجع مثال break السابق.
(4) نمط الاجتياز
معالجة كل عنصر في مصفوفة بالتسلسل:
#include <stdio.h>
int main(void) {
int scores[] = {85, 92, 78, 96, 61};
int len = 5;
for (int i = 0; i < len; i++) {
printf("Student%d: %d %s\n", i + 1, scores[i], scores[i] >= 60 ? "Pass" : "Fail");
}
return 0;
}
Student1: 85 Pass
Student2: 92 Pass
Student3: 78 Pass
Student4: 96 Pass
Student5: 61 Pass
8. الحلقات اللا نهائية وكيفية تجنبها
الحلقة اللا نهائية هي التي شرطها دائمًا صحيح. الحلقات اللا نهائية المتعمدة تستخدم for(;;) أو while(1)، مع break بداخلها للخروج:
#include <stdio.h>
int main(void) {
int num;
while (1) {
printf("Enter a number (0 to quit): ");
scanf("%d", &num);
if (num == 0) {
break;
}
printf("You entered: %d\n", num);
}
printf("Goodbye!\n");
return 0;
}
تحدث الحلقات اللا نهائية غير المتعمدة عادةً لأن متغير الحلقة لا يُحدَّث أبدًا أو يُحدَّث بالاتجاه الخاطئ:
int i = 0;
while (i < 10) {
printf("%d", i);
}
▶ مثال
طباعة مثلث قائم باستخدام حلقات متداخلة:
#include <stdio.h>
int main(void) {
int n = 5;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
printf("* ");
}
printf("\n");
}
return 0;
}
*
* *
* * *
* * * *
* * * * *
▶ مثال
إيجاد القاسم المشترك الأكبر لعددين صحيحين موجبين باستخدام خوارزمية إقليدس، مع عرض حلقة while بعدد تكرارات غير محدد:
#include <stdio.h>
int main(void) {
int a = 48, b = 18;
int orig_a = a, orig_b = b;
while (b != 0) {
int temp = a % b;
a = b;
b = temp;
}
printf("GCD of %d and %d is %d\n", orig_a, orig_b, a);
return 0;
}
GCD of 48 and 18 is 6
9. الاختيار بين الحلقات الثلاث
| الموقف | التوصية |
|---|---|
| عدد تكرارات محدد | for |
| يجب التنفيذ مرة واحدة على الأقل | do-while |
| عدد تكرارات غير محدد | while |
| قائمة تفاعلية | do-while + switch |
❓ أسئلة شائعة
for أم while؟for عندما يكون عدد التكرارات معروفًا، و while عندما لا يكون معروفًا. هذا هو الدليل الأكثر قبولًا.break الخروج من عدة مستويات من الحلقات؟break تخرج فقط من الحلقة الأعمق. للخروج من عدة مستويات، استخدم متغير علم مع تحقق في الحلقة الخارجية، أو goto (غير مستحسن لكنه عملي أحيانًا).for(;;) أم while(1)؟while(1) أوضح قراءة؛ for(;;) هو أسلوب C تقليدي. اختر وفقًا لاصطلاحات فريقك.i و j و k كمتغيرات حلقة؟row أو col أو student_index)، فالاسم الوصفي أفضل.📖 ملخص
whileتتحقق قبل التنفيذ، وdo-whileتنفذ قبل التحقق، وforتُركّز العناصر الثلاثة في الرأسforهي هيكل التكرار الأكثر شيوعًا للحلقات ذات التكرارات المحددة- إجمالي عدد تكرارات الحلقات المتداخلة يساوي حاصل ضرب عدد كل مستوى — انتبه للأداء
breakتخرج من الحلقة الحالية، وcontinueتتجاوز التكرار الحالي — كلاهما يؤثر فقط على الحلقة الأعمق- تجنب الحلقات اللا نهائية غير المتعمدة: تأكد من تحديث متغير الحلقة بشكل صحيح وفي الاتجاه الصحيح
📝 تمارين
- اكتب برنامجًا باستخدام حلقة
forلحساب مجموع المضروبات: 1! + 2! + 3! + ... + 10!. - اكتب برنامجًا باستخدام حلقات متداخلة لطباعة مثلث قائم مقلوب (5 صفوف، 5 نجوم في الصف الأول، نجمة واحدة في الصف الخامس).
- اكتب برنامجًا يقرأ عددًا صحيحًا موجبًا ويطبع أرقامه بترتيب عكسي (مثلًا: الإدخال 1234 يُخرج 4 3 2 1).