המדריך השלם
 

פונקציות

בפרק הראשון טענו כי שפת c הינה שפה פרוצדוראלית, משמע שניתן לפרק את התוכנית לפונקציות - כל פונקציה בעלת תפקיד מוגדר וניתן להשתמש בה על ידי קריאה לפונקציה.
היתרון הוא פשטות הקריאה של התוכנית והבנתה.
פונקציה אם כך היא קטע קוד בעל שם ייחודי (כמו main) בעלת מטרה ברורה, לדוגמא - פונקציה הקוראת נתונים מהמקלדת, מדפיסה, ממיינת וכו'.

תבנית ההגדרה של פונקציה:
returned_type function_name (list_of_parameters)

returned_type - טיפוס הערך שהפונקציה מחזירה. לדוגמא, הפונקציה main אינה מחזירה ערך ולכן טיפוס הערך המוחזר שלה יהיה void (ריק).
function_name - שם הפונקציה. יש לתת שם משמעותי שיעיד על תפקיד הפונקציה. כפי שציינו שם הפונקציה הראשית הוא main ואינו ניתן לשינוי.
list_of_parameters - רשימת פרמטרים (משתנים), מופרדים על ידי פסיקים. הפרמטרים הם ערכי המשתנים להם זקוקה הפונקציה על מנת לבצע את תפקידה.לדוגמא, אם נבנה פונקציה המחשבת סכום האיברים במערך אזי נשלח את המערך כפרמטר לפונקציה, הפונקציה תכיר במערך ותוכל לחשב את סכומו.
במקרה ואין צורך בפרמטרים נשאיר את הסוגריים של הפונקציה ריקים.

הגדרה:
ארגומנטים - המשתנים המוצבים בעת הקריאה לפונקציה.
פרמטרים - הם המשתנים שמופיעים בתוך הסוגריים של הפונקציה. לתוכם מוצבים הארגומנטים שהתוכנית שולחת.

כאשר אנו שולחים כפרמטר מערך דו מימדי ניתן להשמיט את המימד הראשון אך השני חייב להופיע. בהעברת מערך חד מימדי כפרמטר ניתן להשמיט את גודלו.

כאשר כותבים את הפונקציות מעל לפונקציה הראשית (main) אין צורך בהצהרה מוקדמת על פונקציה. לעומת זאת אם הפונקציה נכתבת לאחר הפונקציה הראשית יש צורך להצהיר עליה (כדי שהפונקציה הראשית תכיר אותה) כפי שהגדרנו תבנית הגדרה של פונקציה או ללא שם הפרמטר.

לדוגמא:

int sum (int s);
:או גם כך
int sum (int);
בשני המקרים המהדר יידע שהפונקציה תוגדר בהמשך.

בכתיבת הפונקציה ובהגדרתה ניתן להשתמש בשמות שונים לארגומנטים כלומר, אם נשלח לפונקציהa משתנה ששמו b, לא חייב השם b להופיע אח"כ בפונקציה אלא ניתן להשתמש בשמות אחרים. זאת מכיוון שערכו של המשתנה הוא זה שמועתק לפרמטר של הפונקציה, כלומר עם ביצוע הקריאה לפונקציה מועתקים זה אחר זה ערכי הארגומנטים המצויים בפקודה הקוראת אל הפרמטרים של הפונקציה הנקראת ומאתחלים אותם.
כאשר קוראים לפונקציה אנו חייבים לספק לה את הערכים הדרושים בהתאם לפרמטרים השונים של הפונקציה כך שבזמן שאנו קוראים לפונקציה ערכים אלו מועתקים לפרמטרים השונים וניתן לשנות את הערכים של הפרמטרים מבלי שהדבר יפגע בערכים ששלחנו.
ניתן לקרוא לפונקציה מספר לא מוגבל של פעמים.

כאשר מעבירים משתנים לפונקציה כפרמטרים, ערכי המשתנים לא משתנה לאחר ביצוע הפונקציה. עם זאת, מאחר ובמערך המצב שונה (לא מתבצעת העתקה, כפי שכבר הוזכר), גם בקריאה לפונקציה לא נעשית העתקה של ארגומנט מערך לפרמטר של הפונקציה ושינוי שמבצעים בפונקציה בערכי המערך ישאיר את ערכי המערך עם השינוי גם לאחר סיום ביצוע הפונקציה.

