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

תוכן שנמחק תוכן שנוסף
BRUTE (שיחה | תרומות)
rw
שורה 45:
{
return 1.8 * celsius + 32;
}
</source>
 
==הגדרת פונקציה==
על מנת להגדיר פונקציה, יש לכתוב:
<source lang = "c">
<return_type> <function_name>(<arguments>)
{
<body>
}
</source>
כאשר:
*return_type הוא סוג הערך המוחזר מהפונקציה (אם לא רוצים שהפונקציה תחזיר אף משתנה, כותבים void כטיפוס המשתנה).
*function_name הוא שם הפונקציה.
*arguments הם ''ארגומנטים'', כלומר משתנים שערכם נקבע מחוץ לפונקציה.
*body הוא הפקודות המתבצעות כשהפונקציה נקראת.
 
 
מייד לאחר שם הפונקציה צריכים להופיע סוגריים שבהם תכתב רשימת הפרמטרים שהפונקציה תקבל. גם אם הפונקציה לא מקבלת פרמטרים עדיין יש לכתוב את הסוגריים. לאחר הסוגריים ייפתחו סוגריים מסולסלים שמציינים את תחילת קטע הקוד של הפונקציה, ובסוף הפונקציה יופיעו סוגריים מסולסלים נוספים שסוגרים אותה.
 
בגוף הפונקציה אפשר לכתוב כל רצף פקודות שכבר ראינו. אם הפונקציה מחזירה ערך, צריך לכתוב בגוף הפונקציה:
<source lang = "c">
return <value>;
</source>
כאשר value הוא הערך. אם הפונקציה אינה מחזירה ערך, אז אפשר לכתוב בכל קטע
<source lang = "c">
return;
</source>
דבר שיגרום ליציאה מהפונקציה.
 
===דוגמאות===
 
====פונקציה עם ערך מוחזר====
הנה הפונקציה הממירה מספר נקודה-צפה המתאר טמפרטורה ב-Celsius לטמפרטורה ב-Fahrenheit:
<source lang = "c">
float celsius_to_fahrenheit(float celsius)
{
return 1.8 * celsius + 32;
}
</source>
הפונקציה מקבלת משתנה מסוג מספר נקודה-צפה ששמו celsius, ומחזירה מספר נקודה-צפה.
 
====פונקציה בלי ערך מוחזר====
הנה פונקציה המדפיסה את התרגום למעלות Fahrenheit של מעלות ה-Celsius בערכים {{משמאל לימין|0, 4, 8, ..., 40}}:
<source lang = "c">
void print_conversion_table()
{
int c, f;
 
for(c = 0; c <= 40; c += 4)
{
f = 1.8 * c + 32;
printf("%d in Celsius is %d in Fahrenheit\n", c, f);
}
}
</source>
פונקציה זו איננה מקבלת אף פרמטר, ו(בלי שום קשר) גם אינה מחזירה אף ערך. אפשר לראות שאינה מחזירה אף ערך ע"י כך שהיא מוגדרת כמחזירה void, שהוא טיפוס מיוחד שמשמעו שאין ערך מוחזר.
 
