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

حلقة while في C++: الصياغة وdo-while والمزالق

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

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

عندما لا يكون لديك عدّاد

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

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

يُفحص الشرط count > 0 أولًا؛ فإن كان صحيحًا نُفِّذ الجسم، ثم نعود إلى الأعلى ونفحص مجددًا. والسطر count-- هو ما يجعل الشرط خاطئًا في النهاية؛ احذفه وستعمل الحلقة إلى الأبد.

تشريح حلقة while

قارنها بحلقة for ثلاثية الأجزاء التي تعرفها أصلًا. تفصل حلقة while بين تلك المهام الثلاث: التهيئة تجريها قبل الحلقة، والشرط يوضع بين القوسين، والتحديث يعيش داخل الجسم.

int i = 0;          // التهيئة - قبل الحلقة
while (i < 5) {     // الشرط - يُفحص في كل جولة
    cout << i << "\n";
    i++;            // التحديث - عليك أن تتذكّره بنفسك
}

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

من مزالق C++ التي توقع المبتدئين: فاصلة منقوطة شاردة بعد الشرط مباشرة تحوّل الجسم إلى جملة فارغة.

int i = 0;
while (i < 5);   // <-- هذه الفاصلة المنقوطة هي جسم الحلقة بأكمله
{
    cout << i << "\n";
    i++;
}

هذا يدور إلى الأبد دون أن يفعل شيئًا، لأن الـ; هي الجسم وi لا يتغيّر أبدًا. ثم تُنفَّذ الكتلة المحاطة بالأقواس المعقوفة مرة واحدة بالضبط. لن يوقفك المترجم؛ فهو كود سليم تمامًا، لكنه ليس ما قصدته.

do-while: نفّذ الجسم مرة واحدة على الأقل

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

عليك أن تطلب وتقرأ مرة واحدة على الأقل قبل أن تعرف ما إذا كان الإدخال صالحًا، وهذا بالضبط ما تمنحه لك do-while. لاحظ الفاصلة المنقوطة بعد while (...)؛ فهي إلزامية لـdo-while في C++، ونسيانها خطأ ترجمة شائع.

يظهر الفرق عن حلقة while العادية بوضوح حين يبدأ الشرط خاطئًا:

يُطبع do-while body فقط. تتخطّى حلقة while جسمها بالكامل لأن x < 5 كان خاطئًا قبل الفحص الأول.

التكرار حتى يفشل cin

من الاستخدامات الكلاسيكية لـwhile القراءة حتى يتوقّف الإدخال؛ لا يوجد عدّاد، فأنت تستمر فحسب حتى يخبرك المجرى بالتوقّف. في C++، يُقيَّم cin >> value بوصفه المجرى نفسه، وهو صحيح ما دامت القراءة ناجحة، وخاطئ بمجرّد أن يبلغ نهاية الإدخال أو عدم تطابق في النوع. وهذا يجعله شرط حلقة أنيقًا:

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

إذا نسيت القراءة الثانية داخل الجسم، فلن يتغيّر value أبدًا وستكون أمام حلقة لانهائية. والصيغة while (cin >> value) تتجنّب ذلك بطيّ القراءة داخل الشرط.

break وcontinue في حلقات while

يعمل break وcontinue هنا تمامًا كما في حلقة for. يخرج break من الحلقة فورًا؛ بينما يقفز continue مباشرة إلى فحص الشرط متخطيًا بقية الجولة الحالية:

يطبع هذا 1 3 5 7 9. لا تتوقّف while (true) من تلقاء نفسها عمدًا؛ فالـbreak هو المخرج الوحيد. انتبه إلى continue في حلقة while: لأن التحديث جزء من الجسم، فإن القفز إلى الأعلى بـcontinue قبل أن تقدّم عدّادك طريقة صامتة لتعليق الحلقة. في المثال أعلاه يُنفَّذ n++ أولًا، فهو آمن.

احذر الحلقات اللانهائية

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

int i = 0;
while (i < 5) {
    cout << i << "\n";   // i لا يتغيّر أبدًا -> يعمل إلى الأبد
}
int i = 0;
while (i != 10) {
    i += 3;   // 0، 3، 6، 9، 12... يتجاوز 10 تمامًا -> يعمل إلى الأبد
}

يتعلّق الأول لأن i لا يُحدَّث أبدًا. ويتعلّق الثاني لأن العدّاد يتخطّى القيمة المضبوطة التي يبحث عنها الشرط؛ ففضّل < أو <= على != حين قد لا تقع الخطوة على القيمة بالضبط. والـwhile (true) لا بأس به إن كان فيه break مضمون؛ أما العَرَضي فمجرّد خطأ. وتذكّر مزلق الجسم الفارغ while (...); السابق؛ ففاصلة منقوطة في غير موضعها تنتج حلقة لانهائية تبدو صحيحة للوهلة الأولى.

التالي: حلقة for المعتمدة على المدى

حلقة while هي الأداة المناسبة حين تكرّر حتى يتغيّر شرط ولا يوجد عدّ واضح. لكن حين تريد فقط أن تزور كل عنصر في حاوية - vector أو مصفوفة أو string - دون مؤشر ولا شرط تديره، يقدّم C++ الحديث شيئًا أنظف: حلقة for المعتمدة على المدى (for (auto x : container)). هذا موضوع الصفحة التالية.

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

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

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

متى ينبغي أن أستخدم حلقة while بدلًا من حلقة for في C++؟

استخدم حلقة while عندما لا يكون لديك عدّاد واضح وتريد فقط أن تكرّر حتى يتغيّر شرط ما: قراءة الإدخال حتى يفشل cin، أو الاستعلام حتى تصبح قيمة جاهزة، أو معالجة طابور حتى يفرغ. والجأ إلى حلقة for عندما تعرف عدد التكرارات أو يكون لديك مؤشر واضح للعدّ.

كيف توقف حلقة while لانهائية في C++؟

تأكّد من أن شيئًا داخل الجسم يجعل الشرط خاطئًا في النهاية (إنقاص عدّاد، أو تقديم مؤشر، أو ضبط راية). أما الحلقة while (true) المقصودة فضع داخلها break محميًّا بـif. وإذا تعلّقت حلقة، فالسبب المعتاد هو نسيان تحديث المتغيّر الذي يعتمد عليه الشرط.

Coddy programming languages illustration

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

ابدأ الآن