דוגמא 1:

משולש פסקל - כידוע מכיל את מקדמי הבינום של ניוטון, כל איבר מתקבל מסכום שני האיברים שמתחתיו. יצרנו מערך בגודל 9X9 אבל השתמשנו בחציו, כל שאר התאים במערך מכילים 0.

#include <stdio.h>

const int LENG = 9;

void creating_arr (int paskal[][LENG])
{
    int i,j;
    for (i = 0; i < LENG; i++)
       for (j = 0; j < i+1; j++)
       {
          if (j == 0 || j == i)
             paskal[i][j] = 1;
          else
             paskal[i][j] = paskal[i-1][j-1]+paskal[i-1][j];
       }
}

void writing_arr (int paskal[][LENG])
{
    int i,j;
    for (i = 0; i < LENG; i++)
    {
       printf("\n");
       for (j = 0; j < i+1; j++)
          printf("%d ", paskal[i][j]);
    }
}

void main()
{
    int paskal[LENG][LENG] = {0};
    creating_arr (paskal);
    writing_arr (paskal);
}


הערה:
הצהרנו על "משתנה" מסוג קבוע (const) משמע ערכו לא יוכל להשתנות במהלך התוכנית (מקובל לכתוב קבוע באותיות גדולות).
ניתן להצהיר על קבוע מכל טיפוס שהוא : שלם, ממשי, תווי וכו'.
כאשר מעוניינים שערכם של הארגומנטים ישתנו אז יש לכתוב את אופרטור הכתובת (&) לפני הארגומנט ששולחים וכן בהצהרה על הפונקציה יש לכתוב כפרמטר את סוג הטיפוס ואחריו * (הסבר מלא יובא כשנדבר על מצביעים - כרגע חשוב להבין שכאשר אנו משנים את ערכו של משתנה בתוך פונקציה ומעוניינים ששינוי זה ישמר גם מחוץ לפונקציה יש לשלוח כארגומנט את המשתנה ולפניו לרשום &, ובפונקציה להצהיר על הפרמטר ששלחנו (עם &) עם כוכבית לדוגמא שלחנו &x ו x משתנה שלם אזי בהצהרה של הפונקציה הפרמטר יהיה int* x).

משפט return

זהו הערך המוחזר על ידי הפונקציה. כאשר הפונקציה אינה מטיפוס void אז היא צריכה להכיל לפחות משפטreturn אחד שיופיע כך: return exp. ערכו של הביטוי exp מחושב וידוע. ביצוע של משפט זה מסיים את פעולתה של הפונקציה וחוזרים להמשך הפונקציה שקראה לה.

הערה:
פונקציה מטיפוס void נקראת פרוצדורה.
ניתן לרשום בפרוצדורה משפט return על מנת לסיים אותה אך ללא ערך מוחזר .

דוגמא 2:

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

const int LENG = 9;

void creating_arr (int matrix[][LENG])
{
    int i,j;
    for (i = 0; i < LENG; i++)
       for (j = 0; j < LENG; j++)
          matrix[i][j] = random(40);
}

void printing_arr (int matrix[][LENG])
{
    int i,j;
    printf("The array is: \n");
    for (i = 0; i < LENG; i++)
    {
       printf("\n");
       for (j = 0; j < LENG; j++)
          printf("%3d ", matrix[i][j]);
    }
}

int sum_arr (int matrix[][LENG])
{
    int i, j, sum = 0;

    for (i = 0; i < LENG; i++)
       for (j = 0; j < LENG; j++)
          sum += matrix[i][j];
    printf ("\n\rSum of array is:");
    return sum;
}

int max_arr (int matrix[][LENG])
{
    int i, j, max = matrix[0][0];

    for (i = 0; i < LENG; i++)
       for (j = 0; j < LENG; j++)
          if (max < matrix[i][j])
             max = matrix[i][j];
    printf ("\n\rMax of array is:");
    return max;
}

void main()
{
    randomize();
    clrscr();
    int arr[LENG][LENG];
    creating_arr (arr);
    printing_arr (arr);
    printf(" %d ",sum_arr (arr));
    printf ("%d", max_arr (arr));
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


הערה:
גם פונקציית ()main יכולה להיות מטיפוס שונה מ void ולהחזיר ערך.
לדוגמא:
int main()
{
    . . .
    return 0;
}


דוגמא 3:

#include <stdio.h>
#include <conio.h>

long factorial (int n);
int chack_num (int num);

void main()
{
    int num;
    long fuc;

    printf("Enter a number 0-9: ");
    scanf ("%d", &num);

    while (!chack_num (num))
    {
       printf ("\n\rWrong number Try again: ");
       scanf ("%d", &num);
    }
    fuc = factorial(num);
    printf ("\n\rThe factorial of your number is: %ld",fuc);
}

int chack_num (int num)
{
    if (num > 9 || num < 0)
       return 0;
    else
       return 1;
}

long factorial (int n)
{
    int i = 1;
    double fuc = 1;
    for ( ; i <= n ; i++)
       fuc *= i;
    return fuc;
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


טווח ההכרה

כפי שציינו בפרקים קודמים פונקציה (או משתנה) מוכר ממקום הגדרתו ועד סוף התוכנית כך שכל פונקציה יכולה לקרוא לפונקציות מוכרות לה (אלה שכתובות מעליה ולכן נהוג לכתוב את הפונקציה הראשית אחרונה).

דוגמא:
void a()
{
    . . .
}
void b()
{
    . . .
}
void c()
{
    . . .
}
void main()
{
    . . .
}
פונקציה b מכירה רק את פונקציה a.
פונקציה c מכירה את הפונקציות a, b.
פונקצית main מכירה את הפונקציות a, b, c.

דיברנו בפרקים קודמים על משתנים גלובאליים ולוקאליים. נזכיר כי משתנים גלובליים מוכרים בכל התוכנית ממקום הגדרתם והלאה ומשתנים לוקאליים מוכרים בתוך הפונקציה שלהם בלבד - אך יש לציין כי מקומם בזיכרון משתחרר עם סיום הפונקציה.

דוגמא 4:

#include <stdio.h>
#include <conio.h>

int x = 3;

void a (int x)
{
    x = 5;
    printf ("\n\rThe value of x is: %d", x);
}

void b (int* x)
{
    (*x)++;
    printf ("\n\rThe value of *x is: %d", *x);
}

void c()
{
    x= x+2;
    printf ("\n\rThe value of x is: %d", x);
}

void main()
{
    printf ("\n\rThe value of x is: %d", x);
    a (x);
    printf ("\n\rThe value of x after function a is: %d", x);
    b (&x);
    printf ("\n\rThe value of x after function b is: %d", x);
    {
       int x = 1;
       c();
       printf ("\n\rThe value of x after function c is: %d", x);
   }
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


דוגמא 5:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

const int LENG = 5;

void create_mat (int matrix[])
{
    int i;
    for (i = 0; i < LENG; i++)
       matrix[i] = random(40);
}

void print_mat (int matrix[])
{
    int i;
    printf("\n");
    for (i = 0; i < LENG; i++)
       printf("%3d ", matrix[i]);
}

void swap (int &a, int &b)
{
    int temp;
    temp = a;
    a = b;

    b = temp;
}

void sort (int matrix[])
{
    int i, j;
    for (i = 0; i < LENG-1; i++)
       for (j = i+1; j < LENG; j++)
       {
          if (matrix[i] > matrix[j])
             swap (matrix[i], matrix[j]);
       print_mat (matrix);
       }
}

void main()
{
    randomize();
    int a[LENG];
    printf ("\n\rCreating a random array: \n\r");
    create_mat(a);
    print_mat (a);
    printf ("\n\rSorting a random array: \n\r");
    sort (a);
    print_mat (a);
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט



מבחן
© איתן 2003. כל הזכויות שמורות למערכת המידע איתן.