המצגת נטענת. אנא המתן

המצגת נטענת. אנא המתן

תירגול 10: מבנים (structs) וקבצים

מצגות קשורות


מצגת בנושא: "תירגול 10: מבנים (structs) וקבצים"— תמליל מצגת:

1 תירגול 10: מבנים (structs) וקבצים

2 מבנים מבנה (structure) הוא טיפוס מורכב בשפת C .
זהו טיפוס שמיועד לאיחוד קבוצת משתנים תחת שם אחד. מגדיר טיפוס חדש בשם “struct date” struct date { int day; int month; int year; }; שדות המבנה יש להסביר שהגדרה זו יוצרת טיפוס חדש בשם struct date, הכולל בתוכו שלושה משתנים מטיפוס int: day, month, year. הדרך לתת לטיפוס את השם הרצוי, date, היא באמצעות typedef, שלא נלמד הסמסטר. שימו לב: פקודה זו אינה מקצה זיכרון כלשהו, אלא רק מגדירה טיפוס חדש. טיפוס זה יוכל לשמש אותנו בהמשך להצהרה על משתנים.

3 שימוש במבנים נגדיר משתנים מטיפוס struct date:
על מנת לגשת ל-int כלשהו בתוך yael_bd או ofer_bd עלינו להשתמש באופרטור נקודה ('.'): struct date yael_bd, ofer_bd; yael_bd.day = 1; yael_bd.month = 1; yael_bd.year = 1111; יש להדגיש כי תמיד מציינים במפורש את שם המבנה כדי לגשת למשתנה הפנימי. לדוגמה, השורה האחרונה תגרום לשגיאת קומפילציה, כי המשתנה day אינו מוגדר. printf("%d\n", ofer_bd.day); מה תדפיס השורה הבאה? printf("%d\n", day);

4 שימוש במבנים ניתן לבצע השמה של מבנה כלשהו למבנה אחר מאותו הטיפוס. פעולת ההשמה מעתיקה את התוכן של כל אברי המבנה לתוך אלו של המבנה השני. לדוגמה: פעולת ההשמה בשורה האחרונה מבצעת העתקה של שלושה int-ים, מהמבנה twin1_birthday למבנה twin2_birthday. struct date twin1_birthday; struct date twin2_birthday; twin1_birthday.day = 23; twin1_birthday.month = 12; twin1_birthday.year = 1983; twin2_birthday = twin1_birthday;

5 שימוש במבנים לא ניתן לבצע השוואה של מבנה כלשהו למבנה אחר מאותו הטיפוס. לדוגמה הקוד הבא אינו עובר קומפילציה: כדי להשוות בין מבנים נרשום פונקציה יעודית struct date twin1_birthday = { 23,12,1983 }; struct date twin2_birthday = twin1_birthday; if (twin2_birthday == twin1_birthday) printf("Twins\n");

6 תרגיל הגדירו משתנה מטיפוס צמח ששדותיו הם: שם, כמות מים ליום, כמות דשן ליום ואת התאריך בו התקבל. struct plant { char name[100]; double water_per_day; double fertilizer_per_day; struct date plant_date; }; הדגישו כי לאחר הגדרתו, גם date struct הוא טיפוס, ולכן גם הוא יוכל להופיע כשדה במבנה החדש.

7 שימושי מבנים כיוון שמבנים הם בוודאי טיפוסים, נוכל ליצור מהם מערכים כרגיל: struct date birthday_list[10]; כמו כן, נוכל ליצור משתנה plant_ptr מטיפוס מצביע שמכיל כתובות של משתנים מטיפוס struct plant. struct plant *plant_ptr = 0; יש להדגיש כי אתחלנו את המצביע ל-0 מכיוון שהוא לא מצביע לשום מקום בזיכרון. השימוש במצביע יתבצע כך: struct plant p; plant_ptr = &p; (*plant_ptr).water_per_day = 30.0;

