לדלג לתוכן

3.4 בקרת זרימה פתרון

תרגיל 1

כתבו תוכנית שמבקשת מהמשתמש להכניס מספר, ומדפיסה אם הוא חיובי, שלילי או אפס.

#include <stdio.h>

int main() {
    int num;
    printf("הכנס מספר: ");
    scanf("%d", &num);

    if (num > 0) {
        printf("המספר חיובי\n");
    } else if (num < 0) {
        printf("המספר שלילי\n");
    } else {
        printf("המספר הוא אפס\n");
    }

    return 0;
}

תרגיל 2

כתבו תוכנית שמדפיסה את המספרים מ־10 עד 1 בספירה לאחור.

#include <stdio.h>

int main() {
    int i = 10;

    while (i >= 1) {
        printf("%d\n", i);
        i--;
    }

    return 0;
}

תרגיל 3

כתבו תוכנית שמבקשת מהמשתמש להכניס מספר, ואז מדפיסה את הטבלה הכפולה שלו (מ־1 עד 10).

#include <stdio.h>

int main() {
    int num;
    printf("הכנס מספר: ");
    scanf("%d", &num);

    int i = 1;
    while (i <= 10) {
        printf("%d x %d = %d\n", num, i, num * i);
        i++;
    }

    return 0;
}

תרגיל 4

כתבו לולאה שסופרת עד 100, אבל מדפיסה רק את המספרים שמתחלקים ב־7.

#include <stdio.h>

int main() {
    int i = 1;

    while (i <= 100) {
        if (i % 7 == 0) {
            printf("%d\n", i);
        }
        i++;
    }

    return 0;
}

מצוין! הנה הסבר ברור ומדויק לקוד האסמבלי שנוצר עבור סעיף 4 (הדפסת כל המספרים בין 1 ל־100 שמתחלקים ב־7), לאחר קימפול עם GCC ואובייקט objdump -d:

סעיף 5 – הסבר על קוד האסמבלי

נניח שהקוד הבא קומפל ונוצר עבורו אסמבלי דומה לזה:

main:
   push   %rbp
   mov    %rsp, %rbp
   mov    $1, -4(%rbp)          ; i = 1

.loop:
   cmp    $100, -4(%rbp)        ; while (i <= 100)
   jg     .end                  ; אם i > 100 -> קפוץ לסיום

   mov    -4(%rbp), %eax        ; eax = i
   mov    $7, %edx
   xor    %edx, %edx
   div    %edx                  ; eax / 7 -> rdx = שארית
   cmp    $0, %edx              ; בדוק אם שארית 0
   jne    .skip                 ; אם לא מתחלק ב־7, דלג

   ; כאן תתבצע קריאה ל־printf עם i כפרמטר

.skip:
   add    $1, -4(%rbp)          ; i++
   jmp    .loop

.end:
   mov    $0, %eax
   pop    %rbp
   ret

הסבר שלב אחר שלב

שלב בתוכנית C אסמבלי הסבר
int i = 1; mov $1, -4(%rbp) שמור את המספר 1 במשתנה מקומי בזכרון (i)
while (i <= 100) cmp $100, -4(%rbp)``jg .end השווה את i ל־100, אם עבר – צא מהלולאה
if (i % 7 == 0) mov -4(%rbp), %eax``div %edx``cmp $0, %edx חלק את i ב־7, בדוק אם שארית היא אפס
printf(...) קריאה לפונקציה חיצונית תתבצע רק אם המספר מתחלק ב־7
i++; add $1, -4(%rbp) הגדל את i ב־1
while חוזר ל־התחלה jmp .loop חזור לתחילת הלולאה לבדיקה נוספת
סיום התוכנית (return 0) mov $0, %eax``ret החזר ערך 0 מהפונקציה וסיים

הערות מעניינות:

  • -4(%rbp) הוא המקום בזיכרון שמוקצה למשתנה המקומי i.

  • div משתמש תמיד ב־eax כמספר שמחלקים אותו, ומחזיר את השארית ב־edx – משם נוכל לדעת אם i % 7 == 0.

  • השימוש ב־jne .skip מאפשר לדלג על ההדפסה אם i לא מתחלק ב־7.

  • ret הוא סוף של כל פונקציה – הוא מחזיר את הבקרה למי שקרא לפונקציית main.