1k likes | 1.28k Views
תרגול 6: פונקציות, סוגי משתנים, top-down design. מה היה שבוע שעבר?. לולאות מערכים מערכים דו-ממדיים. והיום נלמד. פונקציות מחסנית הקריאות סוגי משתנים Top-Down design. מבוא לפונקציות תזכורת מההרצאה. פונקציות ב- C.
E N D
תרגול 6: פונקציות, סוגי משתנים, top-down design
מה היה שבוע שעבר? • לולאות • מערכים • מערכים דו-ממדיים מבוא למדעי המחשב מ' - תירגול6
והיום נלמד • פונקציות • מחסנית הקריאות • סוגי משתנים • Top-Down design מבוא למדעי המחשב מ' - תירגול6
מבוא לפונקציותתזכורת מההרצאה מבוא למדעי המחשב מ' - תירגול6
פונקציות ב-C • ניתן להתייחס לפונקציה כמו קופסה שחורה שמקבלת ערכים (פרמטרים) ומחזירה תוצאת חישוב עליהם (ערך החזרה). • ראינו בעבר דוגמאות לפונקציות: printf, scanf... • אנחנו יכולים ליצור פונקציות משל עצמנו לפי הצורך. • יש להבדיל בין קריאה לפונקציה, שעושה שימוש בפונקציה כקופסא שחורה (כפי שעשינו עם printf ,scanf), לבין הגדרת הפונקציה והמימוש שלה, שם מתבצע החישוב בפועל. פרמטרים (מידע מועבר לפונקציה) ערך מוחזר (תוצאה המתקבלת מהפונקציה) מבוא למדעי המחשב מ' - תירגול6
דוגמה – מימוש פונקציה • ננתח את הפונקציה הבאה, שמקבלת שני מספרים ומחזירה את ההפרש ביניהם בערך מוחלט. • לכל פונקציה יש חתימה: הטיפוס המוחזר ע"י הפונקציה מופיע לפני שמה. בסוגריים: רשימת הפרמטרים (מופרדים בפסיקים ביניהם). שם הפונקציה. float delta(float a, float b) { float result = a – b; if (result < 0) result = -result; return result; } מבוא למדעי המחשב מ' - תירגול6
דוגמה - המשך • רכיבים נוספים של הפונקציה: משתנה מקומי:קיים רק בתוך הפונקציה, בזמן שהפונקציה פועלת. "נשכח" לאחר סיום פעולת הפונקציה. float delta(float a, float b) { float result = a – b; if (result < 0) result = -result; return result; } גוף הפונקציה ההוראה return משמשת לקביעת הערך המוחזר על-ידי הפונקציה. זה בעצם הערך שהפונקציה מחשבת. בדוגמה אנו יכולים להחזיר את resultכי ערך החזרה של deltaמהטיפוס המתאים מבוא למדעי המחשב מ' - תירגול6
פקודת return • פעולת return מסיימת את הפונקציה הנוכחית, וההרצה נמשכת מהמקום בו קראנו לפונקציה. • הערך שהועבר ל-return הוא הערך "שהפונקציה מחזירה", כלומר התוצאה. • כאשר הפונקציה לא מחזירה ערך ("טיפוס" מוחזר void), return לא מקבלת ערך (וגם לא הכרחית לכתיבה). • כאשר הפונקציה מחזירה ערך, הפקודה return עם טיפוס מתאים הכרחית בכל מסלולי החישוב.
mainכפונקציה • פונקציית ה-main() היא נקודת ההתחלה של כל תוכנית, והיא נקראת ע"י מע' ההפעלה. • חתימת הפונקציה: • ביצוע return עם ערך כלשהו מתוך main() מסיים את ריצת התוכנית ומחזיר את אותו ערך למע' ההפעלה. • בד"כ נהוג: • החזרת 0 בסיום תקין • כל ערך אחר בשגיאה int main(); מבוא למדעי המחשב מ' - תירגול6
המשך דוגמה – קריאה לפונקציה נשים לב שהפרמטרים המועברים לפונקציה הם מטיפוס מתאים! האם הם חייבים להיות float? float delta(float a, float b); int main(){ float x = 3.4, y = 5.7; float d = delta(x,y); printf(“delta of x and y is: %f\n”, d); d = delta(d, x); printf(“delta of x and y is: %f\n”, d); d = delta(d,d); printf(“delta of x and y is: %f\n”, d); return 0; } יודפס 2.3 יודפס 1.1 יודפס 0
קריאה לפונקציה • כאשר פונקציה נקראת, תחילה מחושבים ערכי הפרמטרים שהועברו אליה – אשר יכולים להיות גם ביטוי מורכב. • הפרמטרים המועברים לפונקציה יומרו לטיפוס המתאים – בדוגמא הקודמת, פונקציה עם פרמטר מסוג float, יכולה להיקרא עם פרמטר int שיומר באופן המוכר כפי שלמדנו. • סדר חישוב הפרמטר הוא תלוי מהדר, לכן לא ניתן להניח שהם מחושבים בסדר מסוים. • ניתן, אך לא הכרחי, להשתמש בערך המוחזר של הפונקציה (אם היא אכן מחזירה ערך). מבוא למדעי המחשב מ' - תירגול6
עוד על פרמטרים • פרמטרים הם משתנים המוגדרים בכותרת הפונקציה ומשתחררים בסיום ריצת הפונקציה. • פרמטרים ב – C מועברים by value, שינוי ערך פרמטר בתוך פונקציה לא ישפיע על ערכי משתנים מחוץ לפונקציה.הם בעצם עותקים של הערכים שחושבו בקריאה לפונקציה. מבוא למדעי המחשב מ' – תירגול 6
תרגילים • תרגיל 1: כתבו פונקציה המקבלת שני מספרים שלמים ומחזירה את המקסימום שלהם.
תרגיל 1 - פתרון נשים לב לחתימת הפונקציה: שני פרמטרים מטיפוס int וערך חזרה מטיפוס int: יכולנו גם לכתוב return y ישר אחרי ה-if, ללא else. int max2(int x, int y){ if (x > y){ return x; } else{ return y; } }
תרגילים • תרגיל 2: כתבו פונקציה המקבלת 3 מספרים שלמים ומחזירה את המקסימום ביניהם. מבוא למדעי המחשב מ' - תירגול6
תרגיל 2 - פתרון אפשר לכתוב פונקציה באותו הסגנון כמו תרגיל 1: • אולי נשתמש בפונקציה הקודמת? int max3(int x, int y, int z){ if (x > y){ if (x > z) return x; else return z; } \\ x is not bigger than y else{ if (y > z) return y; else return z; } } int max2(int x, int y){ if (x > y){ return x; } else{ return y; } }
תרגיל 2 - פתרון הבחנה: אילו ידענו מה המקסימום בין x ו-y, רק היינו צריכים להשוות אותו ל-z. הערך של max2(x,y) הוא בדיוק המקסימום המדובר: • באופן כללי נעדיף להשתמש בפונקציות קיימות על מנת לכתוב קוד חדש. int max3(int x, int y, int z){ return max2(max2(x,y),z); } • נשים לב להתאמה בין טיפוס הערך המוחזר של max2 לערך החזרה של max3 • נשים לב להתאמה בין טיפוס הפרמטר ש-max2 מצפה לקבל לטיפוס הערך המוחזר ע"י max2
תרגילים • תרגיל 3: כתבו פונקציה בשם isPrime שמקבלת int כפרמטר ומחזירה true אם הפרמטר ראשוני ו-false אחרת.
תרגיל 3 – פתרון boolis_prime(intnum) { \\ if divisible by 2, only 2 is prime: if (num%2 == 0) ???; \\ otherwise see if divisible by anything inti=3; while (i*i <= num){ if (num%i == 0) { ??? } i++; } return true; }
תרגיל 3 – פתרון boolis_prime(intnum) { \\ if divisible by 2, only 2 is prime: if (num%2 == 0) returnnum == 2; \\ otherwise see if divisible by anything inti=3; while (i*i <= num){ if (num%i == 0) { return false; } i++; } return true; }
בדיקת ראשוניות – דוגמה לשימוש ניזכר בתרגיל בו מקבלים מספר 1-10 ומדפיסים האם הוא ראשוני, או זוגי או אי-זוגי לא ראשוני ונשנה אותו קצת. • תרגיל 4: כתבו פונקציה בשם printProperty שפותרת את התרגיל עבור כל מספר שלם (שימו לב שהיא לא צריכה להחזיר כלום), תוך שימוש בפונקציה isPrime:
תרגיל 4 - פתרון void print_property(intnum){ if (is_prime(num)){ printf(“Number is prime\n”); } else if (num % 2 == 0){ printf(“Number is even\n”); } else printf(“Number is odd\n”); return; } • ה-return לא הכרחי • טיפוס ערך החזרה הוא void כצפוי
תרגילים • תרגיל 5: מה לא בסדר במימושים הללו? int min(int a, int b) { if (a > b) return b; } void print_value(int m) { printf(“Value=%d\n”, m); return m; }
תרגילים • תרגיל 6: אילו מהקריאות לא חוקיות? חתימות של הפונקציות: intgcd(int n, int m); void print_value(int num); int dist(float, float); char get_letter(); j = gcd(j, j); result = print_value(i+1); dist(2.2, 1.5); printf(“input: %c\n”, get_letter(k)); get_letter;
הצהרת פונקציות – בעיה • הקומפיילר קורא את הקוד מההתחלה לסוף.כשהוא מגיע לנקודה בה יש קריאה לפונקציה, על הפונקציה הזאת להיות כבר מוגדרת: • g() הוגדרה אחרי f()למרות שנעשה בהשימוש ב-f() • נקבל שגיאה האומרת ש-g() אינה מוכרת בקריאה מ-f() int f(int x) { return g(x) + 1; } int g(x) { return x * -1; } error: implicit declaration of function 'g' מבוא למדעי המחשב מ' - תירגול6
הצהרת פונקציות – פתרון א' • נהפוך את סדר כתיבת הפונקציות • הפונקציה הנקראת תיכתב לפני הפונקציה הקוראת • האם הפתרון יעבוד תמיד? int g(x) { return x * -1; } int f(int x) { return g(x) + 1; } מבוא למדעי המחשב מ' - תירגול6
הצהרת פונקציות – בעיה • לא ניתן ליישם את הפתרון עבור פונקציות עם קריאה מעגלית int g(x) { if (x <= 0) x = f(x); return x * -1; } int f(int x) { return g(x) + 1; } מבוא למדעי המחשב מ' - תירגול6
הצהרת פונקציות – פתרון ב' • נצהיר על הפונקציות לפני מימושן. • ההצהרה מדווחת לקומפיילרעל קיומן של הפונקציות לפניהמימוש. • לעיתים אף מייצאים את ההצהרות לקובץ header נפרד חייבים ";" בסוף השורה אין צורך לרשום את שמות המשתנים. int g(int x); int f(int); int g(int x) { if (x <= 0) x = f(x); return x * -1; } int f(int x) { return g(x) + 1; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות מבוא למדעי המחשב מ' - תירגול6
דע מאין באת ולאן אתה הולך • נביט בקטע תוכנית: • הפונקציה delta נקראת כאן פעמיים. • בכל פעם, לאחר שהפונקציה מסתיימת, התוכנית ממשיכה ממקום אחר. • איך זה קורה? float delta_age; floatdelta_height; float age1=2, age2=3, height1=1.67, height2=1.78; delta_age = delta(age1, age2); delta_height= delta(height1, height2); מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות • במהלך ריצת התוכנית, המערכת מנהלתמחסניתשל קריאות. • המחסנית מנוהלת בשיטת Last-In-First-Out (ומכאן שמה). • על המחסנית נשמרים הנתונים הבאים: • לאן לחזור לאחר סיום הפונקציה. • ערכי הפרמטרים שהועברו לפונקציה. • משתנים לוקאליים של הפונקציה. מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות • בתחילת התוכנית, המחסנית ריקה. • בכל פעם שנכנסים לתוך בלוק (תחום בסוגריים מסולסלים, נרחיב בהמשך), התוכנית מקצה את המשתנים הלוקאליים של הבלוק בראש המחסנית וכך היא גדלה. • ברגע שיוצאים מבלוק, התוכנית מפנה אתכל המשתנים שהוקצו עבור בלוק זה,והמחסנית קטנה בחזרה. מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } 4 מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } 4 מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } 4 מבוא למדעי המחשב מ' - תירגול6
מחסנית הקריאות: דוגמה Stack int max2(int x, int y) { if (x > y) return x; else return y; } int max3(int x, int y, int z) { return max2(max2(x,y),z); } int main() { int x = 0, y = 0, z = 0; scanf("%d%d%d", &x, &y, &z); printf("max: %d", max3(x, y, z)); return 0; } מבוא למדעי המחשב מ' - תירגול6
דוגמה - מה תדפיס התוכנית? • לאור מה שראינו זה עתה, מה תדפיס התוכנית הבאה? void setToTen(int x) { x = 10; } int main() { int x = 2; setToTen(x); printf(“%d”,x); return 0; } תשובה: 2 • כאמור, בשפת C שינוי ערך הפרמטרים בתוך הפונקציה לא ישפיע על ערכי משתנים מחוץ לפונקציה מבוא למדעי המחשב מ' - תירגול6
סוגי משתניםמקומיים, סטאטיים, גלובאליים מבוא למדעי המחשב מ' - תירגול6
בלוקים • בלוק הוא קטע קוד שתחום על ידי זוג סוגריים מסולסלים { }. • בלוקים יכולים להיות זרים או מקוננים (אחד מוגדר בתוך השני, כמו במקרה של לולאה בתוך לולאה). • דוגמאות לבלוקים: • כל פונקציה נכתבת בתוך בלוק. • ניתן להשתמש בבלוקים בלולאות ובפקודות התניה. • ניתן גם לשים בלוק סתם כך באמצע קוד רציף! מבוא למדעי המחשב מ' - תירגול6
משתנים מקומיים • משתנים מקומיים הם משתנים: • החיים מרגע הגדרתם ועד סוף הבלוק בהם הוגדרו • נגישים בבלוק בהם הוגדרו ובכל בלוק פנימי • למעשה כל המשתנים שראינו עד כה הם משתנים מקומיים: • משתנים שהוגדרו ב-main()או בכל פונקציה אחרת • משתני אטרציה שהוגדרו בלולאות for • פרמטרים של פונקציות מבוא למדעי המחשב מ' - תירגול6
הסתרה של משתנים • משתנה מבלוק פנימי מסתיר משתנה מבלוק חיצוני אם הם בעלי אותו שם. • ההסתרה אינה תלויה בטיפוס, רק בשם. • קוד המשתמש בהסתרהמבלבל מאוד!לכן, השתדלו להימנע מכך! int main() { inta = 10; if (a > 0) { float a = 0.0; printf(“%f\n”, a); } printf(“%d”, a); return 0; } מבוא למדעי המחשב מ' - תירגול6
משתנים סטאטיים • משתנים סטאטיים הם משתנים: • החיים מרגע תחילת התוכנית ועד סופה – תמד מוקצים בתחילת ריצת התכנית, לא משנה היכן הם הוגדרו. • נגישים בבלוק בו הם הוגדרו ובכל בלוק פנימי (כמו משתנים מקומיים) • מוגדרים ע"י כתיבת המילה השמורה static לפני שם הטיפוס בהגדרת המשתנה • אתחול משתנים סטטיים: • ניתן ע"י ערכים ידועים בזמן קומפילציה בלבד • אם לא צוין ערך אתחול, משתנה סטטי יאותחל ל-0 (בניגוד למשתנה מקומי שלא יאותחל כלל ולא ניתן לצפות את ערכו) מבוא למדעי המחשב מ' - תירגול6