לדלג לתוכן

C++/תנאים

מתוך ויקיספר, אוסף הספרים והמדריכים החופשי
< C++

התוכניות שכתבנו עד כה פעלו באופן זהה כל פעם כשהרצנו אותן. אומנם לפעמים נרצה לגרום למחשב לבצע פעולות שונות בהתאם לקלט או מצב התוכנית עצמה. כדי לעשות זאת עלינו לגרום למחשב לבדוק איזשהו תנאי ובהתאם לתוצאה שהוא יקבל (האם התנאי אמיתי או שקרי) לבצע שורות קוד שונות. ב־C++‎ ישנם שני משפטי קבלת החלטה (if ו־switch) ואופרטור התניה אחד. נסביר את פעולתם בפרק זה.

משפט if

[עריכה]

משפט הבקרה הבסיסי שבודק תנאי כלשהו הוא משפט ה־if:

if(expression)
    // code

קרי: "אם ... אז ...". משפט זה יבדוק את התנאי שנכתוב בין הסוגריים (expression) ואם הוא מתקיים אז הוא יבצע את הקוד שבא אחריו, אם התנאי לא נכון אז הוא ידלג על קוד זה. הבדיקה נעשית על ידי חישוב הערך של הביטוי הנתון, ואם יש צורך בכך, המרתו לטיפוס בוליאני (bool). אם התוצאה היא true אז התנאי הוא נכון (אמיתי) והשורה הבאה אחרי ה־if תתבצע. אם ערך הביטוי הוא false אז השורה הבאה אחרי ה־if לא תתבצע.

להלן דוגמה לשימוש במשפט זה:

int a;
cin >> a;

if(a < 0)
    cout << "The number you've entered is negative.\n";
cout << "The number you've entered is " << a << endl;

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

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

double a;
cin >> a;

if(a < 0)
{
    cout << "The number you've entered is negative, it is treated as zero.\n";
    a = 0;
}

cout << "sqrt(" << a << ") = " << sqrt(a) << endl;

קטע קוד זה יבדוק האם המספר שהוזן שלילי, אם הוא אכן שלילי אז התוכנית תבצע את כל הפקודות שנמצאות בין הסוגריים המסולסלים. במקרה זה תודפס הודעה שהמספר הוא שלילי והתוכנית תציב לתוך המשתנה את המספר 0. אם התנאי שקרי (המספר שהוזן הוא חיובי או שווה לאפס) אז התוכנית תדלג ישר לשורה השמינית. בכל מקרה התוכנית תדפיס את השורש הריבועי של המספר שהוקלד (אם הוא חיובי) או שורש של אפס (אם הוא שלילי).

משפט if else

[עריכה]

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

if(expression)
    // code 1
else
    // code 2

קרי: "אם ... אז ... אחרת ...". משפט זה יבדוק את התנאי ואם הוא נכון יבצע את קטע קוד הראשון (בדומה ל־if רגיל), אבל אם התנאי הוא לא נכון יתבצע קטע קוד השני, זה שאחרי המילה השמורה else. נשתמש במשפט זה כשנרצה שרק אחד מהקטעים יתבצע. לדוגמה, נשנה את הדוגמה עם השורש הריבועי:

double a;
cin >> a;

if(a < 0)
    cout << "Can't calculate the square root of negative number.\n";
else
    cout << "sqrt(" << a << ") = " << sqrt(a) << endl;

גם כאן נוכל להוסיף סוגריים כדי לבצע מספר פקודות אחרי ה־else.

משפט else if

[עריכה]

בתקן שפת C++‎ עצמה לא מוגדר משפט מהסוג הזה (לעומת שפות אחרות כמו Visual Basic לדוגמה). למרות זאת עדיין ניתן להרכיב מבנה כזה:

if(expression)
    // code 1
else if(expression)
    // code 2
else
    // code 3

מבנה כזה הוא שני משפטי "אם ... אז ... אחרת ..." המקוננים אחד בתוך השני, כלומר משפט ה־if השני משחק תפקיד של פקודה שבאה בתוך בלוק ה־else של המשפט הראשון. נתבונן בדוגמה הבאה:

int a;
cin >> a;

if(a > 0)
    cout << a << " is positive.\n";
else
{
    if(a < 0)
        cout << a << " is negative.\n";
    else
        cout << "It's zero.\n";
}

כיוון שמשפט תנאי if הוא פקודה אחת בפני המהדר, נוכל להוריד את צמד הסוגריים המסולסלים. כמו כן שפת C++‎ מתעלמת מרווחים                וירידות

שורה, לכן נוכל להעלות את ה־if לשורה של ה־else. זכרו שכיוון שאלה הן שתי מילות שמורות נפרדות, כפי שהוסבר כאן, יש להפריד אותן עם רווח, אין לכתוב elseif ביחד.

