C++/פונקציות: הבדלים בין גרסאות בדף

תוכן שנמחק תוכן שנוסף
פונקציות
Ybungalobill (שיחה | תרומות)
VOID++
שורה 2:
{{בעבודה}}
 
'''פונקציות''' הן אבני הבניין של [[w:תכנות פרוצדורלי|תכנות פרוצדורלי]]. כל [[w:פונקציה (תכנות)|פונקציה]] היא חלק מהתוכנה שיכול '''לקבל פרמטרים''' ויכול '''להחזיר ערך'''. לכל פונקציה כזאת נוכל לקרוא בכל מיני מקומות שונים בתוכנית. לפיבזמן פרדיגמתהקריאה התכנות(הזימון) הפרוצדורלילפונקציה, ישהתוכנית לפרקעוצרת אתבמקום הקריאה ועוברת לביצוע קוד הפונקציה. כאשר הפונקציה מסתיימת התוכנית לכמהחוזרת שיותרלמקום פונקציותבו קטנותנכתב שכלהזימון אחתכאשר יש בידיה את מהןהערך תבצעשהוחזר מינימוםעל פעולותידי פשוטותהפונקציה.
 
לפי פרדיגמת התכנות הפרוצדורלי יש לפרק את התוכנית לכמה שיותר פונקציות קטנות שכל אחת מהן תבצע מינימום פעולות פשוטות. פונקציות נקראות גם כן '''תת-תוכניות''', שם זה מרמז על כך שהן חלקים מהתוכנית הגדולה כאשר כל פונקציה מתפקדת כתוכנית קטנה בפני עצמה.
 
עד כה כבר הקרתםהכרתם פונקציות שכבר קיימות בספריות של C++‎, לדוגמה sqrt שמקבלת מספר כפרמטר ומחזירה את השורש הריבועי שלו. כמו כן נאמר שגם main היא פונקציה. ההבדל בין פונקציה sqrt לפונקציה main הוא שפונקציה sqrt כבר נכתבה ואנחנו רק השתמשנו בה (זימנו אותה), ואילו את main אנחנו כתבנו בעצמנו, בזאת הגדרנו מה היא תעשה, ומערכת ההפעלה קראהזימנה להאותה. נסביר כעת כיצד לכתוב פונקציות ולקרוא להן.
 
