שפת C מציעה לנו שלושה סוגי לולאות "רשמיים" – דרכים לחזור על קטע קוד מסוים שוב ושוב. כל סוג לולאה פועל בצורה שונה מעט, ואנחנו בוחרים את הסוג הרצוי לנו לפי דרישות התוכנה. בפוסט זה אציג את סוגי הלולאות של C, כולל דוגמאות בסיסיות לשימוש.
לולאת while
while (תנאי) { פקודות }
הלולאה הראשונה שאציג, והפשוטה ביותר (לפחות מבחינת הכתיבה) היא לולאת while. לולאה זו כוללת תנאי אחד בתחילתה, וכל עוד התנאי הזה מתקיים – כלומר, ערך הביטוי שמופיע בו הוא true או ערך מספרי שאינו 0 – הקוד שבתוך הלולאה יבוצע שוב ושוב. הטריק ב-while הוא שהתנאי מופיע בתחילת הלולאה, לפני שהקוד שבפנים מבוצע, כך שייתכן בהחלט שהוא לא יבוצע כלל.
לדוגמה, נניח שיש לנו תוכנה לארדואינו עם פונקציה בשם errorCode, שמחזירה קוד של תקלה במערכת. כאשר הערך המוחזר מהפונקציה הוא 0, פירוש הדבר שאין שום תקלה. בשלב מסוים בתוכנית אנחנו צריכים לבדוק אם יש תקלות ולטפל בהן. נעשה זאת בעזרת לולאת while:
while (errorCode() != 0) { // הודעה למשתמש להמתין בסבלנות בזמן הטיפול בתקלה Serial.println("Please wait, taking care of an error..."); // קריאה לפונקציה שמטפלת בתקלה takeCareOfError(); }
אם אין שום תקלה, התנאי בשורה הראשונה יהיה false והתוכנית תדלג על הלולאה כולה. לעומת זאת, אם הוחזר מהפונקציה ערך שאינו 0, הארדואינו ישלח למוניטור הסריאלי הודעה, יטפל בבעיה ויחזור שוב לבדיקת התנאי.
לולאת do…while
do { פקודות } while (תנאי);
לולאת do…while דומה מאד ללולאת while, פרט להבדל חשוב אחד: בדיקת התנאי מתבצעת בה בסוף, לא בהתחלה. זה אומר שהקוד שבתוך הלולאה יבוצע לפחות פעם אחת, לא משנה מה.
נניח, לדוגמה, שיישום הארדואינו שלנו הוא מערכת מאובטחת שמצריכה שם משתמש וסיסמה. בכל מקרה נרצה שהמשתמש יזין אותם בזמן ההפעלה, אבל אם הוא טעה והזין מידע שגוי, פשוט ניתן לו עוד ועוד הזדמנויות לנסות. למען הנוחות, קיבלנו שתי פונקציות מוכנות מראש – getUsernameAndPassword שמטפלת בקליטת המחרוזות, ו-validLogin שבודקת אם המידע חוקי ומחזירה true או false בהתאם.
do { Serial.println("Enter user name and password:"); getUsernameAndPassword(); } while (!validLogin());
לולאת for
// A = אתחול // B = בדיקה // C = שינוי for (A; B; C) { פקודות }
לולאת for היא הלולאה "החזקה" והגמישה ביותר בשפת C, אשר מעניקה למתכנת מקסימום אפשרויות ושליטה. כמובן, זה לא אומר שהיא תמיד הכי יעילה או הכי נוחה – אחרת לא היה צורך בלולאות האחרות…
כל אחד מרכיבי הבקרה של הלולאה, אותם ציינתי למעלה באותיות A, B ו-C, הוא אופציונלי לגמרי: אפשר, בעיקרון, לכתוב לולאה כזו:
for ( ; ; ) { פקודות }
והפקודות פשוט ירוצו שוב ושוב ללא הפסקה.
הרכיב הראשון (A) הוא האתחול. הוא מתבצע פעם אחת בלבד, לפני שהפקודות מתחילות לרוץ. מכיוון שהשימוש השגרתי של for הוא לחזור על פקודות מספר נתון של פעמים, משתמשים בדרך כלל ברכיב זה כדי לאתחל את המונה של הלולאה, כמו בדוגמה זו:
for (byte i = 0; i < 10; i++) { פקודות }
רכיב B בדוגמה לעיל (i < 10) הוא הבדיקה. כמו בלולאת while, הבדיקה מתבצעת אחרי האתחול ולפני הרצת הפקודות, כך שייתכן מצב בו הפקודות בתוך לולאת for מסוימת לא ירוצו אפילו פעם אחת.
רכיב C משמש, בדרך כלל, להגדלת המונה של הלולאה. אם הלולאה סופרת לאחור ממספר גבוה לנמוך, אפשר לכתוב ב-C קוד שדווקא מקטין את המונה – וכמובן גם דברים פרועים יותר, כגון חילוק המונה בשתיים, העלאתו בריבוע או קריאה לפונקציה שעושה משהו אחר לגמרי. רכיב זה מבוצע בסיום הרצת הפקודות שבלולאה, ומיד אחריו מתבצעת שוב הבדיקה B.
פקודה בודדת
בכל הדוגמאות הקודמות הקפתי את הפקודות שהלולאות מריצות בסוגריים מסולסלים ("{}"). זה חיוני כאשר יש יותר מפקודה אחת, אבל אם הלולאה מבצעת פקודה יחידה, אפשר לוותר על הסוגריים האלה. למעשה, לולאות יכולות להריץ פקודה ריקה לגמרי. לדוגמה, נניח שהתוכנית שלנו מחכה לקלט מהחיבור הטורי ולא צריכה לעשות שום דבר עד שהקלט הזה יגיע:
while (Serial.available() == 0) ;
הלולאה הרביעית
בתחילת הפוסט ציינתי ששלושת סוגי הלולאות שהוזכרו הם "רשמיים". כתבתי את זה כי יש עוד דרך, רביעית, לחזור על פקודות שוב ושוב. דרך זו לגמרי לא מומלצת (מסיבות טובות מאד), ולמעשה נחשבת כמעט טאבו בכל שפת תכנות פרט לאסמבלי. היא מבוססת על הפקודה goto, שמאפשרת לנו לקפוץ ישירות למיקום כלשהו בקוד שלנו. כדי למנוע אסונות תכנות שונים ומשונים אני לא אסביר כאן איך לבצע לולאה בעזרת goto, ואחכה עם זה עד לפוסט הבא בסדרת C למתחילים, שידבר על הדרכים ששפת C מציעה לנו כדי "לשבור" לולאות.
תודה רבה !
אבל, יש גם לולאת case לא?
אני ממש לא זוכר מה היא עושה…
case זו לא לולאה אלא מין if לאפשרויות מרובות. עוד נגיע לזה 🙂
יותר נכון switch,מאוד שימושי
נכון, switch – פשוט בפסקל זה נקרא case אז מבחינתי זה אותו דבר 🙂
אפשר לשלוח לך שאלה ותעזור לי בפתרון
בעיקרון לא – אם אענה לכל שאלה אישית לא יישאר לי זמן לחיות… אבל אם זה משהו שעשוי לעניין עוד קוראים, אפשר לכתוב את השאלה כאן ואשתדל לענות.
וואו, מדריך מצויין!
לימד אותי מספר דברים שלא ידעתי או שלא ידעתי בדיוק
אחלה שיעור, שני דברים שמפריעים לי:
1. אתה משתמש בסוג המשתנה byte, שאני מניח שקיים בארדואינו, אבל בשפת C אין סוג משתנה כזה.
2. רק מC99 מותר להצהיר על המשתנה בתוך לולאת הfor עצמה. הניסוח המסורתי הוא:
int i;
for( i=1; i<10; ++i )
{
}
תודה. בתחילת הסדרה הזו כתבתי שלא חסרים מדריכים מצוינים לשפת C "רגילה", ולכן אני מתמקד כאן, כמו שאמרת, במימוש שלה בסביבת הפיתוח של ארדואינו.