int a;
cin >> a;

if(a > 0)
    cout << a << " is positive.\n";
else if(a < 0)
    cout << a << " is negative.\n";
else
    cout << "It's zero.\n";

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

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

משפט if else מקוצר

[עריכה]

נאתחל משתנה bool x=true, ניתן לשאול באופן מקוצר ולתת פקודה בשורת השאלה הבוליאנית.

bool x = true;
	x ? cout << "true" : cout << "false";

זהו קיצור של if ו else באותו משפט, כשהסימן : משמש else. האם הביטוי משמאל ל(?) אמת? אם כן, אז הביטוי האמצעי יופעל, אם לא, אז הביטוי בסוף יופעל.

משפט switch

[עריכה]

נתבונן בדוגמה הבאה:

cout << "Do you like apples (Y or N)?\n";

char answer;
cin >> answer;

if(answer == 'Y')
    cout << "Take an Apple!\n";
else if(answer == 'N')
    cout << "It's your problem...\n";
else
    cout << "I can't understand you...\n";

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

switch(answer)
{
case 'Y':
    cout << "Take an Apple!\n";
    break;

case 'N':
    cout << "It's your problem...\n";
    break;

default:
    cout << "I can't understand you...\n";
}

בדוגמה הפשוטה הזאת לא נראה יתרון רב, היא אף תופסת יותר מקום. אך כתיב כזה לא רק ברור יותר אלא גם במקרים רבים דווקא מקצר את התוכנית.

משפט זה נקרא גם הוראת בחירה כיוון שהתוכנית בוחרת את אחת האפשרויות המפורטות אחרי ה־switch. נסביר את אופן הפעולה של המשפט הזה. תחילה התוכנית מחשבת את הביטוי שנרשם בין הסוגריים אחרי ה־switch. תוצאת הביטוי צריכה להיות מטיפוס שלם כלשהו (int, char, short ...). לאחר מכן התוכנית קופצת לאפשרות ה־case המתאימה. במקרה ואף אחד מהערכים הקבועים שרשמנו אחרי ה־caseים לא שווה לערך הביטוי הנבדק, התוכנית תקפוץ לחלק ה־default (ברירת מחדל), במקרה והוא קיים. שימו לב שאין מיגבלות לסדר שבו נרשום את כל האפשרויות, גם את ה־default ניתן לרשום בהתחלה, באמצע או בכלל לא לרשום.

פקודת ה־break אינה חלק בלתי נפרד מהמשפט הזה. כפי שנראה בעתיד בלולאות, פקודה זו משמשת ליציאה מבלוק פקודות שתחום בסוגריים מסולסלים וששייך ללולאה או להוראת בחירה. כאשר התוכנית מגיע להוראת ה־break היא תצא מתוך הבלוק של הוראת הבחירה ותמשיך הלאה, היא לא תבצע את הפקודות שבתוך הבלוק. במקרה שלנו, למשל אם answer מכיל את התו 'N' ואנחנו לא נרשום את הוראות ה־break, התוכנית תדפיס "It's your problem...\n" ותמשיך לחלק ה־default שבו תפלוט את המחרוזת "I can't understand you...\n". כתוצאה על המסך יופיעו שתי שורות שונות, במקום אחת.

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

switch(answer)
{
case 'y':
case 'Y':
    cout << "Take an Apple!\n";
    break;

case 'n':
case 'N':
    cout << "It's your problem...\n";
    break;

default:
    cout << "I can't understand you...\n";
}

בדוגמה זו המשתמש אינו חייב להקליד דווקא אות גדולה, התוכנית תבין את תשובתו ללא תלות בגודל האות. אם למשל יקליד המשתמש את התו 'n', אז התוכנית תקפוץ ל־case השלישי ותמשיך עד לפקודת ה־break.

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

[עריכה]

אופרטור התניה הוא אופרטור טרנארי, כלומר הוא מקבל שלושה אופרנדים. אופרטור זה יראה כך:

expression ? true_expression : false_expression

אופרטור זה דומה למשפט if else רגיל; הוא יחשב את הביטוי הראשון (expression), ימיר את ערכו לערך בוליאני, ובהתאם לערך זה יחשב ויחזיר את ערך אחד מהביטויים true_expression או false_expression.

ניתן להשתמש באופרטור זה בדרכים שונות. לרוב משתמשים בו כדי לקצר משפטים מהסוג הזה:

int max;
if(a>b)
    max = a;
else
    max = b;

באמצעות המשפט הזה הקוד מקוצר עד לשורה אחת:

int max = a>b?a:b;

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

int result = b!=0 ? a/b : throw math_error();

במקרה ש־b שווה לאפס, הקוד יזרוק חריגה (throw).


הפרק הקודם:
משתנים
תנאים הפרק הבא:
לולאות