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

תוכן שנמחק תוכן שנוסף
Ybungalobill (שיחה | תרומות)
אין תקציר עריכה
פונקציות
שורה 15:
</source>
{{הארה|הפונקציה atan2 מקבלת שיעורי ווקטור ומחזירה את הזווית שבין הווקטור לבין ציר ה-x. תפקידה דומה ל-atan(y/x)&lrm; מלבד ש-atan2 עובדת באופן תקין גם כאשר שיעור ה-x שווה ל-0. פונקציות מתמתיות אלה נמצאות בספרייה <cmath>.}}
בדוגמה זו קראנו לפונקציה בשם atan2. שני הפרמטרים שנתנו לפונקציה הם y ו-x. כיוון שהפונקציה מחזירה ערך, אנחנו שמרנו אותו במשתנה alpha. כמו כן לאו דווקא יש לשמור את הערך שמחזירה פונקציה. קיימות פונקציות רבות שהערך המוחזר הוא לא המטרה שעבורה נקראתה הפונקציה, בעיקר כשערך זה מסמל שגיאה. לדוגמה הפונקציה הנפוצה שמשמשת את מתכנתי C לקלט, שמה scanf, מחזירה את מספר הערכים שנקלטו בהצלחה. למרות זאת, לרובהרבה מניחים את תקינות הקלט ולא בודקים ערך זה.
 
חשוב להבין שלעומת שפות אחרות, כמו Pascal למשל, הקריאה לפונקציה '''לא''' נעשת כאשר אנו כותבים את שמה. הפונקציה נקראת על ידי אופרטור קריאה לפונקציה (). אופרטור זה מיוחד בכך שמקבלשיכול לקבל מספר כלשהושרירותי של אופרנדים. האופרנד הראשון הוא שם הפונקציה שאותה אנו רוצים לקרוא לה, במקום שם הפונקציה ניתן לתת גם מצביע לפונקציה (למד בהמשך על [[C++/מצביעים והמשתנה המיוחס|מצביעים]]). שאר האופרנדים הם הפרמטרים שיש להעביר אל הפונקציה. במקוםהטיפוסים שםשל הפונקציההפרמטרים ניתןהמועברים לכתובלפונקציה גםצריכים מצביעלהתאים לפונקציהלטיפוסים של הפרמטרים בהכרזה על הפונקציה או ניתנים להמרת implicit (למדראה בהמשךלמטה).
 
נכתוב בפרק זה פונקציה שמטרתה תהיה לעגל מספר שיבוא בפרמטר הראשון אל הכפולה הקרובה ביותר של חזקה של 10. החזקה של 10 אליה יש לעגל תבוא בפרמטר השני. הפונקציה תחזיר את התוצאה לאחר העיגול. נקרא לפונקציה זו בשם roundTo. לדוגמה נביא מספר קריאות לפונקציה זו:
שורה 27:
</source>
 
הפלט התקין צריך להיות: {{קוד בשורה|16, 20, 0, 100}}.
<div style="direction: ltr;">
16, 20, 0, 100
</div>
 
== הגדרת פונקציות ==
 
{{הערה|הכרזה או הגדרה של הפונקציה תעשה לפני השימוש הראשון בה. טרם למדנו על הכרזות יש לכתוב את הגדרת הפונקציה לפני פונקציית ה-main.}}
 
=== כותרת הפונקציה ===
 
