1 / 23

תכנות מערכות בשפת C

מכללת אורט כפר-סבא. תכנות מערכות בשפת C. פונקציות מערכים. 10.09.14. אורי וולטמן. uri.weltmann@gmail.com. מציאת המחלקים של מספר נתון.

dara-dodson
Download Presentation

תכנות מערכות בשפת C

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. מכללת אורט כפר-סבא תכנות מערכות בשפת C פונקציות מערכים 10.09.14 אורי וולטמן uri.weltmann@gmail.com

  2. מציאת המחלקים של מספר נתון כתבו פונקציה שכותרתה void print_divisors (int num) המקבלת כפרמטר מס' שלם חיובי גדול מ-1, ומציגה כפלט על המסך את רשימת מחלקיו של המספר הנתון. המחלקים של מס' טבעי נתון הם כל המס' הטבעיים המחלקים אותו ללא שארית. למשל, עבור הזימון print_divisors(6) יוצג על המסך הפלט: 6, 3, 2, 1. מה יהיה הפלט עבור print_divisors(12) ? print_divisors(29) ? print_divisors(30) ?

  3. מציאת המחלקים של מספר נתון • רעיון לפתרון: נסרוק את תחום המספרים שבין 1 לבין המספר הנתון, ונבדוק עבור כל מספר בתחום אם הוא מחלק את הפרמטר num ללא שארית. void print_divisors (int num) { int i; for (i=1; i<=num; i++) if ((num % i) == 0) printf (“%d “, i); } את משפט התנאי ניתן היה להחליף ב- if (!(num % i)) כזכור, בשפת C אין טיפוס נתונים בוליאני, ולכן הערך 0 נחשב 'false' וכל ערך שונה מאפס נחשב 'true'.

  4. מציאת המחלקים של מספר נתון • אחד המאפיינים של חלוקה בשלמים הוא שהמחלקים של כל מספר טבעי N, אינם גדולים מ-N/2 (למעט N עצמו). • למשל: המחלקים של 12=N הם 1,2,3,4,6,12, וכולם (למעט 12 עצמו) אינם גדולים מ-N/2=12/2=6. • נשתמש בתכונה זו ונפתח לולאה יעילה יותר. void print_divisors (int num) { int i; for (i=1; i<=num ; i++) if ((num % i) == 0) printf (“%d “, i); } i<=num/2 printf (“%d”, num);

  5. פונקציות מתמטיות (math.h) בקובץ math.h מוגדרות מספר פונקציות מתמטיות: sqrt – מקבלת מס' ממשי ומחזירה את השורש הריבועי שלו. floor – מקבלת מס' ממשי ומחזירה אותו מעוגל כלפי מטה. ceil – מקבלת מס' ממשי ומחזירה אותו מעוגל כלפי מעלה. • תרגיל: כתבו פונקציה שכותרתהint sqrt_is_int (int num)המקבלת כפרמטר מספר שלם חיובי (טבעי), ומחזירה 1 אם השורש שלו הוא מס' שלם, ו-0 אחרת. • לדוגמא: sqrt_is_int(36), sqrt_is_int(9) יחזירו 1, ואילו sqrt_is_int(3), sqrt_is_int(15) יחזירו 0.

  6. כתבו פונקציה שכותרתה void f (int n) המקבלת כפרמטר מס' טבעי n, ומציגה כפלט את כל המס' הטבעיים אשר אינם גדולים מ-n והשורש שלהם שלם. למשל, עבור הזימון f(50) יוצג על המסך הפלט: 1, 4, 9, 16, 25, 36, 49. הרעיון האלגוריתמי: נסרוק את כל המס' הטבעיים מ-1 ועד n, נזמן עבור כל אחד מהם את הפונקציה sqrt_is_int(שכתבנו קודם), ואם הפונקציה מחזירה 1 אז נציג כפלט את המספר.

  7. האם ניתן לפתח אלגוריתם אשר זמן הריצה שלו יהיה קצר מזמן הריצה של אלגוריתם זה? נפתח פונקציה המשתמשת ברעיון אלגוריתמי אחר, הפותרת את הבעיה ע"י "ייצור" מספרי הפלט באמצעות העלאה בריבוע של כל המספרים השלמים אשר ריבועם קטן מ-n. void f (int n) { int i; for (i=1; i<=n; i++) if (sqrt_is_int(i)) printf (“%d “, i); } void f (int n) { int i; for (i=1; i<=sqrt(n); i++) printf (“%d “, i*i); }

  8. בדיקת ראשוניות כתבו פונקציה שכותרתה int is_prime (int n) המקבלת כפרמטר מס' טבעי גדול מ-1, ומחזירה 1 אם הוא ראשוני, ו-0 אם הוא פריק. מספר ראשוני (prime number) הוא מספר טבעי הגדול מ-1 אשר לא מתחלק באף אחד מהטבעיים שקטנים ממנו (פרט ל-1). הגדרה נוספת למספר ראשוני: מספר טבעי שיש לו בדיוק שני מחלקים (הוא עצמו, ו-1). מספר פריק (composite number) הוא מספר שאיננו ראשוני. מה יהיה הרעיון האלגוריתמי מאחורי הפתרון?

  9. מדוע הלולאה מתחילה מ-2 ולא מ-1? ומדוע היא מסתיימת ב-n-1 ולא ב-n? האם אפשר לנצל רעיון מאחת הבעיות הקודמות בכדי לייעל את הלולאה? נשפר את האלגוריתם על-די קביעת הגבול העליון של הלולאה ב-n/2. int is_prime (int n) { int i; for (i=2; i<=n-1; i++) if (n % i == 0) return 0; return 1; } int is_prime2 (int n) { int i; for (i=2; i<=n/2; i++) if (n % i == 0) return 0; return 1; }

  10. בדיקת ראשוניות הקטנו את הגבול העליון של הלולאה בחצי (במקום N-1 מגיעים רק עד N/2), אבל ניתן לצמצם עוד. • מחלקים באים בזוגות. • ככל שמחלק גדול יותר, כך "בן זוגו" קטן יותר. • איך אפשר להשתמש בעובדה זו לשיפור הלולאה?

  11. בדיקת ראשוניות טענה: אם N אינו ראשוני, אז יש לו מחלק שקטן או שווה לשורש N. הוכחה: נניח בשלילה שכל המחלקים של N גדולים משורש N. אז קיימים שני מחלקים גדולים משורש N, שמכפלתם שווה N. נרשום כל-אחד מהם בתור שורש N + מס' חיובי, ואז אם נכפול אותם נקבל מצד אחד שהמכפלה שווה N, ומצד שני היא שווה למס' גדול מ-N, וזו סתירה. • מטענה זו נסיק כי אין צורך לחפש מחלק שגדול מהשורש הריבועי. ננצל עובדה זו כדי לצמצם את הגבול העליון של הלולאה המחפשת מחלקים.

  12. מה ניתן לומר על המחלקים הזוגיים של מס' לא-ראשוני N? ברור שאם מס' זוגי כלשהו מחלק את N, אזי גם 2 מחלק את N. איך אפשר לנצל עובדה זו כדי לשפר את יעילות האלגוריתם? אם N אינו מתחלק ב-2, אין טעם לבדוק מס' זוגיים נוספים כמחלקים אפשריים: אם 2 = N, אזי הוא ראשוני. אם N הוא מס' זוגי שונה מ-2, אזי הוא אינו ראשוני. עבור יתר המקרים – אין צורך לבדוק מחלקים זוגיים, אלא רק מחלקים אי-זוגיים. int is_prime2 (int n) { int i; for (i=2; i<=n/2; i++) if (n % i == 0) return 0; return 1; } int is_prime3 (int n) { int i; for (i=2; i<=sqrt(n); i++) if (n % i == 0) return 0; return 1; } int is_prime4 (int n) { int i; if (n == 2) return 1; if (n % 2 == 0) return 0; for (i=3; i<=sqrt(n); i+=2) if (n % i == 0) return 0; return 1; }

  13. משתנים מטיפוס שלם בשפת C, משתנה מטיפוס שלם מוגדר בד"כ להיות int או long, וההבדל ביניהם הוא בגודל המשתנה (מס' הבתים בזיכרון שהמשתנה תופס). משתנים מטיפוס int תופסים פחות מקום בזיכרון מאשר long, ולכן מסוגלים להכיל טווח ערכים קטן יותר. מס' הבתים (bytes) שכל טיפוס תופס בזיכרון, משתנה מסביבת עבודה אחת לשנייה. אם, למשל, גודלו של int הוא 2 בתים, אז טווח הערכים שלו הוא 32,767+ ... 32,768-. אם גודלו של long הוא 4 בתים, אז טווח הערכים שלו הוא 2,147,483,647+ ... 2,147,483,648-. נוכל לברר כמה בתים תופס כל טיפוס בסביבת העבודה שלנו, על-ידי שימוש בפונקציה sizeof: printf (“%d %d”, sizeof(int), sizeof(long))

  14. משתנים מטיפוס שלם על-ידי הוספת המילה השמורה unsigned לפני שם הטיפוס, נוכל להגדיר משתנה נטול סימן (כלומר, אי-שלילי בלבד). בעוד ש-int הוא 32,767+ ... 32,768- unsigned int הוא 65,535+ ... 0 ובעוד ש-long הוא 2,147,483,647+ ... 2,147,483,648- unsigned long הוא 4,294,967,295 + ... 0 בדוגמאות הנ"ל הנחנו ש-sizeof(int)=2, ו-sizeof(long)=4 . אפשר להוסיף signed לפני שם של משתנה, בכדי להדגיש שמדובר במשתנה שיכול לקבל גם ערכים שליליים (כלומר, להגדיר אותו להיות מטיפוס signed int או signed long), אבל אין חובה לעשות זאת. לא ניתן לרשום signed/unsigned לפני משתנה מטיפוס ממשי.

  15. היפוך מספר שלם כתבו פונקציה שכותרתה המקבלת כפרמטר מספר שלם וחיובי (טבעי) x, ומחזירה את המספר המורכב מספרותיו של x, אך בסדר הפוך. למשל, עבור הזימון reverse(1293),יוחזר המספר 3921. עבור הזימון reverse(34),יוחזר המספר 43. עבור הזימון reverse(10),יוחזר המספר 1. עבור הזימון reverse(3),יוחזר המספר 3. מדוע שלא נגדיר גם את הערך המוחזר של הפונקציה להיות unsigned int, כמו הפרמטר? עבור הזימון reverse(59999),יוחזר המספר 99995. נניח והגדרנו את הערך המוחזר להיות unsigned int במקום unsigned long. מהו הערך הקטן ביותר של הפרמטר, שעבורו הפונקציה תחזיר ערך שגוי? (הניחו ש-int גודלו 2 בתים בזיכרון המחשב) unsigned long reverse (unsigned int x)

  16. שזירת מספרים כתבו פונקציה שכותרתה המקבלת כפרמטרים שני מס' שלמים וחיוביים (טבעיים) a ו-b, ומחזירה את המספר המורכב מספרותיהם של a ו-b, באופן הבא: ספרה של a, ולימינה ספרה של b, ולימינה ספרה של a, ולימינה ספרה של b, וכך הלאה. למשל, עבור הזימון merge(1293,3456),יוחזר המספר 13249536. עבור הזימון merge(415,34),יוחזר המספר 43145. עבור הזימון merge(27,1009),יוחזר המספר 217009. רמז: השתמשו בפונקציה reverse שכתבתם בתרגיל הקודם. unsigned long merge (unsigned int a, unsigned int b)

  17. מערכים בשפת C בשפת C מצהירים על מערך באופן הבא: int grades[30] float height[20] int A[8] • המיספור של מערך בשפת C מתחיל מאפס, ולא מ-1. • הערך ההתחלתי של כל תא במערך הוא "זבל". • אסור לחרוג מגבולות המערך!

  18. תרגיל ראשון במערכים נתונה הצהרת המערך: int temp[10] כתבו תכנית מחשב ובה - לולאה להשמת הערך 0 בכל אחד מאיברי המערך. לולאה לקליטת עשרה נתוני קלט באיברי המערך. לולאה להכפלה ב-2 את ערכו של כל איבר במערך. לולאה להצגה כפלט של כל איברי המערך.

  19. תרגיל במערכים נתון המערך A בן 100 איברים מטיפוס שלם, ונתון המשתנה i מטיפוס שלם. תאר את מטרת הלולאה הבאה: תאר את מטרת הלולאה הבאה: האם שתי הלולאות מבצעות את אותה המשימה? החלף את הלולאה השנייה בלולאה יעילה יותר. for (i=0; i<=99; i++) if (A[i] % 5 == 0) printf (“%d “, A[i]); for (i=0; i<=99; i++) if (i % 5 == 0) printf (“%d “, A[i]);

  20. תרגיל במערכים נתון המערך A שהצהרתו היא int A[8], וערכי איבריו הם: עבור אילו מארבע הלולאות הבאות תהיה חריגה מגבולות המערך? מה יהיו ערכי המערך אחרי ביצוע הלולאה הבאה? for (i=0; i<=7; i++) A[i] = A[i+1]; for (i=0; i<=6; i++) A[i] = A[i]*2; for (i=0; i<=6; i++) A[i] = A[i-1]; for (i=0; i<=6; i++) A[i] = A[i*2]; for (i=1; i<=7; i++) A[i-1] = A[i];

  21. תרגיל במערכים כתבו תכנית המקבלת כקלט 120 ציונים (כל ציון הוא מספר שלם בטווח בין 0 ל-100), ומציגה כפלט את מספר הציונים הגבוהים מהממוצע. #include <stdio.h> #define SIZE 120 int main() { int grades[SIZE], sum = 0, counter = 0, i; float average; for (i=0; i<SIZE; i++) { scanf (“%d”, &grades[i]); sum += grades[i]; } average = (float)sum/SIZE; for (i=0; i<SIZE; i++) if (grades[i] > average) counter++; printf (“The number of above average grades is %d”, counter); return 0; }

  22. תרגיל במערכים – פתרון המשתמש בפונקציות #include <stdio.h> #define SIZE 120 void read_array (int ar[], int n) /* תאים n הוא מערך של שלמים שגודלו ar טענת כניסה: */ /* טענת יציאה: הפונקציה קולטת ערכים ושומרת במערך */ { int i; for (i = 0; i < n; i++) scanf (“%d”, &ar[i]); } int sum_array (int ar[], int n) /* תאים n הוא מערך של שלמים שגודלו ar טענת כניסה: */ /* טענת יציאה: הפונקציה מחזירה את סכום איברי המערך */ { int sum = 0, i; for (i = 0; i < n; i++) sum += ar[i]; return sum; }

  23. תרגיל במערכים – פתרון המשתמש בפונקציות int num_of_elements_above_bound (int ar[], int n, float bound) /* תאים n הוא מערך של שלמים שגודלו ar טענת כניסה: */ /* bound טענת יציאה: הפונקציה מחזירה את מספר האיברים במערך שגדולים מ-*/ { int i, counter = 0; for (i = 0; i < n; i++) counter += (ar[i] > bound); return counter; } int main() { int grades[SIZE], above_avg; float average; read_array(grades,SIZE); average = (float)sum_array(grades,SIZE) / SIZE; above_avg = num_of_elements_above_bound(grades,SIZE,average); printf (“The number of above average grades is %d”, above_avg); return 0; }

More Related