Menu

If else ב-C: תחביר, דוגמאות וטעויות נפוצות

איך C מקבלת החלטות: פקודת if, else, שרשראות else if, קינון והאופרטור הטרנרי, ובנוסף כלל האמת (0 הוא שקר, כל השאר אמת) והבאג של = מול == ששובר תנאים בשקט.

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

למה תוכניות צריכות הסתעפויות

כל תוכנית עד עכשיו רצה ישר: שורה 1, שורה 2, שורה 3. תוכניות אמיתיות מקבלות החלטות. האם הסיסמה נכונה? האם המספר שלילי? האם הקובץ נפתח? פקודת if היא הדרך של C לשאול שאלה ולהריץ קוד רק כשהתשובה היא כן.

התנאי temperature > 30 נבדק פעם אחת. הוא מתקיים, ולכן ההודעה מודפסת. השורה האחרונה נמצאת מחוץ לסוגריים המסולסלים, ולכן היא מודפסת בכל מקרה. שנו את 31 ל-18 והריצו שוב: ההודעה הראשונה נעלמת והשנייה נשארת.

תחביר: סוגריים, סוגריים מסולסלים ובלי נקודה-פסיק

ל-if ב-C יש צורה קבועה:

if (condition) {
    // רץ כשהתנאי שונה מאפס
}

שלושה כללים ששווה לשנן מוקדם. הסוגריים סביב התנאי חובה. אין מילת מפתח then. ואין נקודה-פסיק אחרי הסוגר הסוגר: נקודה-פסיק תועה מסיימת את הפקודה בדיוק שם:

// באג: ה-if לא עושה כלום; ה-printf תמיד רץ
if (x > 10);
{
    printf("big\n");
}

זה מתקמפל בלי בעיה. ה-; הוא פקודה ריקה שהופכת לגוף של ה-if, והסוגריים המסולסלים שמתחתיו הם סתם בלוק עצמאי שתמיד רץ. קומפילציה עם gcc -Wall תופסת את זה.

הסוגריים המסולסלים עצמם אופציונליים עבור פקודה אחת, אבל השאירו אותם. if בלי סוגריים מסולסלים שבהמשך גדל לשורה שנייה הוא מקור קלאסי לבאגים, כי ב-C ההזחה לא מקבצת פקודות.

else ו-else if

else מספק את המסלול השני:

עבור יותר משתי תוצאות, שרשרו עם else if. C בודקת כל תנאי לפי הסדר ועוצרת בראשון שמתקיים:

הסדר חשוב כאן מאוד. מכיוון שהשרשרת עוצרת בהתאמה הראשונה, הבדיקה השנייה רואה רק ציונים מתחת ל-90, ולכן score >= 80 לא צריך להוסיף גם && score < 90. כתבו את השרשרת מהתנאי המחמיר ביותר לפחות מחמיר, אחרת כל ערך ייפול לענף הראשון.

ה-else בסוף אופציונלי. הוסיפו אותו בכל פעם שהשרשרת אמורה לכסות כל מקרה; היעדרו פירושו "אם שום דבר לא התאים, לא לעשות כלום", וזה בסדר, אבל צריך להיות מכוון.

ערכי אמת: 0 הוא שקר, כל השאר אמת

בשפה הבסיסית של C אין טיפוס בוליאני נפרד בתנאים. if פשוט שואל אם הביטוי שונה מאפס.

שתי השורות האחרונות מראות את החצי השני של הכלל: אופרטורי השוואה הם ביטויים רגילים שמפיקים 1 עבור אמת ו-0 עבור שקר. בגלל זה if (5 > 2) עובד: זה בעצם if (1).

זו גם הסיבה ש--3 הוא אמת ב-C. הכלל הוא שונה מאפס, לא חיובי. אם אתם רוצים לדעת אם מספר חיובי, כתבו if (n > 0), לא if (n).

C99 הוסיפה את <stdbool.h> עם טיפוס bool אמיתי ועם true ו-false, שנקראים טוב יותר בקוד חדש. מתחת למכסה הם עדיין 1 ו-0, כך ששום דבר בכלל שלמעלה לא משתנה. ראו את העמוד על בוליאנים ב-C.

אופרטורי ההשוואה והאופרטורים הלוגיים שתשתמשו בהם בתנאים:

==   equal to            &&   logical AND (both sides true)
!=   not equal to        ||   logical OR  (either side true)
<    less than           !    logical NOT
>    greater than
<=   less than or equal
>=   greater than or equal

&& ו-|| מבצעים short-circuit: a && b אף פעם לא מחשב את b אם a שקר, ו-a || b אף פעם לא מחשב את b אם a אמת. זו הבטחה, לא אופטימיזציה, ולכן בטוח לכתוב if (n != 0 && total / n > 5): החילוק לא יכול לרוץ כש-n הוא אפס.

הבאג של = מול ==

