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

break وcontinue في لغة C: كيف تعملان ومتى تستخدمهما

تترك break الحلقة أو جملة switch؛ وتقفز continue إلى المرور التالي. كيف تتصرّف كل منهما في for وwhile وdo-while، كيف تهرب من الحلقات المتداخلة براية أو goto، والاستخدامات الخاطئة التي تجعل متابعة الحلقات صعبة.

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

طريقتان لتغيير مسار الحلقة

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

لدى C كلمة مفتاحية لكل حالة:

  • break - اترك الحلقة الآن. ويُستأنف التنفيذ عند أول جملة بعدها.
  • continue - تخلَّ عن هذا المرور فقط. وانتقل إلى التالي.

تطبع الحلقة الأولى 1 2 3 4 ثم تتوقّف. وتطبع الثانية 1 2 3 4 6 7 8 9 10 - فقد تخطّت قيمة واحدة وواصلت.

break داخل حلقة

الاستخدام النموذجي هو بحث يتوقّف بمجرّد نجاحه:

ولأن found تُضبَط قبل break، تستطيع الشيفرة بعد الحلقة التمييز بين "وجدته" و"نفدت العناصر". هذا الاقتران - متغيّر نتيجة مع break - هو صيغة البحث القياسية في C. أما عدّاد الحلقة نفسه فغير قابل للاستخدام بعدها عندما يكون معرّفًا في الترويسة، لأنه يخرج من النطاق عند القوس المعقوف الخاتم.

تخرج break دائمًا من حلقة واحدة: أقرب for أو while أو do-while أو switch يحيط بها.

continue داخل حلقة

continue مخصّصة للمدخلات التي يجب تخطّيها بدل إيقاف العمل:

أما وجهة قفز continue فتعتمد على نوع الحلقة:

for        -> the update part of the header (so the counter still advances)
while      -> the condition test (nothing else in the body runs)
do-while   -> the condition test at the bottom

هذا الفرق ليس نظريًا. ففي حلقة for لا تستطيع continue أبدًا تخطّي زيادة العدّاد، لأن الزيادة في الترويسة. أما في حلقة while فتستطيع:

/* BUG: continue skips i++, so this hangs at the first even number */
int i = 0;
while (i < 10) {
    if (i % 2 == 0) {
        continue;
    }
    printf("%d ", i);
    i++;
}

إما أن تنقل i++ إلى ما قبل continue، أو تكتبها حلقة for، حيث تجعل الترويسة الخطأ مستحيلًا.

break داخل switch ليست break للحلقة

تُنهي break أقرب حلقة أو switch يحيط بها - أيهما أقرب. ضع switch داخل حلقة فتصبح كل break فيها تابعة لـ switch:

يطبع الأمر q رسالته وتستمرّ الحلقة عبر cc. فإن كان يُفترض بالخروج أن يُنهي الحلقة، فتلك break لم تفعل ذلك. والحلول هي راية أو goto أو نقل الحلقة إلى دالة واستخدام return - وكلها معروضة أدناه.

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

تترك break واحدة مستوى واحدًا. وداخل حلقتين متداخلتين تُنهي الداخلية فقط، وتبدأ الحلقة الخارجية مرورها التالي كأن شيئًا لم يكن.

لا تملك C صيغة break 2 ولا break معنونة. وأمامك ثلاثة خيارات صادقة:

راية. محمولة وواضحة ومزعجة قليلًا:

تظهر الراية في موضعين - الشرط الخارجي والإسناد - وهذه هي التكلفة. ومع ثلاثة مستويات من التداخل يصبح الأمر مزعجًا فعلًا.

goto. قفزة C المذمومة كثيرًا، وهذه هي الحالة الوحيدة التي يستخدمها فيها مبرمجو C المخضرمون دون اعتذار:

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

دالة وreturn. الجواب الأفضل عادةً، لأن البحث يستحقّ اسمًا:

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

متى تفيدان، ومتى تضرّان

تستحقّ break وcontinue مكانهما عندما تتيحان للحلقة أن تقول "انتهت هذه الحالة" مرة واحدة قرب الأعلى، بدل تغليف الجسم كله بـ if. قارن:

/* مع continue: العمل الحقيقي غير مزاح إلى الداخل */
for (int i = 0; i < n; i++) {
    if (!isValid(a[i])) continue;
    if (isDuplicate(a[i])) continue;
    process(a[i]);
}

/* بدونها: كل حارس يضيف مستوى */
for (int i = 0; i < n; i++) {
    if (isValid(a[i])) {
        if (!isDuplicate(a[i])) {
            process(a[i]);
        }
    }
}

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

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

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

ما الفرق بين break وcontinue في لغة C؟

تُنهي break الحلقة بالكامل ويُستأنف التنفيذ بعدها. أما continue فتتخلّى عن المرور الحالي فقط وتنتقل إلى التالي - إلى جزء التحديث في حلقة for، أو مباشرة إلى فحص الشرط في while أو do-while.

كيف أخرج من حلقة متداخلة في لغة C؟

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

هل تخرج break من الحلقة أم من switch فقط؟

من أيهما يحيط بها بشكل أوثق. فـ break داخل switch موجود داخل حلقة يُنهي switch فقط؛ وتواصل الحلقة عملها. للخروج من الحلقة من داخل switch تحتاج إلى راية أو goto أو return.

لماذا تتسبّب continue بحلقة لا نهائية في حلقة while عندي؟

لأن continue تقفز إلى الشرط وتتخطّى بقية الجسم - بما في ذلك زيادة العدّاد إن كانت في النهاية. في حلقة for يوجد التحديث في الترويسة فيُنفَّذ دائمًا؛ أما في حلقة while فانقل التحديث إلى ما قبل continue أو استخدم for.

Coddy programming languages illustration

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

ابدأ الآن