{{הארה|1 = בשפת C משמשת {{מונח|המילה השמורה|מילה מוגדרת בשפה}} void גם במשמעות שונה לחלוטין, שאותה נראה ב[[שפת C/מצביעים#מצביעים לvoid|מצביעים ל-void]]. אין להתבלבל בין שתי משמעויות נפרדות אלה - הן שונות זו מזו.}}
 
====פונקציה בלי ערך מוחזר ופקודת יציאה מפורשת====
נניח שהחלטנו לשאול את המשתמש האם להדפיס את טבלת ההמרות, ואם המשתמש יקליד את התו 'n', לא נדפיס כלום.. נוכל לכתוב זאת כך:
<source lang = "c">
void print_conversion_table_if_needed()
{
int c, f;
char reply;
printf("Print out conversion table?");
scanf("%c", &reply);
if(reply == 'n')
return;
 
for(c = 0; c <= 40; c += 4)
{
f = 1.8 * c + 32;
printf("%d in Celsius is %d in Fahrenheit\n", c, f);
}
}
</source>
בפונקציה הקודמת, נשים לב לשורות:
<source lang = "c">
if(reply == 'n')
return;
</source>
הפקודה return גורמת ליציאה מהפונקציה (בלי ערך מוחזר בפונקציה זו). אם הפקודה מתבצעת, אז שאר הפקודות עד סוף הפונקציה אינן מתבצעות.
 
==קריאה לפונקציה==
קריאה לפונקציה נכתבת כך:
<source lang = "c">
<function_name>(<values>)
</source>
כאשר function_name היא שם הפונקציה, ו-values הם הערכים שיש להשים למשתניה. אם הפונקציה אינה מקבלת ארגומנטים, פשוט רושמים כך:
<source lang = "c">
<function_name>()
</source>.
 
להלן דוגמה לקריאה לפונקציה celsius_to_fahrenheit:
<source lang = "c">
#include <stdio.h>
 
float celsius_to_fahrenheit(float celsius)
{
return 1.8 * celsius + 32;
}
 
 
int main()
{
int f;
f = celsius_to_fahrenheit(3);
printf("%d", f);
return 0;
}
</source>
השורה
<source lang = "c">
f = celsius_to_fahreneit(3);
</source>
קוראת לפונקציה עם הערך 3. כעת הפונקציה מתחילה לפעול, ובתוך הפוקנציה, המשתנה celsius הוא בעל הערך 3. כשהפונקציה מגיעה לשורה
<source lang = "c">
return 1.8 * celsius + 32;
</source>
חוזר רצף התוכנית לשורה שקראה לה. במקרה זה, הערך המוחזר מהפונקציה יושם למשתנה f.
 
אם נחזור שוב לתוכנית המקורית שרשמנו בתחילת הפרק, נוכל לכתוב אותה כך:
<source lang = "c">
#include <stdio.h>
 
float celsius_to_fahrenheit(float celsius)
{
return 1.8 * celsius + 32;
}
 
 
int main()
{
int c, f;
 
for(c = 0; c <= 40; c += 4)
{
f = celsius_to_fahrenheit(c);
printf("%d in Celsius is %d in Fahrenheit\n", c, f);
}
 
printf("Enter degrees in Clesius: ");
scanf("%d", &c);
f = celsius_to_fahrenheit(c);
printf("This is %d in Fahrenheit\n", f);
return 0;
}
</source>
למעשה, כפי שכתובה התוכנית כעת, נוכל אפילו לוותר על חלק מהמשתנים, ולכתוב אותה בצורה קצרה יותר כך:
<source lang = "c">
#include <stdio.h>
 
float celsius_to_fahrenheit(float celsius)
{
return 1.8 * celsius + 32;
}
 
 
int main()
{
int c;
 
for(c = 0; c <= 40; c += 4)
printf("%d in Celsius is %d in Fahrenheit\n", c, celsius_to_fahrenheit(c));
 
printf("Enter degrees in Clesius: ");
scanf("%d", &c);
printf("This is %d in Fahrenheit\n", celsius_to_fahrenheit(c));
return 0;
}
</source>
שורה 77 ⟵ 261:
}}
 
===פונקציות פלט וקלט===
[[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]][[קובץ:[[קובץ:PictureFileName.jpg|left|thumb|250px|כיתוב תמונה]]]]]]]]]]]]]]]]]]]]]]]]]]===פונקציות פלט וקלט===
 
ב[[שפת C/פלט וקלט|פלט וקלט]] ראינו כבר את הפונקציות printf, scanf, putchar, ו getchar.
 
<nowiki>==הצהרה על פונקציות==
 
נתבונן בתוכנית הבאה:
שורה 155 ⟵ 339:
printf("%d",y);
}
</source>
</source></nowiki><math>[[מדיה:formula]][[קובץ:
== PictureFileName.jpg|left|thumb|250px|כיתוב תמונה ==
[[מדיה:[[מדיה:Example.ogg]][[מדיה:[[מדיה:Example.ogg]][[מדיה:[[מדיה:Example.ogg]][[מדיה:Example.ogg]]]]]]]]]]</math>
 
==פונקציות רקורסיביות==
שורה 196 ⟵ 378:
</source>
 
==מעט על פונקציות והנדסת תוכנה==
בדיקה
 
