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

תוכן שנמחק תוכן שנוסף
Ybungalobill (שיחה | תרומות)
Ybungalobill (שיחה | תרומות)
אין תקציר עריכה
שורה 1:
{{C++‎}}
{{בעבודה}}
 
'''פונקציות''' הן אבני הבניין של [[w:תכנות פרוצדורלי|תכנות פרוצדורלי]]. כל פונקציה היא חלק מהתוכנה שיכול '''לקבל פרמטרים''' ויכול '''להחזיר ערך'''. לכל פונקציה כזאת נוכל לקרוא בכל מיני מקומות שונים בתוכנית. לפי פרדיגמת התכנות הפרוצדורלי יש לפרק את התוכנית לכמה שיותר פונקציות קטנות שכל אחת מהן תבצע מינימום פעולות פשוטות. לדוגמה
 
פונקציות נקראות גם כן '''תת-תוכניות''', שם זה מרמז על כך שהן חלקים מהתוכנית הגדולה כאשר כל פונקציה מתפקדת כתוכנית קטנה בפני עצמה.
 
עד כה כבר הקרתם פונקציות שכבר קיימות בספריות של C++‎, לדוגמה sqrt שמקבלת מספר כפרמטר ומחזירה את השורש הריבועי שלו. כמו כן נאמר שגם main היא פונקציה. ההבדל בין פונקציה sqrt לפונקציה main הוא שפונקציה sqrt כבר נכתבה ואנחנו רק השתמשנו בה, ואילו את main אנחנו כתבנו בעצמנו, בזאת הגדרנו מה היא תעשה, ומערכת ההפעלה קראה לה. נסביר כעת כיצד לכתוב פונקציות ולקרוא להן.
 
== קריאה לפונקציות ==
 
נתבונן תחילה באופן השימוש בפונקציות. על מנת לקרוא לפונקציות שקיימות כבר בספריות C++‎ רשמנו את שם הפונקציה ואחריו את הפרמטרים בתוך סוגריים. לדוגמה:
<source lang="cpp">
double alpha = atan2(y, x);
</source>
{{הארה|הפונקציה atan2 מקבלת שיעורי ווקטור ומחזירה את הזווית שבין הווקטור לבין ציר ה-x. תפקידה דומה ל-atan(y/x)&lrm; מלבד ש-atan2 עובדת באופן תקין גם כאשר שיעור ה-x שווה ל-0. פונקציות מתמתיות אלה נמצאות בספרייה <cmath>.}}
בדוגמה זו קראנו לפונקציה בשם atan2. שני הפרמטרים שנתנו לפונקציה הם y ו-x. כיוון שהפונקציה מחזירה ערך, אנחנו שמרנו אותו במשתנה alpha. כמו כן לאו דווקא יש לשמור את הערך שמחזירה פונקציה. קיימות פונקציות רבות שהערך המוחזר הוא לא המטרה שעבורה נקראתה הפונקציה, בעיקר כשערך זה מסמל שגיאה. לדוגמה הפונקציה הנפוצה שמשמשת את מתכנתי C לקלט, שמה scanf, מחזירה את מספר הערכים שנקלטו בהצלחה. למרות זאת, לרוב מניחים את תקינות הקלט ולא בודקים ערך זה.
 
חשוב להבין שלעומת שפות אחרות, כמו Pascal למשל, הקריאה לפונקציה '''לא''' נעשת כאשר אנו כותבים את שמה. הפונקציה נקראת על ידי אופרטור קריאה לפונקציה (). אופרטור זה מיוחד בכך שמקבל מספר כלשהו של אופרנדים. האופרנד הראשון הוא שם הפונקציה שאותה אנו רוצים לקרוא, שאר האופרנדים הם הפרמטרים שיש להעביר אל הפונקציה. במקום שם הפונקציה ניתן לכתוב גם מצביע לפונקציה (למד בהמשך).
 