זו הטעות הנפוצה ביותר בתנאים ב-C:

// באג: משים 5 ל-x, ואז בודק 5 (שונה מאפס), אז זה תמיד רץ
if (x = 5) {
    printf("x is five\n");
}

C מאפשרת השמה בתוך ביטוי, ולכן השורה חוקית. היא שומרת 5 ב-x, מפיקה את הערך 5, ו-5 אינו אפס: הענף רץ בכל פעם, ו-x נדרס בשקט.

שתי הגנות. ראשית, תמיד קמפלו עם אזהרות:

gcc -Wall -Wextra program.c -o program

גם GCC וגם clang מסמנים "suggest parentheses around assignment used as truth value". שנית, יש מתכנתים שכותבים את הקבוע לפני המשתנה, if (5 == x), כך ששגיאת הקלדה כמו if (5 = x) תהיה שגיאת קומפילציה ולא באג שקט. הסגנון הזה עניין של טעם; הפעלת אזהרות לא.

קינון

if יכול להכיל if אחר. קינון מבטא תנאים שיש להם משמעות רק אחרי שתנאי קודם מתקיים:

שתי רמות קריאות. ארבע לא. כשהקינון מעמיק, חפשו דרך לשטח אותו: לעתים קרובות על ידי שילוב תנאים עם &&, או על ידי טיפול במקרי הכישלון קודם ויציאה מוקדמת:

// שטוח יותר: מטפלים בחריגים, ואז ממשיכים בעבודה
if (age < 18)     { printf("Adults only.\n");        return 0; }
if (!hasTicket)   { printf("Please buy a ticket.\n"); return 0; }
printf("Welcome in.\n");

ה-else התלוי

כש-if בלי סוגריים מסולסלים מקונן בתוך if אחר, לאיזה if שייך ה-else? הכלל של C: else נקשר ל-if הקרוב ביותר שעוד לא הותאם, בלי קשר לאיך שהקוד מוזח.

// ה-else שייך ל-if הפנימי, למרות ההזחה
if (a > 0)
    if (b > 0)
        printf("both positive\n");
else
    printf("a is not positive\n");   // שגוי: רץ כש-a > 0 ו-b <= 0

ההזחה אומרת שה-else מתאים ל-if החיצוני. הקומפיילר מתאים אותו לפנימי. סוגריים מסולסלים מבטלים את העמימות לגמרי, וזה הטיעון האמיתי לשימוש בהם תמיד:

if (a > 0) {
    if (b > 0) {
        printf("both positive\n");
    }
} else {
    printf("a is not positive\n");
}

האופרטור הטרנרי

כשהסתעפות קיימת רק כדי לבחור ערך, האופרטור המותנה ? : אומר את זה בביטוי אחד:

קראו את cond ? x : y כ"אם cond אז x, אחרת y". רק אחד משני הענפים מחושב, וכל הביטוי מפיק ערך, ולכן אפשר להשים אותו או להעביר אותו כארגומנט במקום שבו פקודה לא יכולה להופיע.

שמרו אותו לבחירות פשוטות של ערכים. אופרטורים טרנריים מקוננים (a ? b : c ? d : e) חוקיים וכמעט תמיד קשים יותר לקריאה משרשרת ה-else if שהם מחליפים.

שאלות נפוצות

איך כותבים פקודת if else ב-C?

שימו את התנאי בסוגריים ואת הקוד בסוגריים מסולסלים: if (score >= 60) { printf("Pass\n"); } else { printf("Fail\n"); }. בלוק ה-else רץ רק כשהתנאי שקר, ואין ב-C מילת מפתח then.

מה נחשב אמת בפקודת if ב-C?

כל ערך שאינו אפס. בתחביר הבסיסי של C אין טיפוס בוליאני ייעודי, ולכן if (n) רץ כש-n הוא כל דבר חוץ מ-0, ו-if (!n) רץ רק כש-n הוא בדיוק 0. אופרטורי השוואה כמו == ו-< מפיקים 1 עבור אמת ו-0 עבור שקר.

מה ההבדל בין = ל-== ב-C?

== משווה, = משים. הכתיבה if (x = 5) משימה 5 ל-x ואז בודקת את 5, שאינו אפס, ולכן הענף תמיד רץ. זה מתקמפל בלי שגיאה, ולכן זה הבאג הנפוץ ביותר של מתחילים בתנאים ב-C: רוב הקומפיילרים מזהירים עליו עם -Wall.

איך עובד האופרטור הטרנרי ב-C?

condition ? valueIfTrue : valueIfFalse הוא ביטוי שמפיק אחד משני ערכים, ולכן אפשר לשים אותו בתוך השמה או כארגומנט של printf: int max = a > b ? a : b;. השתמשו בו כדי לבחור ערך, וב-if רגיל כשצריך להריץ פקודות.

איור של שפות התכנות ב-Coddy

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

להתחיל