Menu
flag Ar iconالعربيةdown icon

حلقة do-while في لغة C: الصياغة والأمثلة ومتى تستخدمها

حلقة C التي تبدأ بالجسم: كيف تضمن do-while مرورًا واحدًا قبل الفحص، ولماذا تنتهي بفاصلة منقوطة، وأنماط القوائم وإعادة المحاولة التي صُنعت لها، وكيف تختلف عن حلقة while العادية.

تحتوي هذه الصفحة على محررات قابلة للتشغيل - حرّر، شغّل، وشاهد النتيجة فوراً.

الحلقة التي تُنفَّذ مرة دائمًا

تفحص حلقة while قبل أن تتصرّف، فيمكن أن تُنفَّذ صفر مرة. وذلك صحيح عادةً. لكنه أحيانًا خاطئ تمامًا: فلا يمكنك معرفة هل تكرّر سؤالًا قبل أن تعرضه، ولا يمكنك الحكم على إدخال المستخدم قبل أن تقرأ شيئًا. وتنقل do-while الفحص إلى النهاية، فيُنفَّذ الجسم أولًا ويقرّر الشرط فقط هل يُعاد مرة أخرى.

الشرط i < 5 غير محقّق منذ البداية. فحلقة while تُنفَّذ صفر مرة؛ وdo-while تُنفَّذ مرة واحدة بالضبط. وذلك هو الفرق كله بينهما.

الصياغة، وتلك الفاصلة المنقوطة

do {
    // الجسم - يُنفَّذ مرة واحدة على الأقل دائمًا
} while (condition);

الترتيب يُقرأ كما يُنفَّذ: افعل الجسم، بينما يبقى الشرط محقّقًا، افعله مجددًا.

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

وهذا أيضًا الموضع الوحيد في C الذي تكون فيه while (cond); بفاصلة منقوطة صحيحةً لا علّة. ففي حلقة while عادية تُنشئ الترقيمة نفسها جسمًا فارغًا وحلقة لا نهائية عادةً؛ أما هنا فهي تُغلق do.

والأقواس اختيارية لجسم من جملة واحدة، لكن اكتبها على أي حال، كما في كل بنية تحكّم أخرى في C.

نمط التحقّق من الإدخال

هذا ما صُمّمت do-while من أجله. عليك قراءة شيء قبل أن تعرف هل هو مقبول، فيجب أن تحدث القراءة قبل الفحص:

تواصل الحلقة القراءة حتى تمرّ قيمة، والشرط نفسه الذي يرفض قيمة سيّئة هو الذي يطلب مرورًا آخر. ولو كُتبت بـ while، لوجب ظهور القراءة مرتين - مرة قبل الحلقة لتهيئة الشرط، ومرة في نهاية الجسم - وهو التكرار الذي تزيله do-while.

ومع إدخال حقيقي كان الجسم سيستدعي scanf بدلًا من ذلك:

int age;
do {
    printf("Enter your age (1-120): ");
    if (scanf("%d", &age) != 1) {
        while (getchar() != '\n') { }   /* تخلّص من السطر السيّئ */
        age = -1;                        /* افرض مرورًا آخر */
    }
} while (age < 1 || age > 120);

لاحظ حلقة while الداخلية التي تستنزف بقية السطر. فإن أخفقت scanf في التحويل، يبقى النصّ المخالف جاثمًا في مخزن الإدخال وتفشل كل قراءة لاحقة عليه أيضًا - أي حلقة تدور إلى الأبد وهي تطبع السؤال. ومسحه جزء من النمط.

نمط القائمة

الاستخدام الكلاسيكي الآخر: اعرض الخيارات، واقرأ خيارًا، وتصرّف بناءً عليه، وكرّر حتى ينسحب المستخدم. ويجب أن تظهر القائمة قبل أن يوجد أي خيار لفحصه.