שורה 38 ⟵ 40:
* '''הטיפוס של הערך המוחזר מהפונקציה''' – זהו טיפוס כלשהו, מובנה או מוגדר על ידי המתכנת. ניתן במקום זאת לרשום את המילה השמורה void שפירושה שהפונקציה '''לא''' מחזירה ערך.
* '''שם הפונקציה''' – הכללים לבחירת שם הפונקציה זהים לכללים לבחירת כל שם אחר ב-C++&lrm;. נשתמש בשם זה על מנת לקרוא לפונקציה משאר התוכנית.
* '''טיפוסים ושמות הפרמטרים''' – רשימה זו תבוא בסוגריים אחרי שם הפונקציה. כל פרמטר יהיה מופרד בפסיקים משאר הרשימה. הגדרת פרמטרים אלה דומה להגדרה של משתנים לוקאלייםמקומיים, הם אף מתפקדים וממומשים כמשתנים לוקאלייםמקומיים לכל דבר. ההבדל היחידי הוא בהגדרה: נצטרך לרשום טיפוס לכל פרמטר בנפרד, גם אם כולם מאותו הטיפוס. שם הפרמטר ישמש אותנו אך ורק בגוף הפונקציה בפניות אליו, לכן אם מסיבות כלשהן הפרמטר לא נמצא בשימוש, ניתן לא לתת לו שם.
 
להלן כדוגמה כותרת הפונקציה שנכתוב בפרק זה:
שורה 67 ⟵ 69:
=== הוראת return ===
 
על מנת להחזיר ערך מהפונקציה נשתמש בהוראת return. הוראה זו מחזירה את ערך הביטוי שנכתב אחריה. בדוגמה שלמעלה אנחנו מחזירים את ערכו של המשתנה result, כמו כן, ניתן היה להסתדר גם בלעדיו: לכתוב את הביטוי אחרי המילה השמורה return ובכך להחזיר ישירות את תוצאת הביטויתוצאתו. הטיפוס של הביטוי חייב להיות זהה לטיפוס של הערך המוחזר על ידי הפונקציה (מצויין בכותרתבתחילת כותרת הפונקציה) או ניתן להמרת implicit אליו. בדוגמה שלנו הטיפוסים מתאימים זה לזה ולא תיווצר שום בעייה (מחזירים int).
 
את הוראת ה-return ניתן לכתוב לאו דווקא בסוף הפונקציה. כאשר מבוצעת הוראת ה-return מכל מקום אחר בתוך גוף הפונקציה היא מפסיקה את ביצוע העתידי שלה, במילים אחרות התוכנית יוצאת מהפונקציה. תכונה זו של הוראה זו מאפשרת את קיצור הקוד ומניעת קינון תנאים, בדומה להוראת break.
 
כל פונקציה שבכותרתה מצויין טיפוס הערך המוחזר חייבת להחזיר ערך, כלומר בכל פונקצייה שטיפוס הערך המוחזר הוא לא void חייבת לכלול הוראת return שבה תסתיים ריצתה. לדוגמה הפונקציה הבאה תקינה:
<source lang="cpp">
int f()
{
int n;
for(;;)
{
cout << "Enter a positive integer:\n";
cin >> n;
if(n > 0)
return n;
 
cout << "It's not positive! ";
}
}
</source>
בסוף גוף הפונקציה אין הוראת return, אבל התוכנית אף פעם לא תגיע לסוף בלוק הפונקציה מהסיבה שהיא מכילה לולאה אינסופית. הלולאה תיפסק רק כאשר תתבצעה הוראת ה-return שתצא מתוך הפונקציה ולכן ההוראה האחרונה שתתבצעה תהיה תמיד הוראת ה-return. לעומת זאת הפונקציה הבאה לא תקינה:
<source lang="cpp">
int f()
{
int n;
cout << "Enter a positive integer:\n";
cin >> n;
if(n > 0)
return n;
 
cout << "It's not positive! ";
}
</source>
הסיבה היא שכאשר התוכנית תקלוט מספר שלילי היא תגיע לסוף הפונקציה, לא תמצא את הוראת ה-return ולא תדע איזה ערך להחזיר. מהדר טוב צריך להתריע על העדר הוראות ה-return.
 
=== טיפוס void ===
שורה 75 ⟵ 110:
== הכרזת פונקציות ==
 