שפת C משמשת לכתיבת תוכנות מסובכות מאד. הקוד של [[w:לינוקס (ליבה)|ליבת לינוקס]], לדוגמה, מורכב ממיליוני שורות קוד. בשפת C מתמודדים עם מורכבות זו בעזרת חלוקת הקוד לפונקציות (וכן, במידה מסויימת, על ידי חלוקה ל[[שפת C/מודולים|מודולים]]). תכנות טוב מבוסס על חלוקת כל תוכנית למספר פונקציות, כך שלכל אחת מטרה מוגדרת אחת. כאשר פונקציה עושה יותר מדי פעולות, או כאשר קטעי קוד חוזרים על עצמם בפונקציות שונות, מחלקים את הקוד לפונקציות קטנות יותר. בצורה זו ניתן לפשט תוכנית שמבצעת משימות מורכבות לתוכנית שבה כל פונקציה לבדה מבצעת משימה פשוטה, ומורכבות התוכנית נובעת מהבנייה ההדרגתית של פונקציות אחת על השנייה. הייתרונות המושגים על ידי כך:
*הקוד נוח לקריאה וברור.
*קל יותר לשנות או לתקן כל פונקציה בנפרד, כך שאם מתגלה בעיה באחד מחלקי התוכנית מספיק לתקן רק את החלק הזה, מבלי שהדבר ישפיע על שאר חלקי התוכנית.
*הקוד מאפשר שימוש חוזר. אם קטע קוד נבדק ועובד, ואנו צריכים את אותו קטע קוד בחלק אחר של התוכנית, אין צורך לשכפל אותו.
 
נשתמש בקוד שראינו ב[[שפת C/פונקציות#הצורך בפונקציות|צורך בפונקציות]] כדוגמה (למרות שזהו קוד פשוט מאד). ראשית נתבונן בפונקציה main:
<source lang = "c">
#include <stdio.h>
 
 
int main()
{
int c, f;
 
for(c = 0; c <= 40; c += 4)
{
f = 1.8 * c + 32;
printf("%d in Celsius is %d in Fahrenheit\n", c, f);
}
 
printf("Enter degrees in Clesius: ");
scanf("%d", &c);
f = 1.8 * c + 32;
printf("This is %d in Fahrenheit\n", f);
return 0;
}
</source>
ברור למדי שהפונקציה מבצעת שני דברים: מדפיסה טבלת המרות, וממירה שאילתה בודדת. נחלק, לכן, את הקוד לפונקציות:
<source lang = "c">
#include <stdio.h>
 
 
void print_init_conversion_table();
void handle_conversion_query();
 
 
int main()
{
print_init_conversion_table();
handle_conversion_query();
return 0;
}
 
 
void print_init_conversion_table()
{
int c, f;
 
for(c = 0; c <= 40; c += 4)
{
f = 1.8 * c + 32;
printf("%d in Celsius is %d in Fahrenheit\n", c, f);
}
}
 
 
void handle_conversion_query()
{
int c, f;
 
printf("Enter degrees in Clesius: ");
scanf("%d", &c);
f = 1.8 * c + 32;
printf("This is %d in Fahrenheit\n", f);
}
</source>
כעת נשים לב לשורת ההמרות שחוזרת על עצמה (כפי שראינו מקודם), ונהפוך אותה לפונקציה:
<source lang = "c">
#include <stdio.h>
 
 
float celsius_to_fahrenheit(int celsius);
void print_init_conversion_table();
void handle_conversion_query();
 
 
int main()
{
print_init_conversion_table();
handle_conversion_query();
return 0;
}
 
 
void print_init_conversion_table()
{
int c, f;
 
for(c = 0; c <= 40; c += 4)
printf("%d in Celsius is %d in Fahrenheit\n", c, (int)celsius_to_fahrenheit(c));
}
 
 
void handle_conversion_query()
{
int c;
 
printf("Enter degrees in Clesius: ");
scanf("%d", &c);
printf("This is %d in Fahrenheit\n", (int)celsius_to_fahrenheit(c));
}
 
 
float celsius_to_fahrenheit(int celsius)
{
return 1.8 * celsius + 32;
}
</source>
איכות הקוד כעת טובה יותר:
*הקוד חסין יותר מטעויות - צמצמנו את מספר המקומות בהם נצטרך לשנות משהו אם יש טעות בנוסחת ההמרה, לדוגמה.
*הקוד גמיש יותר - קל יהיה לשנות את הקוד אם תגיע דרישה לתוכנית שתעשה משהו אחר, לדוגמה:
**תוכנית ששואלת את המשתמש האם להדפיס טבלת המרה '''או''' לענות על שאילתה
**תוכנית שמדפיסה טבלת המרה, ואז עונה על שאילתות בלולאה עד שהמשתמש מציין שסיים
 
 
 
ב[[שפת C/ניהול זיכרון דינאמי#מעט על מבנים והנדסת תוכנה|מעט על מבנים והנדסת תוכנה]] נדבר עוד על עניינים אלה בהקשר של ''[[שפת C/מבנים|מבנים]]''.
 
{{שפת C|מוגבל}}
 
[[קטגוריה:שפת C|פונקציות]]