break داخل switch تُنهي switch، لا الحلقة - وهي نقطة تستحقّ الدقّة، لأن الاثنين يستخدمان الكلمة المفتاحية نفسها. فالحلقة هنا تنتهي لأن choice != 4 يصبح غير محقّق. ولو أردت الخروج من الحلقة من داخل switch، لكانت return أو متغيّر راية هي السبيل؛ فـ break وحدها لا تستطيع ذلك.

المرور الأول المضمون قد يكون علّة

لأن الجسم يُنفَّذ قبل أي فحص، ستعالج do-while بكل رضا بيانات غير موجودة:

/* BUG: prints a[0] even when n is 0 */
int i = 0;
do {
    printf("%d\n", a[i]);
    i++;
} while (i < n);

مع n == 0 يقرأ هذا a[0] على مصفوفة فارغة - سلوك غير معرَّف. وأي حلقة على مجموعة قد تكون فارغة تريد while أو for، حيث يأتي الفحص أولًا.

والقاعدة العملية: استخدم do-while فقط حين يكون التنفيذ بصفر تكرارات مستحيلًا بطبيعة المسألة، لا مجرّد مستبعد عمليًا. فسؤال المستخدم، ورمي النرد حتى يظهر هدف، وتوليد مرشّح وفحصه - كلها لا يمكن الحكم عليها قبل المرور الأول فعلًا. أما المرور على قائمة فلا يستطيع ادّعاء ذلك.

break وcontinue في do-while

كلتاهما تعملان، ولـ continue التواء يستحقّ المعرفة: فهي تقفز إلى فحص الشرط، لا إلى أعلى الجسم.

تُنفَّذ i++ في أعلى الجسم في كل مرور، بما في ذلك المرورات التي تقطعها continue، فتواصل الحلقة التقدّم. ضع التحديث بعد continue فتتجمّد الحلقة - وهو الفخّ نفسه الموجود في حلقات while.

أما break فتترك الحلقة فورًا وتتخطّى الشرط كليًا.

الاختيار بين الحلقات الثلاث

حلقات C الثلاث متساوية في القدرة؛ والاختيار يتعلّق بأيّها يعبّر عن القصد.

for        a counter, its limit, and its step belong together - "n times"
while      repeat until a condition changes, and maybe not at all - "until"
do-while   the same, but the first pass is guaranteed - "at least once"

وعمليًا تكون do-while أندر الثلاث بفارق واسع. فمعظم الحلقات إما تعدّ وإما تحتاج إلى معالجة الحالة الفارغة، وكلتاهما تريدان الفحص في الأعلى. الجأ إلى do-while حين تجد نفسك تكرّر جملة قبل حلقة while مباشرة لتهيئة شرطها - فذلك التكرار هو الإشارة.

الأسئلة الشائعة

كيف تكتب حلقة do-while في لغة C؟

do { body } while (condition); - الجسم أولًا، والفحص بعده، وتنتهي الجملة كلها بـ فاصلة منقوطة. ويُنفَّذ الجسم مرة واحدة على الأقل دائمًا، ثم يتكرّر ما دام الشرط غير صفري.

ما الفرق بين while وdo-while في لغة C؟

موضع الفحص. فحلقة while تفحص الشرط قبل المرور الأول، فيمكن أن تُنفَّذ صفر مرة. أما do-while فتفحص بعده، فتُنفَّذ دائمًا مرة واحدة على الأقل. اختر do-while فقط حين يكون ذلك المرور الأول المضمون هو ما تحتاجه المسألة فعلًا.

لماذا تحتاج حلقة do-while إلى فاصلة منقوطة في النهاية؟

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

متى ينبغي أن أستخدم حلقة do-while؟

حين يجب أن يُنفَّذ الجسم قبل أن يمكنك معرفة هل تكرّر: عرض قائمة قبل قراءة خيار، أو إعادة السؤال حتى يصحّ الإدخال، أو توليد قيمة ثم فحصها. وإن أمكن فحص الشرط مسبقًا، فإن حلقة while تقول ذلك بوضوح أكبر.

Coddy programming languages illustration

تعلّم البرمجة مع Coddy

ابدأ الآن