לפני שנוכל להשתמש בשם כלשהו ב-C++&lrm;, לרוב, תחילה נצטרך להכריז עליו או להגדיר אותו. במילים אחרות, המהדר שקורא את קבצי התוכנית מהתחלה עד הסוף, צריך להתקל כבר בהכרזת שם זה על מנת להכיר אותו. '''ההכרזה''' אומרת למהדר שקיים שם מסויים (למשל i) ושיש להתייחס אליו כלדבר מסויים (למשל כלשם של משתנה מטיפוס int). דבר זה תקף גם עבור שמות הפונקציות. הפונקציות שנמצאות בספריות כלשהן, (למשל atan2 שהשתמשנו בה למעלה), מוכרזות בקבצי ההכללה של הספריות אלה (דוגמה <cmath>).
 
כאשר נכתוב פונקציה משלנו, נצטרך לפעמים להכריז עליה לפני שנשתמש בה. אנחנו חייבים להשתמש בהכרזה כאשר אנחנו מפרקים את התוכנית למודולים (למספר קבצי קוד, לרוב עם סיומת cpp), או כאשר אנחנו משתמשים בשתי פונקציות רקורסיביות הקוראות זו לזו (למד בהשמך). במקרה של תוכנית פשוטה בעלת קובץ אחד נוכל להגדירלסדר את הפונקציההפונקציות בסדר כזה שכל אחת תהיה מוגדרת לפני השימוש הראשון בה. לדוגמה אם נקרא לפונקציה roundTOroundTo מפונקציית main, נוכל להגדיר אותה לפני פונקציית main ולהסתדר ללא הכרזות. ארגון קוד כזה גורם להופעת פונקציה main בסוף הקוד בתור פונקציה אחרונה. כמו כן קיימים מתכנתים המעדיפים להגדיר את הפונקציות אחרי ה-main, במקרה כזה עליהם להוסיף שורות נוספות לפני פונקציית main שהן שורות ההכרזה.
 
ההכרזה תכיל את כותרת הפונקציה שתסתיים בנקודה פסיק. גוף הפונקציה לא יבוא בהכרזה מהסיבה הפשוטה שהוא זה שמבדיל בין הגדרה והכרזה. לדוגמה הכרזת הפונקציה roundTo תראה כך:
<source lang="cpp">
int roundTo(int number, int exponent);
</source>
 
הכרזת הפונקציה צריכה להכיל את אותו השם, אותו טיפוס מוחזר ואותם טיפוסי הפרמטרים כמו גם הגדרתה. כנאמר למעלה שמות הפרמטרים ניתנים אך ורק על מנת לפנות אליהם מתוך גוף הפונקציה עצמה, לכן כאשר אין בהם צורך נוכל למחוק אותם:
<source lang="cpp">
int roundTo(int, int);
</source>
כאשר כותבים את הקריאה לפונקציה סביבות פיתוח שונות נותנות רמזים שמכילים את כותרת הפונקציה. לכן כדאי בכל זאת לכתוב את שמותם המלאים של הפרמטרים כדי שנדע מה תפקיד הפרמטר הראשון ומה תפקיד הפרמטר השני, גם כששניהם מטיפוס int. כמו כן אם ניתנים שמות לפרמטרים הם לא חייבים להיות זהים בין ההכרזה וההגדרה.
 
== רקורסיה ==
שורה 85 ⟵ 131:
העמסת פונקציות (Overloading) היא יצירה של יותר מפונקציה אחת עם אותו שם, כאשר הן נבדלות זו מזו על ידי רשימת הפרמטרים שלהן.<br /> יש צורך באלמנט זה בכדי ליצור פונקציה אחת (בעצם כמה, בעלות שם זהה) שהיא רב שימושית, הוי אומר שלמשל פונקציה שמחזירה את הגדול מבין שני מספרים שמתקבלים כפרמטרים תהיה מתאימה למספר טיפוסי נתונים.<br /> למשל: היא תוכל לחשב את התוצאה גם אם יתקבלו משתנים מטיפוס int וגם אם יתקבלו משתנים מטיפוס double, ואפשר כמובן שיהיה שוני בין שני החישובים.
 
==יישום==
===דוגמה להעמסה===
כעת, נדגים את הרעיון ע"י העמסה של פונקציה המחזירה את סכומם של שני מספרים שנשלחו אליה כפרמטרים: