3. פקודות תנאי

התכניות שכתבנו עד כה התקדמו סדרתית (כלומר פקודה אחר פקודה), מהפקודה הראשונה ועד האחרונה (או עד הסוף המר). במקרים רבים אנו זקוקים לתכניות שבהן פקודות מסוימות מתבצעות כתלות בערכם של משתנים שונים (למשל לא נרצה לבצע פעולת חילוק עת ערכו של המחלֵק הוא אפס). פקודות התנאי שנכיר בַפרק הנוכחי, ופקודות הלולאה שנכיר בפרק הבא, הן שתאפשרנה לנו להתקדם בצורה יותר מתוחכמת מהאופנות הסדרתית, ולבצע פקודות שונות בתכנית רק במידת הצורך. אנו אומרים שפקודות התנאי והלולאה הן פקודות בקרה (control statements) במובן זה שהן מבקרות את התקדמות התכנית: הן קובעות לאן תתקדם התכנית בכל שלב (על-פי ערכי המשתנים).

בפרק הנוכחי נלמד את שתי פקודות התנאי (if-else, switch). בנוסף להן נכיר את אופרטור ה: ? (שהינו if-else קטן), וכן את הטיפוס bool

3.1 פקודות ה: if (ללא else)

פקודת ה- if היא פקודת התנאי הראשונה שנכיר. תחילה נכיר אותה בצורתה המצומצמת: ללא else, ואחר כך בצורתה הכללית: עם אפשרות ל- else. לצידה של פקודת ה- if-else קיימת פקודת תנאי נוספת, פקודת ה- switch, ואותה נכיר בַהמשך.

פקודת ה: if, חלק ב'


פקודת ה: if, חלק א'


קוד התכנית הכולל פקודת if

#include <iostream>

using std::cin ;

using std::cout ;

using std::endl ;

int main() {

int num1, num2;

cout << "Enter two integer numbers: " ;

cin >> num1 >> num2 ;

cout<< num1 << “ + ” << num2 <<“ = ”<< num1+num2<< endl;

cout<< num1 << “ - ” << num2 <<“ = ”<< num1-num2<< endl;

cout<< num1 << “ * ” << num2 <<“ = ”<< num1*num2<< endl;

if (num2 != 0)

cout << num1 << “ / ” << num2 << “ = ” << num1/num2<< endl;

if (num2 == 0)

cout << "Cannot divide by zero" << endl ;

cout << "bye" ;

return 0 ;

}

הסבר כתוב אודות תכנית הכוללת if (ללא else)

3.1.pdf

תרגול עצמי בסיסי בנושא פקודת if

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

3.2 תוספת else

פקודת if-else, חלק ב'


פקודת if-else, חלק א'


קוד תכנית הכוללת if-else

#include <iostream>


using std::cin ;

using std::cout ;

using std::endl ;


int main()

{

int num1, num2 ;


cin >> num1 >> num2 ;


if (num1 <= num2)

cout << num1 << " " << num2 << endl ;

else

cout << num2 << " " << num1 << endl ;


return 0 ;

}


הסבר כתוב אודות if-else

3.2.pdf

תרגול עצמי בסיסי בנושא if-else

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

3.2.1 + 3.2.2 הערכה מקוצרת של ביטויים בולאניים (תנאים), ותנאים מקוננים (nested)

הסבר כתוב בנושא הערכה מקוצרת של ביטויים בולאניים, ותנאים מקוננים

3.2.1-3.2.2.pdf

תרגול עצמי בסיסי בנושא if-else ותנאים מקוננים

כתבו תכנית הקוראת מהמשתמש שני מספרים שלמים.

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

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

אם המספר הראשון אינו גדול מאפס:

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

