המדריך השלם
 

תנאי בקרה

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

פקודות לביצוע מותנה:
הפקודות if ו- else
הפקודות switch ו- case
האופרטור ?

פקודות לביצוע לולאות:
הפקודות for
הפקודה while
הפקודה do while
(ופקודות עזר break ו- continue)

המשך במקום אחר בתוכנית:
goto

משפט if

משפט בקרה המאפשר לנו ביצוע מותנה של הוראות או פקודות כאשר תנאי מסוים נבדק ומבוצע בהתאם לערכו של התנאי: אמת - המיוצג על ידי כל מספר השונה מ- 0, ושקר - המיוצג על ידי הספרה 0.
משפט if מאפשר לנו לסעף את תוכניתנו על ידי תנאי לוגי באופן הבא:

תבנית של הפקודה if:

if (term)
{
    expression a;
}
else
{
    expression b;
}

כלומר אם התנאי בתוך הסוגריים של משפט ה-if מתקיים ( ערך term הוא "אמת" כאשר ערך התנאי שונה מאפס), בצע את הפקודות המופיעות בין הסוגריים המסולסלים (expression a). אם התנאי לא מתקיים בצע את סדרת הפקודות המופיעות בין הסוגריים המסולסלים השניים (expression b) .

הערה:
אפשר גם ללא סוגריים מסולסלים אבל אז יתבצע רק המשפט הראשון שלאחר התנאי , בהנחה שהתנאי אמת.

דוגמא 1:

#include <stdio.h>

void main()
{
    int a, b;

    printf("Enter a value for a \n\r");
    a = (int)getchar();
    printf("Enter a value for b \n\r");
    flushall();
    b = (int)getchar();

    if(a > b)
      printf ("a is bigger then b");
    else
       printf ("b is bigger or equal to a");
}


הערה:
משפטif יכול להופיע גם בתוך משפטelse - לדוגמא, בדוגמא זו, אם התנאי הראשון נכשל אזי המספר השני גדול או שווה למספר הראשון. כעת נשאל לאחר משפט else (למעשה - בתוך פסקת else) אם b גדול מ- a. אם לא - ברור לנו כי a ו- b שווים. נראה זאת בדוגמא הבאה.

דוגמא 2:

#include <stdio.h>

void main()
{
    int a, b;

    printf("Enter values for a and b\n\r");
    scanf("%d %d",&a, &b);

    if (a > b)
       printf ("a is bigger then b");
    else
       if (b > a)
          printf ("b is bigger then a");
       else
          printf("a and b are equal");
}


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

תבנית לשימוש בפקודת if else :

If (exp)
{
   . . .
}
else if(exp)
{
   . . .
}
else if(exp)
{
   . . .
}
else
{
   . . .
}


הערה:
התנאי הראשון יהיה if והאחרון יהיה else.
נבדק התנאי הראשון - אם הוא מצליח (ערכו אמת) מבוצע הבלוק המתאים לו. אם השני נכשל -עוברים ל- if הבא, אם הוא מצליח מבוצע הבלוק המתאים, אחרת עוברים ל- if הבא וכך הלאה.

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

דוגמא 3:

#include <stdio.h>

void main()
{
    int a

    printf("Enter a number between 0-100: ");
    scanf("%d", &a);
    if (a < 0)
       printf("The number is not at the target");
    else if (a < 10)
       printf("The number is between 0-10");
    else if (a < 20)
       printf("The number is between 10-20");
    else if (a < 30)
       printf("The number is between 20-30");
    else if (a < 30)
       printf("The number is between 30-40");
    else if (a < 40)
       printf("The number is between 30-40");
    else if (a < 50)
       printf("The number is between 40-50");
    else if (a < 60)
       printf("The number is between 50-60");
    else if (a < 70)
       printf("The number is between 60-70");
    else if (a < 80)
       printf("The number is between 70-80");
    else if (a < 90)
       printf("The number is between 80-90");
    else if (a < 100)
       printf("The number is between 90-100");
    else
       printf("The number is bigger then 100");
}


בפקודת ה-if נשתמש באופרטורים: > , < , >= , <= , == ,!= , !.

תנאים מורכבים:
עד כה הדגמנו תנאים פשוטים כמו: קטן מ, שווה ל, שונה מ- וכו'. כעת נראה איך ניתן לכתוב תנאים מורכבים על ידי שימוש באופרטורים לוגיים : וגם (&&) ,או (||).
נמחיש על ידי דוגמא:
    int a, b;
   printf("Enter 2 numbers: \n");
   scanf("%d %d", &a, &b);
   if (a > b && a == 5)
        printf("a > b and a == 5\n");
   if (b > 7 && b < a)
        printf(" b > 7 and b < a\n");
   if (!a || !b)
        printf("a or b is zero");


סדר ביצוע פעולות בביטויים לוגיים:
ביטוי לוגי נבדק תמיד משמאל לימין עד אשר ניתן יהיה לקבוע בוודאות את ערך הביטוי - אמת או שקר. לדוגמא:
נניח שערך הביטוי x > y הוא שקר ורשמנו If (x > y && y++)
- ברור שערך הביטוי במשפט ה- if יהיה שקר, אך מאחר והביטוי נבדק משמאל לימין ומדובר בביטוי "וגם" (כל חלקיו צריכים להיות אמת על מנת שכולו יקבל ערך אמת) - הבדיקה תיפסק לאחר החלק הראשון ברגע שיסתבר שהוא שקר, ולכן החלק השני כלל לא ייבדק והמשתנה y לא יקודם באחד.

משפט swich

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

constant1- קבוע ראשון.
..
..
constantn - הקבוע ה n.

switch(exp or variable)
{
    case constant1: command; break;
    case constant2: command; break;
    case constant3: command;break;


    case constantn: command;break;
    default: command;
}



switch מקבל משתנה או ביטוי ומחשב את ערכו. הערך המתקבל הוא קבוע (ערך מספרי או אלפבתי) והפקודה שמתאימה לקבוע שחושב מתבצעת, כלומר התוכנית פונה אל שורת ה- case המתאימה ומבצעת את הפקודות הכתובות אחריה עד שהיא מגיעה לפקודת break.
מטרת הפקודה break היא למנוע את המשך ביצוע הפקודות הבאות ב- case-ים שבאים אחרי.
אם הערך המתקבל ממשפט ה- switch אינו תואם לאף אחד מה- case-ים מתבצעות ההוראות שאחרי פקודת ה-defaut.

הערה:
הפקודה default לא חייבת להופיע אך במקרה זה אם הקבוע שחושב ב switch אינו תואם את אחד ה- case- ים לא יבוצע דבר.

דוגמא 4:

#include <stdio.h>
void main()
{
    char ch;
    printf("Enter a char (between a-e): ");
    scanf("%c", &ch);

    switch(ch)
    {
       case 'a': printf("You have printed a");break;
       case 'b': printf("You have printed b");break;
       case 'c': printf("You have printed c");break;
       case 'd': printf("You have printed d");break;
       case 'e': printf("You have printed e");break;
       default: printf("Your char is not between a-e");
    }
}


וללא שימוש ב break נקבל:

דוגמא 5:

#include <stdio.h>
void main()
{
    char ch;
    printf("Enter a char (between a-e): ");
    scanf("%c", &ch);

    switch(ch)
    {
        case 'a': printf("You have printed a");
        case 'b': printf("You have printed b");
        case 'c': printf("You have printed c");
        case 'd': printf("You have printed d");
        case 'e': printf("You have printed e");
        default: printf("Your char is not between a-e");
    }
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


הביטוי המותנה ?

התבנית של ?

;condition? exp1: exp2

לפני ה- ? ישנו תנאי ובאם התנאי מתקיים יש לבצע את הביטוי הראשון. אחרת (התנאי אינו מתקיים) יש לבצע את הביטוי השני (המופיע מיד לאחר הנקודותיים "": ).
כמו כן ניתן להציב את הערך המתקבל במשתנה או לצורך הדפסה (בפקודה printf).
בעצם ניתן לתרגם ביטוי זה למשפט if כך:

if (condition)
    exp1;
else
    exp2;
דוגמא:
int x, y, z;
if (x > y)
       z = x;
   else
       z = y;
:על פי הביטוי המותנה ? נרשום כך
   int x, y, z;
   z = (x >y) ? x : y;
כך המשתנה z יקבל את הערך המקסימלי מבין המשתנים x, y


דוגמא 6:

#include <stdio.h>
void main()
{
    char ch;

    printf ("Enter a latter (a-z): ");
    scanf("%c", &ch);
    ch = ('a' <= ch && ch <= 'z')? (ch+'A'-'a'):ch;
    printf("The result is: %c", ch);
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


לולאת for

לולאות מאפשרות לבצע הוראה או בלוק הוראות בתוכנית מספר פעמים בהתאם לצרכינו.
כאשר אנו מעוניינים כי בלוק של פקודות או פקודה בודדת יתבצעו מספר פעמים אנו משתמשים בלולאת for .
לולאתfor נקראת גם לולאת אינקדס.
הלולאה בנויה משלושה חלקים:
1. אתחול משתנים.
2. תנאי ביצוע.
3. קידום משתנים.

מבנה הלולאה:

for (initialization ; boolean condition ; increment)
{
   . . .
}

שלושת חלקי הלולאה מופרדים בניהם על ידי ; (נקודה פסיק).
בחלק הראשון מתבצע אתחול משתנים, בחלק השני נבדק תנאי הלולאה - כאשר אם ערכו הבוליאני של תנאי זה אמת יבוצע גוף הלולאה ואם לא נצא מהלולאה ובחלק השלישי (המבוצע לאחר ביצוע גוף הלולאה ) מבוצע קידום משתנים.
יש לציין כי האתחול מתבצע רק פעם אחת בכניסה ללולאה, אח"כ נבדק תנאי הלולאה ואם ערכו אמת מתבצע גוף הלולאה, אח"כ קידום משתנים ושוב בדיקת תנאי הלולאה וחוזר חלילה. הרוטינה תתבצע עד אשר לא יתקיים תנאי הלולאה ואז נמשיך בתוכנית לאחר לולאת ה- for.

הערה:
אפשר לוותר על הסוגריים אם גוף הלולאה מורכב משורת קוד אחת.

דוגמא 7:

#include <stdio.h>
void main()
{
    int times;
    printf("Printing the numbers form 10 to 1: \n\r");
    for (times = 10 ; times > 0 ; times--)
        printf ("%d ", times);
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


השמטת חלקים בלולאה:
לעיתים נרצה לוותר על אחד ממרכיבי הלולאה.
כל אחד משלושת חלקי הלולאה (אתחול, תנאי לולאה, קידום) יכול להיות ריק.
לדוגמא:
int a = 5;
for ( ; a < 5; a++)
{
   . . .
}
בדוגמא זו דילגנו על אתחול המשתנה מאחר ואיתחלנו אותו מראש.

int a;
for (a = 5; a<5 ; )
{
   . . .
a++;
}
בדוגמא זו השמטנו את קידום המשתנה, הקידום נעשה בגוף הלולאה.

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

דוגמא 7.1:

#include <stdio.h>

void main()
{
    printf("Printing the numbers form 10 to 1: \n\r");
    int times = 10;

    for ( ; times > 0 ; times--)
        printf ("%d ", times);
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


אין הכרח שקידום המשתנה יהיה באחד בכל איטרציה. לדוגמא:
int a;
for (a = 40; a >=0 ; a +=2)
    printf("%d ",a);
בדוגמא זו אנו מדפיסים את המספרים הזוגיים מ 40 עד ל 0.
קידום המשתנה הוא ב- 2.
כמו כן אין הגבלה למשתנה אחד, כלומר אפשר לבצע אתחול של מספר משתנים, בדיקת תנאי לוגי על מספר משתנים וקידום של מספר משתנים יחד. לדוגמא:
int counter ;
char ch ;
for (ch = 'a', counter = 1; counter <= 26 ; ch++, counter++)
    printf("%d. %c ",counter, ch);
קטע קוד זה ידפיס את האותיות האנגליות מ- a עד z כאשר בכל שורה יופיע אינדקס האות, נקודה מפרידה ואחריה האות עצמה.
רואים כי כאשר אנו עובדים עם מספר משתנים יש להקפיד על פסיקים בניהם.

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

דוגמא 7.2:

#include <stdio.h>

void main()
{
    double i;
    double result = 1;

    printf ("Factorial function:\n\r");
    for (i = 0; i < 10; i++)
    {
        if (i != 0)
       result *= i;
        printf ("%lf\n\r", result);
    }
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


דוגמא 8:

#include <stdio.h>

void main()
{
    printf("Printing the multiplication table: \n\r");
    int i,j;

    for (i = 1 ; i <= 10 ; i++)
    {
       printf("\n\r");
       for (j = 1 ; j <= 10 ; j++)
          printf ("%2d ", i*j);
       }
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


דוגמא 8.1:

#include <stdio.h>

void main()
{
    int i, j;

    for (i = 0; i < 6; i++)
    {
       printf ("\n\r");
       for (j = 0; j <= i ; j++)
          putchar ('*');
    }
}


לולאת while

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

מבנה הלולאה:
while(boolean condition)
{
    ......
}

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

נחקה את התוכנית המדפיסה את המספרים מ 1 עד 10 על ידי לולאת while:

דוגמא 9:

#include <stdio.h>

void main()
{
    int times = 10;
    printf("Printing the numbers form 10 to 1: \n\r");
    while (times > 0)
    {
       printf ("%d ", times);
       times--;
    }
}


למעשה בתוכנית זו ידענו את מספר החזרות על גוף הלולאה ולכן ניתן לתרגם פקודת while ללולאת for כך:
for (times = 10; times > 0; times--)
   printf ("%d ", times);


דוגמא 10:

#include <stdio.h>

void main()
{
    printf("Enter a number 1-10 (quit -0): \n\r");
    int a;
    int sum = 0;

    scanf ("%d", &a);
    while (a != 0)
    {
       sum += a;
       printf("The sum so far: %d\n\r", sum);
       scanf ("%d", &a);
    }
}


את לולאת ה-while בתוכנית זו לא ניתן לתרגם ללולאתfor מפני שמספר הפעמים שהמשתמש יקיש על מקש שונה מ 0 לא ידוע לנו ולכן במקרה זה מתאימה רק לולאת while.
תנאים מורכבים בלולאה:
כמו בחלק של תנאי הלולאה בלולאתfor יכולנו לרשום תנאי מורכב עם מספר משתנים כך גם בתנאי הלולאה של לולאת while (עשינו זאת על ידי שימוש באופרטורים הלוגים : וגם, או כך גם כאן).
דוגמא:
while ( x > 47 && (y < 10 || z ==15))
גוף הלולאה יבוצע אם המשתנה x > 47 וגם y <10 או z == 15 .

לולאת do while

כמו בלולאת while פשוטה, גם כאן יש תנאי ובאם הוא מתקיים גוף הלולאה מתבצע. ההבדל הוא שראשית מבוצע גוף הלולאה ורק לאחר מכן נבדק התנאי ובאם התנאי לא מתקיים ממשיכים בתוכנית לאחר לולאת do while.
כלומר תמיד גוף הלולאה יבוצע לפחות פעם אחת.

מבנה הלולאה:
do
{
   . . .
}
while (condition)


דוגמא 11:

#include <stdio.h>

void main()
{
    int result = 0;
    printf("The sq of the number from 1 to 10: \n\r");
    do
    {
       result += 1;
       printf("%d \n\r", result*result);
    }
    while (result < 10);
}


פקודת goto

תווית(label): אוסף של פקודות המאוגדות ליחידה אחת תחת כותר מסוים, כותר זה נקרא תווית.
מבנה התווית:
label: command1;
    command2;
   . . .

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

הערה:
ניתן להוכיח כי אפשר להמיר כל תוכנית המכילה goto לתוכנית ללא goto על ידי לולאת while.

תבנית goto:
goto label;
כאשר label היא תווית.

דוגמא 12:

#include <stdio.h>

void main()
{
    int var = 0;

    a: if (var == 0)
       goto a0;
    else
       goto a1;
    a1: printf("Var != 0\n\r");
    a0: printf("Var = 0\n\r");
}


יש לשים לב איפה ממקדים את התווית משום שהשפה c פועלת באופן סדרתי כלומר אם במהלך התוכנית יש תווית היא תבצע אותן לפי הסדר ולפעמים זה גורם לטעויות ,דוגמא לכך:

דוגמא 12.1:

#include <stdio.h>

void main()
{
    int var = 0;

    a: if (var == 0)
       goto a0;
    else
       goto a1;
    a0: printf("Var = 0\n\r");
    a1: printf("Var != 0\n\r");
}

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

הפקודות break ו- continue

הפקודות break ו-continue קשורות לשלושת הלולאות שהצגנו (for, while, do while).
פקודת break מפסיקה את ביצוע הלולאה אפילו אם תנאי הלולאה מתקיים. לעומת זאת פקודתcontinue מדלגת על הפקודות שבגוף הלולאה עד לביצוע הבא של גוף הלולאה.
תבנית לשימוש בפקודת break:
if (condition)
    break;
......

השימוש יעשה בגוף הלולאה בעזרת פקודת break ניתן לקטוע לולאות אינסופיות.
נראה זאת בדוגמא הבא:

דוגמא 13:

#include <stdio.h>

void main()
{
    char ch;
    while (1)
    {
       printf ("To exit print E:\n\r");
       flushall();
       scanf ("%c", &ch);
       if (ch == 'E')
       break;
    }
}
העבר את העכבר מעל הדוגמא כדי לראות הסבר מפורט


תבנית של הפקודה continue:
if (condition)
    continue;
......

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

#include <stdio.h>

void main()
{
    int i;
    for (i = 0; i < 10; i++)
    {
       if (i % 2 == 1)
          continue;
       printf ("%d is even\n\r", i);
    }
}



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