== קריאה לפונקציות ==
שורה 13:
<source lang="cpp">
double alpha = atan2(y, x);
</source>{{הארה|1=
{{הארה|הפונקציה atan2 מקבלת שיעורי ווקטור ומחזירה את הזווית שבין הווקטור לבין ציר ה-x. תפקידה דומה ל-atan(y/x)&lrm; מלבד ש-atan2 עובדת באופן תקין גם כאשר שיעור ה-x שווה ל-0. פונקציות מתמתיות אלה נמצאות בספרייה <cmath>.
}}
בדוגמה זו קראנו לפונקציה בשם atan2. שני הפרמטרים שנתנו לפונקציה הם y ו-x. כיוון שהפונקציה מחזירה ערך, אנחנו שמרנו אותו במשתנה alpha. כמו כן לאו דווקא יש לשמור את הערך שמחזירה פונקציה. קיימות פונקציות רבות שהערך המוחזר הוא לא המטרה שעבורה נקראתהנקראה הפונקציה, בעיקר כשערך זה מסמל שגיאה. לדוגמה הפונקציה הנפוצה שמשמשת את מתכנתי C לקלט, שמה scanf, מחזירה את מספר הערכים שנקלטו בהצלחה. למרות זאת, הרבה מניחים את תקינות הקלט ולא בודקים ערך זה.
 
קריאה לפונקציה היא מעבר ביצוע התוכנית ממקום אחד בקוד למקום שני. בניגוד ללולאות או תנאים, התוכנית תחזור למקום ממנו נקראה הפונקציה כאשר הפונקציה תסתיים. ברגע הקריאה לפונקציה התוכנית דוחפת את הפרמטרים של הפונקציה אל [[w:מחסנית (מבנה נתונים)|המחסנית]] (אזור מיוחד בזיכרון), שומרת את כתובת החזרה ורק אז מבצעת קפיצה אל קוד הפונקציה עצמה. כאשר התוכנית מסיימת לבצע את קוד הפונקציה היא שולפת מהמחסנית את כתובת החזרה ומבצעת קפיצה על פיה. שיטה זו מאפשרת גם לקרוא לכל פונקציה שהיא מכל מקום בתוכנית וגם לאפשר קריאות רקורסיביות, קריאות לפונציה אחת מתוך פונקציה אחרת.
 
חשוב להבין שלעומת שפות אחרות, כמו Pascal למשל, הקריאה לפונקציה '''לא''' נעשת כאשר אנו כותבים את שמה. הפונקציה נקראת על ידי אופרטור קריאה לפונקציה: () (סוגריים). אופרטור זה מיוחד בכך שיכול לקבל מספר שרירותי של אופרנדים. האופרנד הראשון הוא שם הפונקציה שאותה אנו רוצים לקרוא לה, במקום שם הפונקציה ניתן לתת גם מצביע לפונקציה (למד בהמשך על [[C++/מצביעים והמשתנה המיוחס|מצביעים]]). שאר האופרנדים הם הפרמטרים שיש להעביר אל הפונקציה. הטיפוסים של הפרמטרים המועברים לפונקציה צריכים להתאים לטיפוסים של הפרמטרים בהכרזה על הפונקציה או ניתנים להמרת implicit אליהם (ראה למטה).
 
נכתוב בפרק זה פונקציה שמטרתה תהיה לעגל מספר שיבוא בפרמטר הראשון אל הכפולה הקרובה ביותר של חזקה של 10. החזקה של 10 אליה יש לעגל תבוא בפרמטר השני. הפונקציה תחזיר את התוצאה לאחר העיגול. נקרא לפונקציה זו בשם roundTo. לדוגמה נביא מספר קריאות לפונקציה זו:
שורה 34 ⟵ 37:
== הגדרת פונקציות ==
 
{{הערה|הכרזה או הגדרה של הפונקציה תעשה לפני השימוש הראשון בה. '''טרם למדנו על הכרזות, יש לכתוב את הגדרת הפונקציההפונקציות לפני פונקציית ה-main.'''}}
=== כותרת הפונקציה ===
 
כל הגדרה של פונקציה תתחיל מכותרתה. כותרת הפונקציה מגדירה בסדר הבא את:
* '''הטיפוס של הערך המוחזר מהפונקציה''' – זהו טיפוס כלשהו, מובנה או מוגדר על ידי המתכנת. ניתן במקום זאת לרשום את המילה השמורה void שפירושה שהפונקציה '''לא''' מחזירה ערך (ראה בהמשך).
* '''שם הפונקציה''' – הכללים לבחירת שם הפונקציה זהים לכללים לבחירת כל שם אחר ב-C++&lrm;. נשתמש בשם זה על מנת לקרוא לפונקציה משאר התוכנית.
* '''טיפוסים ושמות הפרמטרים''' – רשימה זו תבוא בסוגריים אחרי שם הפונקציה. כל פרמטר יהיה מופרד בפסיקים משאר הרשימה. הגדרת פרמטרים אלה דומה להגדרה של משתנים מקומיים, הם אף מתפקדים וממומשים כמשתנים מקומיים לכל דבר. ההבדל היחידי הוא בהגדרה: נצטרך לרשום טיפוס לכל פרמטר בנפרד, גם אם כולם מאותו הטיפוס. שם הפרמטר ישמש אותנו אך ורק בגוף הפונקציה בפניות אליו, לכן אם מסיבות כלשהן הפרמטר לא נמצא בשימוש, ניתן לא לתת לו שם.
שורה 52 ⟵ 55:
=== גוף הפונקציה ===
 
'''הגדרה''' של פונקציה מכילה את קוד הפונקציה, כלומר היא מגדירה בפירוש מה הפונקציה עושה. כאשר אנו מגדירים פונקציה אנו נכתוב אחרי הכותרת את גופה בתוך בלוק התחום בסוגריים מסולסלים. בלוק זה יכיל הוראות הניתנות לביצוע, בין השאר, כמו בכל בלוק אחר, גם בבלוק הפונקציה נוכל להגדיר משתנים מקומיים (לוקאליים). משתנים אלה יושמדו בעת יציאה מהפונקציה. בתוך גוף הפונקציה נוכל להשתמש בפרמטרים שהפונקציה מקבלת. פרמטרים אלה גם הם מתפקדים כמשתנים מקומיים. נכתוב את גוף הפונקציה roundTo:
<source lang="cpp">
int roundTo(int number, int exponent)
שורה 66 ⟵ 69:
 
בפונקציה זו הגדרנו משתנה לוקאלי powerOfTen ושמרנו לתוכו את החזקה של 10 שאליה ברצוננו לעגל את המספר. בשורה לפני האחרונה של גוף הפונקציה אנו מעגלים את המספר ושומרים את התוצאה במשתנה עזר result. לאחר מכן בשורה האחרונה אנו מחזירים (return) את הערך שנמצא במשתנה result.
 
המשתנים הלוקאליים (מקומיים) נקראים גם משתנים אוטומטיים (auto). הקצאת זיכרון עבור משתנים אלה מתבצעת באופן אוטומטי כמו גם שיחרורו. זיכרון זה הוא זיכרון המחסנית. כיוון שבעת יציאה מהפונקציה המחסנית מוחזרת למצבה כפי שהוא היה לפני קריאתה, כל המשתנים הלוקאליים נשלפים ממנה.
 
=== הוראת return ===
שורה 105 ⟵ 110:
 
=== טיפוס void ===
 
בשפות אחרות מפרידים את המושג "פונקצייה" מ-"פרוצדורה" (למשל ב-Pascal יש מילה שמורה function ומילה procedure, ב-Visual Basic יש Function ויש Sub). '''פרוצדורה''' היא פונקציה שלא מחזירה ערך. כדי להגדיר פונקציה שלא תחזיר ערך יש לכתוב את הטיפוס void (ריק) בטיפוס המוחזר שלה. טיפוס זה מיוחד בכך שלא ניתן ליצור משתנה מטיפוס זה. טיפוס זה משמש ליצירת טיפוסים מורכבים.
 
כאשר הפונקציה לא מחזירה ערך (פונקציית void), לא הכרחי להשתמש בהוראה return. אם בכל זאת נרצה לצאת מגוף הפונקציה נוכל לרשום return ללא ביטוי אחריו:
<source lang="cpp">
void g()
{
int n;
cin >> n;
 
if(n < 0)
return;
 
cout << "I'm a void function!\n";
}
</source>
פונקציה זו תקינה. כמו כן, אם נכתוב אחרי ה-return ביטוי שהטיפוס שלו הוא לא void, המהדר יתן שגיאה. אחרי ה-return ניתן לכתוב ביטויים שהטיפוס שלהם הוא void, לדוגמה ניתן להחזיר את ערך ה-void המוחזר מפונקציית void אחרת, או ליצור ערך "void" זמני (כמובן פעולות אלה הן אך ורק דרכי כתיבה שונות, הרי לא קיימים ערכי void). אפשרות זו נוספה ל-C++&lrm; כדי להקל על יצירת [[C++/תבניות|תבניות]] עם פרמטרי void.
<source lang="cpp">
return void();
return f();
</source>
בהנחה ש-f היא פונקציית void, שתי הוראות אלו תהינה נכונות כאשר נכתובן בפונקציה g.
 
=== פונקציית main ===
שורה 126 ⟵ 153:
 
== רקורסיה ==
 
== פרמטרים שרירותיים ==
 
== ערכי ברירת מחדל ==
 
== העמסת פונקציות ==
 
העמסת פונקציות (Overloadingfunction overloading) היא יצירה של יותר מפונקציה אחת עם אותו שם, כאשר הן נבדלות זו מזו על ידי רשימת הפרמטרים שלהן.<br /> יש צורך באלמנט זה בכדי ליצור פונקציה אחת (בעצם כמה, בעלות שם זהה) שהיא רב שימושית, הוי אומר שלמשל פונקציה שמחזירה את הגדול מבין שני מספרים שמתקבלים כפרמטרים תהיה מתאימה למספר טיפוסי נתונים.<br /> למשל: היא תוכל לחשב את התוצאה גם אם יתקבלו משתנים מטיפוס int וגם אם יתקבלו משתנים מטיפוס double, ואפשר כמובן שיהיה שוני בין שני החישובים.
 
===דוגמה להעמסה===