Menu

לולאת do while ב-C: תחביר, דוגמאות ומתי להשתמש בה

הלולאה של C שהגוף שלה בא קודם: איך do-while מבטיחה סיבוב אחד לפני הבדיקה, למה היא מסתיימת בנקודה ופסיק, תבניות התפריט והניסיון החוזר שבשבילן היא נוצרה, ובמה היא שונה מלולאת while רגילה.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

הלולאה שתמיד רצה פעם אחת

לולאת while בודקת לפני שהיא פועלת, כך שהיא יכולה לרוץ אפס פעמים. זה בדרך כלל נכון. לפעמים זה בדיוק לא נכון: אי אפשר לדעת אם לחזור על בקשה לקלט עד שהצגתם אותה, ואי אפשר לשפוט את הקלט של המשתמש עד שקראתם משהו. do-while מעבירה את הבדיקה לסוף, כך שהגוף רץ קודם והתנאי מחליט רק אם לרוץ שוב.

התנאי i < 5 שקרי כבר מההתחלה. לולאת ה-while רצה אפס פעמים; ה-do-while רצה בדיוק פעם אחת. זה כל ההבדל ביניהן.

התחביר, והנקודה ופסיק הזו

do {
    // body - always runs at least once
} while (condition);

הסדר נקרא כמו שהוא מתבצע: עשו (do) את הגוף, כל עוד (while) התנאי מתקיים, עשו אותו שוב.

הנקודה ופסיק שאחרי הסוגר הסוגר היא חובה. 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') { }   /* discard the bad line */
        age = -1;                        /* force another pass */
    }
} 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

ללמוד תכנות עם Coddy

להתחיל