3.2.3 מיון שלושה מספרים (גרסה א')

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

קוד התכנית הממיינת שלושה מספרים (גרסה א')

/*******************************************************/

//

// Sorting three integers

// ======================

// Written by: Yosi Cohen, id: 333444555, login: yosico, Class: A1

//

// This program reads from the user three ints and

// displays them sorted from smallest to largest.

// The program examines the six combinations of size

// (e.g., the first is smaller than the second that is

// smaller than the third).

/*******************************************************/

#include <iostream>

using std::cin ;

using std::cout ;

using std::endl ;

int main()

{

int first, second, third ; // the 3 inpt nums

cout << "Enter three integer numbers: " ;

cin >> first >> second >> third ;

cout << “The sorted list is: " ;

if (first <= second && second <= third) // 1st smlst

cout << first <<" "<< second <<" "<< third <<endl ;

if (first <= third && third <= second)

cout << first <<" "<< third <<" "<< second <<endl ;

if (second <= first && first <= third) // 2nd smlst

cout << second <<" "<< first <<" "<< third <<endl ;

if (second <= third && third <= first)

cout << second <<" "<< third <<" "<< first <<endl ;

if (third <= second && second <= first) // 3rd smlst

cout << third <<" "<< second <<" "<< first <<endl ;

if (third <= first && first <= second)

cout << third <<" "<< first <<" "<< second <<endl ;

return 0 ;

}

הסבר כתוב אודות התכנית הממיינת שלושה מספרים (גרסה א')

התכנית שהצגנו פשוטה למדי (וזו תכונה רצויה) יחד עם זאת יש לה שתי מגבלות:

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

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

לכן עתה נציג תכנית שניה אשר מבצעת אותה משימה באופן אחר.

3.2.4 מיון שלושה מספרים (גרסה ב')

גרסה זאת אסביר רק באמצעות טקסט כתוב, ללא סרטון נלווה

3.2.4.pdf

3.2.5 מיון שלושה מספרים (גרסה ג')

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

קוד התכנית הממיינת שלושה מספרים (גרסה ג')

#include <iostream>


using std::cin ;

using std::cout ;

using std::endl ;


int main()

{

int first, second, third ; // the 3 inpt nums


cin >> first >> second >> third ;


if (first < second)

{

if (second < third)

cout << first << second << third ;

else // first < second && second >= third

// that is: second is the greatest

// we do not know, yet,

// who is the smallest

// so we need another if:

if (first < third)

cout << first << third << second ;

else

cout << third << first << second ;

}

else // first >= second

{

if (second > third)

cout << third << second << first ;

else // first >= second && third >= second

// that is: second is smallest.

// now, check who is largest:

if (first > third)

cout << second << third << first ;

else

cout << second << first << third ;

}

return 0 ;

}


הסבר כתוב אודות התכנית הממיינת שלושה מספרים (גרסה ג')

3.2.5.pdf

3.2.6 פתרון משוואה ריבועית

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

משוואה ריבועית היא ביטוי מהצורה: y= a*x2 +b*x + c, עבור a, b, c שהינם מספרים ממשיים כלשהם. לדוגמה: y = 4*x2 +3*x – 8 או y = -2*x2 +18 הן משוואות ריבועיות. שורשי המשוואה הריבועית הם מספרים אשר אם יוצבו במקום x יגרמו לכך שערכו של y יהיה אפס. לדוגמה שורשי המשוואה השניה מבין השתיים שהצגנו הם 3, ו- -3 . רובכם ודאי זוכרים כי הנוסחה למציאת שורשי משוואה ריבועית (המסומנים כ- x1, x2) היא:

x1, x2 = [ -b +- sqrt(b2 –4*a*c) ] / [2*a]

כאשר הביטוי (...) sqrt מסמן את השורש של הערך המופיע בתוך הסוגריים.

לביטוי: b2 –4*a*c נהוג לקרוא בשם דיסקרימיננטה.

נרצה עתה לכתוב תכנית אשר קולטת מהמשתמש שלושה מספרים ממשיים המהווים מקדמים של משווה ריבועית (כדוגמת: 2- 0 ו- 18). התכנית תציג למשתמש את שורשי המשוואה.

לפני שנפנה להצגת התכנית נסביר כי בשפת C קיימת פונקציה אשר עת מעבירים לה ערך מחזירה את השורש החיובי שלו. הפונקציה נקראת sqrt, היא מקבלת פרמטר מטיפוס double (כלומר מספר רציונלי שעשוי להיות גדול במיוחד), ומחזירה ערך מאותו טיפוס. כדי להשתמש בפונקציה זאת, כמו גם בפונקציות מתמטיות אחרות, יש להוסיף לתכנית שורת include נוספת:

<include <cmath# (אין צורך בתוספת של פקודת using).

קוד תכנית הפותרת משווה ריבועית (גרסה א')

#include <iostream>

#include <cmath>

using std::cin ;

using std::cout ;

using std::endl ;

int main()

{

double param_a, param_b, param_c,

discriminant ;

cin >> param_a >> param_b >> param_c ;

discriminant = param_b * param_b – (4 * param_a * param_c) ;

if (discriminant < 0)

cout << "No solution" << endl ;

else

{

double x1, x2 ;

discriminant = sqrt(discriminant);

x1 = (-param_b + discriminant) / (2 * param_a) ;

x2 = (-param_b – discriminant) / (2 * param_a) ;

cout << x1 << " " << x2 ;

}

return 0 ;

}

הסבר אודות תכנית הפותרת משוואה ריבועית (גרסה א')

3.2.6a.pdf

קוד תכנית הפותרת משוואה ריבועית (גרסה ב')

#include <iostream>

#include <cmath>

using std::cin ;

using std::cout ;

using std::endl ;

int main()

{

double param_a, param_b, param_c,

discriminant ;

cin >> param_a >> param_b >> param_c ;

if (param_a == 0) // a linear equation

if (param_b == 0) // a constant function

if (param_c == 0)

cout << "Every x is a root" << endl ;

else

cout << "No roots" << endl ;

else // a 'real' linear eq.

cout << (-param_c)/param_b ;

else // a 'real' quadratic eq.

{

discriminant = param_b * param_b – (4 * param_a * param_c) ;

if (discriminant < 0)

cout << " No roots " << endl ;

else if (discriminant == 0)

cout << (-param_b)/ (2 * param_a) ;

else

{

double x1, x2 ;

discriminant = sqrt(discriminant);

x1 = (-param_b + discriminant) / (2 * param_a) ;

x2 = (-param_b – discriminant) / (2 * param_a) ;

cout << x1 << " " << x2 ;

}

}

return 0 ;

}

הסבר אודות תכנית הפותרת משוואה ריבועית (גרסה ב')

3.2.6b.pdf

3.2.7 שרשרת של if-else (והערה קטנה על n\ במחרוזת)

בסעיף זה אסביר כיצד נכתוב קוד הכוללת שרשת של if ו- else

3.2.7.pdf

תרגול עצמי בסיסי בנושא שרשרת של if-else

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

אם המספר הוא שלילי הודיע שהקלט שגוי.

אחרת, אם המספר קטן מ- 2 הודיעו שזה תינוק;

אחרת, אם המספר קטן מ- 12 הודיעו שזו ילדה;

אחרת אם המספר קטן מ- 18 הודיעו שזה נער;

אחרת אם המספר קטן מ- 65 הודיעו שזו בוגרת;

אחרת הודיעו שזה זקן.

3.3 משתנים בולאניים

בסעיף זה אסביר את הצורך במשתנים מטיפוס bool, ואת האופן בו ניתן לעשות בהם שימוש

קוד התכנית המסווגת משולשים, ועושה שימוש במשתנים בולאניים

#include <iostream>


using std::cin ;

using std::cout ;


int main() {

int edge1, edge2, edge3 ;


cin >> edge1 >> edge2 >> edge3 ;


if (edge1 <= 0 || edge2 <= 0 || edge3 <= 0 ||

edge1 >= edge2 + edge3 ||

edge2 >= edge1 + edge3 ||

edge3 >= edge1 + edge2 )

cout << "Illegal input\n" ;

else if (edge1 == edge2 && edge2 == edge3)

cout << "equilateral\n" ;

else

{

bool isosceles = false, // 2 sides equal

right_angle = false ;


if (edge1 == edge2 || edge2 == edge3 || edge1==edge3)

isosceles = true ;


if (edge1*edge1 == edge2*edge2 + edge3*edge3 ||

edge2*edge2 == edge1*edge1 + edge3*edge3 ||

edge3*edge3 == edge2*edge2 + edge1*edge1 )

right_angle = true ;

if (isosceles == true && right_angle == true)

cout << "isosceles and right_angle\n" ;

else if (isosceles == true)

cout << "isosceles\n" ;

else if (right_angle == true)

cout << "right angle\n" ;

else

cout << "a simple triangle\n" ;

}

return 0 ;

}



הסבר כתוב אודות משתנים בולאניים

3.3.pdf

תרגול עצמי בסיסי בנושא משתנים בולאניים

כתבו תכנית הקוראת מהמשתמש שני מספרים שלמים.

התכנית תציין לעצמה במשתנה הבולאיני pos האם שני המספרים חיוביים ממש, או לא נכון ששני המספרים חיוביים ממש.

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

עתה התכנית תודיע:

א. האם שני המספרים חיוביים וזוגיים.

ב. האם שני המספרים חיוביים, אך לא שניהם זוגיים

ג. האם שני המספרים זוגיים אך לא שניהם חיוביים

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

3.4 פקודת ה: switch

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

הסבר כתוב אודות פקודת ה: switch

3.4.pdf

תרגול עצמי בסיסי בנושא פקודת ה: switch

כתבו תכנית הקוראת מהמשתמש מספר שלם המציין חודש בשנה, על התכנית להדפיס את שמו של החודש (לדוגמה: אם הוזן 4 אזי יודפס April). אם הוזן מספר שאינו בתחום 1..12 התכנית תודיע על שגיאה.

3.5 אופרטור ה: ?

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

3.5.pdf

תרגול עצמי בסיסי בנושא אופרטור ה: ?

כתבו תכנית הקוראת מהמשתמש מספר שלם, ומכניסה למשתנה שלם pos_even את הערך 1 אם המספר שנקרא הוא זוגי חיובי; ומכניסה ל pos_even את הערך 1- אם התנאי הנ"ל אינו מתקיים. כתבו את ההשמה באמצעות אופרטור הסימן שאלה.

3.6 תרגילים

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

הערות לתרגילים (התקפות לכל התרגילים בכל הקורס)

הקפידו על סגנון תכנותי, בפרט על:

1. תיעוד על כל מרכיביו (ראשי, משתנים, במידת הצורך גם תיעוד בגוף הקוד: בפרט ובמיוחד בתכנית בה יש מקרים\מצבים שונים, באיזה תת-מקרה או תת-מקרים זיהיתם, עד כה, שאתם מצויים).

2. עימוד.

3. שמות משתנים.

4. תכנית קריאה ולא מסורבלת.

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

הישמרו מלשלוח מבט, ולוּ חטוף, בתכניתו של חברכם המלומד! לכל היותר אפשרו לו להסביר לכם מילולית מה היה הרעיון שבאמצעותו הוא פתר את התכנית בְקַלולה.

3.6.pdf