כשאין לכם מונה
לולאת for בנויה סביב מונה שמגדירים מראש. אבל להרבה לולאות אין ספירה ברורה: להמשיך לקרוא מספרים עד שהקלט נגמר, להמשיך לבקש סיסמה עד שהיא נכונה, להמשיך לחצות ערך עד שהוא מגיע ל-1. בשבילן, לולאת while היא ההתאמה הטבעית: היא פשוט חוזרת כל עוד תנאי נשאר true.
לולאת while בודקת את התנאי שלה לפני כל סיבוב, כולל הראשון. אם התנאי false מההתחלה, הגוף לא רץ בכלל.
התנאי count > 0 נבדק קודם; אם הוא true הגוף רץ, ואז חוזרים לבדוק שוב. השורה count-- היא מה שבסופו של דבר הופך את התנאי ל-false: תמחקו אותה והלולאה תרוץ לנצח.
האנטומיה של לולאת 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 (...): ב-C++ היא חובה ב-do-while, ושכחה שלה היא שגיאת קומפילציה נפוצה.
ההבדל מ-while רגילה בולט כשהתנאי false מההתחלה:
רק do-while body מודפס. לולאת ה-while מדלגת לגמרי על הגוף שלה, כי x < 5 היה false לפני הבדיקה הראשונה.
לולאה עד ש-cin נכשל
שימוש קלאסי ב-while הוא קריאה עד שהקלט נעצר: אין מונה, פשוט ממשיכים עד שה-stream אומר לעצור. ב-C++, cin >> value מחזיר את ה-stream עצמו, שנחשב true כל עוד הקריאה מצליחה ו-false ברגע שהוא מגיע לסוף הקלט או לאי התאמה בטיפוס. זה הופך אותו לתנאי לולאה נקי:
התנאי עושה עבודה כפולה: הוא קורא וגם בודק בצעד אחד. השוו את זה לערך זקיף (sentinel), למשל עצירה ב-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++ רץ קודם, אז זה בטוח.
היזהרו מלולאות אינסופיות
התנאי חייב בסופו של דבר להפוך ל-false, וזה תלוי לגמרי בכך שמשהו בתוך הגוף משתנה. שני האשמים הרגילים הם שכחת העדכון, ועדכון שמדלג מעבר לערך היציאה:
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++?
ודאו שמשהו בתוך הגוף בסופו של דבר הופך את התנאי ל-false (הקטנת מונה, קידום מצביע, הדלקת דגל). בלולאת while (true) מכוונת, שימו בפנים break שמוגן על ידי if. אם לולאה נתקעת, הסיבה הרגילה היא ששכחתם לעדכן את המשתנה שהתנאי תלוי בו.