8 שימושי מבנים נוכל להעביר מבנה כפרמטר לפונקציה by value (את המבנה עצמו): void print_plant_water(struct plant p) { printf("%f", p.water_per_day); } נוכל להעביר מבנה כפרמטר לפונקציה by address (מצביע למבנה): void print_plant_water(struct plant *p) { printf("%f", (*p).water_per_day); { יש להסביר כי כאשר מעבירים את המבנה כפרמטר, מתבצע copy by value וכאשר יש שדות רבים למבנה, העתקה זו מאוד יקרה, לכן בד"כ נעדיף להשתמש במצביע. מה עדיף?

9 האופרטור -> האופרטור -> (חץ) שמופעל על מצביע למבנה, מאפשר גישה ישירה לתוך השדות של המבנה המוצבע. למשל, נתבונן בהגדרה: struct plant my_plant; struct plant *plant_ptr = &my_plant; בעזרת המצביע plant_ptr, נוכל כעת לגשת לשדות הפנימיים של המבנה my_plant בשתי דרכים (שקולות לחלוטין): (*plant_ptr).name (*plant_ptr).water_per_day plant_ptr->name; plant_ptr->water_per_day;

10 תרגיל 1 – חורף תשע"ו מועד ב' בשאלה זו נפתור בעיות הקשורות להובלה.
כדי לנהל הובלה, כל קופסא שצריכה להכנס למשאית מתוארת ע"י המבנה הבא: struct box{ double weight; int x, y, z; }; השדה weight מתאר את משקל הקופסא. השדות x, y, z מתארים את רוחב גובה ועומק הקופסא בס"מ, בהתאמה. מכיוון שבכל הובלה יש מספר קופסאות, נעבוד עם מערך של קופסאות. למשל המערך הבא: מתאר הובלה של 4 קופסאות. weight =50.0 x=100 y=200 z=60 weight =10.5 y=80 weight =2.5 x=10 y=50 z=20 weight =3.1 x=15 y=10

11 תרגיל 1 - המשך סעיף א' (15 נקודות) ממשו פונקציה רקורסיבית שחתימתה:
double total_weight(struct box arr[], int n); הפונקציה מקבלת כקלט מערך של קופסאות ואת אורכו, ומחזירה את המשקל הכולל של הקופסאות יחד. שימו לב: אסור להשתמש במשתנים סטטיים אסור להשתמש בלולאות

12 תרגיל 1 - המשך סעיף ב' (5 נקודות)
כדי להחליט איזו מבין 2 קופסאות גדולה יותר, נשווה את הרוחב (x) שלהן. אם לשתי קופסאות אותו רוחב, נשווה את הגובה שלהן (y), ואם גם הרוחב וגם הגובה שווים, נשווה את העומק שלהן (z). אם ל-2 קופסאות אותם רוחב, גובה ועומק נגיד שגודלן שווה. ממשו פונקציה שחתימתה: struct box* boxcmp(struct box* b1, struct box* b2); הפונקציה מקבלת כקלט2 מצביעים לקופסאות, ומחזירה מצביע לגדולה ביניהן. אם הקופסאות באותו גודל, היא תחזיר מצביע לאחת מהן.

13 מבוא למדעי המחשב מ' - תירגול 2
תרגיל 1 - המשך סעיף ג' (15 נקודות) ממשו פונקציה שחתימתה: struct box* new_hovala(struct box arr1[], int n1, struct box arr2[], int n2); הפונקציה מקבלת שני מערכים של קופסאות, ממוינים מהקטנה לגדולה כפי שהוגדר בסעיף הקודם. הפונקציה מקצה מקום למערך חדש של קופסאות באורך n1+n2, ומעתיקה אליו את הקופסאות משני המערכים, כך שגם המערך החדש נותר ממוין. הפונקציה מחזירה מצביע למערך החדש. מבוא למדעי המחשב מ' - תירגול 2

14 מבוא למדעי המחשב מ' - תירגול 2
תרגיל 1 - פתרון #include <stdbool.h> struct box { double weight; int x, y, z; }; double total_weight(struct box arr[], int n) { if (n <= 0) return 0; return total_weight(arr + 1, n - 1) + arr[0].weight; { struct box* boxcmp(struct box* b1, struct box* b2) { if (b1->x != b2->x) return b1->x > b2->x ? b1 : b2; if (b1->y != b2->y) return b1->y > b2->y ? b1 : b2; if (b1->z != b2->z) return b1->z > b2->z ? b1 : b2; return b1; } מבוא למדעי המחשב מ' - תירגול 2

15 תרגיל 1- פתרון struct box* new_hovala(struct box arr1[], int n1, struct box arr2[], int n2) } struct box* arr3 = malloc((n1 + n2) * sizeof(struct box)); if (!arr3) return NULL; int i1 = 0, i2 = 0, i3 = 0; while (i1 < n1 || i2 < n2) { if (i1 == n1) arr3[i3++] = arr2[i2++]; else if (i2 == n2) arr3[i3++] = arr1[i1++]; else arr3[i3++] = is_smaller(arr1 + i1, arr2 + i2) ? arr1[i1++] : arr2[i2++]; { return arr3; bool is_smaller(struct box* b1, struct box* b2) { if (b1->x != b2->x) return b1->x < b2->x; if (b1->y != b2->y) return b1->y < b2->y; if (b1->z != b2->z) return b1->z < b2->z; return false; }

16 יש לוודא שהפתיחה הצליחה
עבודה עם קבצים - פתיחה פתיחת קובץ - הפעולה המקשרת בין מצביע מיוחד בתוכנית (מטפוס FILE*) לקובץ פיסי על ההתקן. File path and name Mode (r/w/a) פתיחת קובץ טקסט לקריאה FILE* fid=fopen)"c:\\temp\\speed1.dat", "r"); FILE* fid=fopen("c:\\temp\\speed1.dat", "w"); פתיחת קובץ טקסט לכתיבה mode operation r read w write a append יש לוודא שהפתיחה הצליחה נכתב ע"י יעל ארז. © כל הזכויות שמורות.

17 עבודה עם קבצים – קריאה וכתיבה
פעולות קריאה/כתיבה נוספות ימשיכו מהמקום בו עצרנו. while (1) { fscanf(fid1,”…”, &…); if (feof(fid)) break; fprintf(fid2, “…”, …); } בסוף הקובץ נדלק דגל eof. לא לשכוח לסגור את הקבצים בסוף fclose(fid1); fclose(fid2); נכתב ע"י יעל ארז. © כל הזכויות שמורות.

18 מבוא למדעי המחשב מ' - תירגול 2
תרגיל 2 נתון הקובץ טקסט story.txt אשר יש להכניסו לספרית הפרויקט (שם הפרויקט מתחת למיקום בו נמצא קובץ ה sln. כעת, כיתבו תוכנית אשר קוראת את הטקסט מתוך הקובץ ומדפיסה את: מספר התווים בקובץ. מספר המילים בקובץ. מספר השורות בקובץ. ניתן להניח שהמילים מופרדות ברווח יחיד ואין רווחים בתחילת ובסוף הקובץ. מבוא למדעי המחשב מ' - תירגול 2

19 תרגיל 2 - פתרון #include <stdio.h> #include <stdlib.h> int main() { FILE* fid = fopen("story.txt", "r"); if (!fid) { printf("cannot open file\n"); return 1; } int char_cnt = 0, word_cnt = 0, line_cnt = 0; while (1) { char c; fscanf(fid, "%c", &c); if (feof(fid)) break; char_cnt++; if (c == '\n') line_cnt++; if (c == ' ') word_cnt++; fclose(fid); printf("the story has %d lines, %d words and %d chars\n", line_cnt, word_cnt, char_cnt); return 0; {

20 תרגיל 3 כיתבו תוכנית אשר קולטת מהמשתמש את מספר הסטודנטים והפרטים שלהם לפי המבנה הבא (ניתן להניח ששם הסטודנט לא יעבור 100 תווים): struct student { char* name; int id; double avg; } ; התוכנית תשמור את הפרטים במערך, ולאחר מכן תכתוב אותו לקובץ בשם students.txt כיתבו תוכנית אשר קוראת את הקובץ למערך של סטודנטים

21 תרגיל 3 - פתרון struct student { char* name; int id; double avg; }; #define MAX_LEN 100 int main() { int num_students; struct student* arr = read_data(&num_students); if (!arr) return 1; serialize(arr, num_students); free_arr(arr, num_students); arr = deserialize(&num_students); print_arr(arr, num_students); return 0; }

22 תרגיל 3 - פתרון struct student* read_data(int *num_students) { printf("enter number of students\n"); scanf("%d", num_students); struct student* arr = malloc(sizeof(struct student)*(*num_students)); if (!arr) return NULL; memset(arr, 0, sizeof(struct student)*(*num_students)); for (int i = 0; i < (*num_students); i++) { arr[i].name = malloc(sizeof(char)*(MAX_LEN + 1)); if (arr[i].name == NULL) { free_arr(arr, *num_students); } printf("enter name id and average:\n"); scanf("%s%d%lf", arr[i].name, &arr[i].id, &arr[i].avg); return arr; {

23 תרגיל 3 - פתרון void serialize(struct student* arr, int n) { FILE* fid = fopen("students.txt", "w"); if (!fid) return 1; fprintf(fid, "%d\n", n); for (int i = 0; i < n; i++) { fprintf(fid, "%d ", strlen(arr[i].name)); fprintf(fid, "%s ", arr[i].name); fprintf(fid, "%d %f\n", arr[i].id, arr[i].avg); { fclose(fid); } void free_arr(struct student* arr, int n) { for (int i = 0; i < n; i++) free(arr[i].name); free(arr);

24 struct student. deserialize(int. n) { FILE. fid = fopen("students
struct student* deserialize(int* n) { FILE* fid = fopen("students.txt", "r"); if (!fid) return 1; fscanf(fid, "%d", n); struct student *arr = malloc(sizeof(struct student)*(*n)); if (!arr) return NULL; memset(arr, 0, sizeof(struct student)*(*n)); for (int i = 0; i < (*n); i++) { int name_len; fscanf(fid, "%d", &name_len); arr[i].name = malloc(sizeof(char)*(name_len + 1)); if (arr[i].name == NULL) { free_arr(arr, (*n)); } fscanf(fid, "%s %d %lf", arr[i].name, &arr[i].id, &arr[i].avg); fclose(fid); return arr; תרגיל 3 - פתרון

25 תרגיל 3 - פתרון void print_arr(struct student* arr, int n) { for (int i = 0; i < n; i++) { printf("%d. ", i+1); printf("%d %s %f\n", arr[i].id, arr[i].name, arr[i].avg); } {


הורד את "ppt "תירגול 10: מבנים (structs) וקבצים

מצגות קשורות


מודעות Google