נכתוב בפרק זה פונקציה שמטרתה תהיה לעגל מספר שיבוא בפרמטר הראשון אל הכפולה הקרובה ביותר של חזקה של 10. החזקה של 10 אליה יש לעגל תבוא בפרמטר השני. הפונקציה תחזיר את התוצאה לאחר העיגול. נקרא לפונקציה זו בשם roundTo. לדוגמה נביא מספר קריאות לפונקציה זו:
<source lang="cpp">
cout << roundTo(16, 0) << ", ":
cout << roundTo(16, 1) << ", ":
cout << roundTo(16, 2) << ", ":
cout << roundTo(54, 2) << endl:
</source>
 
הפלט התקין צריך להיות: {{קוד בשורה|16, 20, 0, 100}}.
עד כה כבר הקרתם פונקציות שכבר קיימות בספריות של C++&lrm;, לדוגמה sqrt שמקבלת מספר כפרמטר ומחזירה את השורש הריבועי שלו. כמו כן נאמר שגם main היא פונקציה. ההבדל בין פונקציה sqrt לפונקציה main הוא שפונקציה sqrt כבר נכתבה ואנחנו רק השתמשנו בה, ואילו את main אנחנו כתבנו בעצמנו, בזאת הגדרנו מה היא תעשה ומערכת ההפעלה קראה לה. נסביר כעת כיצד לכתוב פונקציות ולקרוא להן.
 
== הגדרת פונקציות ==
 
הכרזה או הגדרה של הפונקציה תעשה לפני השימוש הראשון בה. טרם למדנו על הכרזות יש לכתוב את הגדרת הפונקציה לפני פונקציית ה-main.
נכתוב פונקציה שמטרתה תהיה לעגל מספר שיבוא בפרמטר הראשון אל הכפולה הקרובה ביותר של חזקה של 10. החזקה של 10 אליה יש לעגל תבוא בפרמטר השני. הפונקציה תחזיר את התוצאה לאחר העיגול.
 
=== כותרת הפונקציה ===
 
כל הגדרה של פונקציה תתחיל מכותרתה. כותרת הפונקציה מגדירה בסדר הבא את:
* '''הטיפוס של הערך המוחזר מהפונקציה''' – זהו כל טיפוס שהוכלשהו, מובנה או מוגדר על ידי המתכנת. ניתן במקום זאת לרשום את המילה השמורה void שפירושה שהפונקציה '''לא''' מחזירה ערך.
* '''שם הפונקציה''' – הכללים לבחירת שם הפונקציה זהים לכללים לבחירת כל שם אחר ב-C++&lrm;. נשתמש בשם זה על מנת לקרוא לפונקציה משאר התוכנית.
* '''טיפוסים ושמות הפרמטרים''' – רשימה זו תבוא בסוגריים אחרי שם הפונקציה. וכלכל פרמטר יהיה מופרד בפסיקים משאר הרשימה. הגדרת פרמטרים אלה דומיםדומה להגדרה של משתנים לוקאליים, הם אף מתפקדים וממומשים כמשתנים לוקאליים לכל דבר. ההבדל היחידי הוא מלבדבהגדרה: שנצטרךנצטרך לרשום טיפוס לכל פרמטר בנפרד, גם אם כולם מאותו הטיפוס. שם הפרמטר ישמש אותנו אך ורק בגוף הפונקציה בפניות אליו, לכן אם מסיבות כלשהן הפרמטר לא נמצא בשימוש, ניתן לא לתת לו שם.
 
להלן דוגמהכדוגמה לכותרתכותרת הפונקציה שאנו נכתובשנכתוב בפרק זה:
 
<source lang="cpp">
שורה 22 ⟵ 46:
</source>
 
משמעות הכותרת היא: הפונקציה נקראת roundTo, היא מקבלת שני פרמטרים מטיפוס שלם ששמם number ו-exponent והיא מחזירה ערך מטיפוס שלם.
 
=== גוף הפונקציה ===
 
'''הגדרה''' של פונקציה (לעומת הכרזתה, ראה למטה) מכילה את קוד הפונקציה, כלומר היא מגדירה בפירוש מה הפונקציה עושה. כאשר אנו מגדירים פונקציה אנו נכתוב אחרי הכותרת את גופה בתוך בלוק התחום בסוגריים מסולסלים. בלוק זה יכיל הוראות הניתנות לביצוע, בין השאר, כמו בכל בלוק אחר, גם בבלוק הפונקציה נוכל להגדיר משתנים מקומיים (לוקאליים). משתנים אלה יושמדו בעת יציאה מהפונקציה. בתוך גוף הפונקציה נוכל להשתמש בפרמטרים שהפונקציה מקבלת. נכתוב את גוף הפונקציה roundTo:
<source lang="cpp">
int roundTo(int number, int exponent)
שורה 45 ⟵ 69:
על מנת להחזיר ערך מהפונקציה נשתמש בהוראת return. הוראה זו מחזירה את ערך הביטוי שנכתב אחריה. בדוגמה שלמעלה אנחנו מחזירים את ערכו של המשתנה result, כמו כן, ניתן היה להסתדר גם בלעדיו: להחזיר ישירות את תוצאת הביטוי. הטיפוס של הביטוי חייב להיות זהה לטיפוס של הערך המוחזר על ידי הפונקציה (מצויין בכותרת הפונקציה) או ניתן להמרת implicit אליו. בדוגמה שלנו הטיפוסים מתאימים זה לזה ולא תיווצר שום בעייה (מחזירים int).
 
=== טיפוס void ===
{{בעבודה}}
 
=== פונקציית main ===
== קריאה לפונקציות ==
 
== הכרזת פונקציות ==
 
לפני שנוכל להשתמש בשם כלשהו ב-C++&lrm;, לרוב, תחילה נצטרך להכריז עליו או להגדיר אותו. במילים אחרות, המהדר שקורא את קבצי התוכנית מהתחלה עד הסוף, צריך להתקל כבר בהכרזת שם זה על מנת להכיר אותו. ההכרזה אומרת למהדר שקיים שם מסויים (למשל i) ושיש להתייחס אליו כלדבר מסויים (למשל כלשם של משתנה מטיפוס int). דבר זה תקף גם עבור שמות הפונקציות. הפונקציות שנמצאות בספריות כלשהן, למשל atan2 שהשתמשנו בה למעלה, מוכרזות בקבצי ההכללה של הספריות אלה (דוגמה <cmath>).
 
כאשר נכתוב פונקציה משלנו, נצטרך לפעמים להכריז עליה לפני שנשתמש בה. אנחנו חייבים להשתמש בהכרזה כאשר אנחנו מפרקים את התוכנית למודולים (למספר קבצי קוד, לרוב עם סיומת cpp), או כאשר אנחנו משתמשים בשתי פונקציות רקורסיביות הקוראות זו לזו (למד בהשמך). במקרה של תוכנית פשוטה בעלת קובץ אחד נוכל להגדיר את הפונקציה לפני השימוש הראשון בה. לדוגמה אם נקרא לפונקציה roundTO מפונקציית main, נוכל להגדיר אותה לפני פונקציית main ולהסתדר ללא הכרזות. ארגון קוד כזה גורם להופעת פונקציה main בסוף הקוד בתור פונקציה אחרונה. כמו כן קיימים מתכנתים המעדיפים להגדיר את הפונקציות אחרי ה-main, במקרה כזה עליהם להוסיף שורות נוספות לפני פונקציית main שהן שורות ההכרזה.
 
== רקורסיה ==
 
== העמסת פונקציות ==
 
העמסת פונקציות (Overloading) היא יצירה של יותר מפונקציה אחת עם אותו שם, כאשר הן נבדלות זו מזו על ידי רשימת הפרמטרים שלהן.<br /> יש צורך באלמנט זה בכדי ליצור פונקציה אחת (בעצם כמה, בעלות שם זהה) שהיא רב שימושית, הוי אומר שלמשל פונקציה שמחזירה את הגדול מבין שני מספרים שמתקבלים כפרמטרים תהיה מתאימה למספר טיפוסי נתונים.<br /> למשל: היא תוכל לחשב את התוצאה גם אם יתקבלו משתנים מטיפוס int וגם אם יתקבלו משתנים מטיפוס double, ואפשר כמובן שיהיה שוני בין שני החישובים.