220 likes | 495 Views
תכנות בשפת C תרגול 9 typedef, struct, רשימות מקושרות. typedef אופרטור ה-. ניתן להגדיר טיפוס חדש על ידי פקודת typedef שתבניתה היא: typedef existing_type new_type ; המהדר יחליף את הטיפוס existing_type בטיפוס החדש new_type . לדוגמה: typedef int* pint; pint p,q; int* r; r = p;
E N D
תכנות בשפת C תרגול 9 typedef, struct, רשימות מקושרות
typedefאופרטור ה- • ניתן להגדיר טיפוס חדש על ידי פקודת typedef שתבניתה היא: typedef existing_type new_type ; • המהדר יחליף את הטיפוסexisting_type בטיפוס החדש new_type. לדוגמה: typedef int* pint; pint p,q; int* r; r = p; • השימוש ב-typedef מאפשר להפוך את הקוד לקריא יותר מבחינת ההקשר.
struct- מבנה • טיפוס המאגד עצמים מטיפוסים שונים (או זהים) בתוך רשומה אחת. תחביר: • struct name_of_struct { field1; field2; etc.}; • דומה למערך בכך ששניהם יכולים לאגד מספר נתונים , אך במבנה יש חופש בבחירת טיפוסי הנתונים: • struct address{ char city[20]; char street[20]; int num_house; long code_area;}; אין מניעה שאחד השדות יהיה בעצמו מבנה
תחבירstruct • ע"מ להכריז על משתנה מסוג מבנהaddress יש לכתוב: struct address x; • איתחול: struct address add = {"migdal Haemek", "Harazim", 5, 23028}; • ניתן להשתמש ב- typedef כדי להקל על שימוש ב- struct : typedef struct some_name {char alias[20];char username [20];char password[10];int numberOfFriends; } facebook_record; אפשר להחליף כל מופע של facebook_recordבקוד ב- struct some_name , ולהיפך
תחבירstruct(המשך) • דרך אחרת: struct some_name {char alias[20];char username [20];char password[10]; int numberOfFriends; }; typedef struct some_name facebook_record; • struct ניתן לשימוש כפרמטר לפו' או כערך החזרה של פו', ממש כמו כל טיפוס אחר. • ניתן להגדיר מצביע למבנה: facebook_record* p;ניתן להגדיר מערך של רשומות: facebook_record records[10];
גישה לשדות ב- struct • כדי לגשת לשדות, קיימים שני אופרטורים: נקודה (.) וחץ (->) . • אופרטור הנקודה מאפשר גישה לשדות בתוך משתנה מטיפוס המבנה. facebook_record d; strcpy(d.username, “david hasholet”); d.numberOfFriends = 501; • אופרטור החץ מאפשר גישה לשדות בתוך משתנה מטיפוס מצביע למבנה. facebook_record* d = (facebook_record*)malloc( sizeof(facebook_record) ); strcpy(d->username, “david hasholet”); d->numberOfFriends = 501; • שימו לב ש: d->numberOfFriends = 501; שקול ל-(*d).numberoffriends=501;
תחבירstruct(המשך) • מבנה מקונן:שדות המבנה יכולים להיות בעצמם מבנה לדוגמא: struct address { char city[15]; char street[15]; }; struct citizen{ struct address add; long id; }; • נניח כי אנו מצהירים על משתנה מסוג citizen: struct citizen ctzn; • כדי לגשת לשדה id נרשום: ctzn.id • כדי לגשת לשדה city נרשום ctzn.add.city – כלומר, ראשית ניגש לשדה add שהוא גם מטיפוס מבנה וממנו ניגש לשדות שלו שוב על ידי אופרטור הנקודה. • הערה: ניתן לבנות מבנים בעלי קינון מדרגה גבוהה יותר (כלומר שדה של שדה של מבנה וכו').
תרגיל 1 • להלן הגדרה עבור מבנה המממש מערך דינאמי שניתן להוסיף לו מס' בלתי מוגבל של ערכים: typedef struct dyn { int *data; int len; int used; } DynArr; • נתונה פונקציה void dynamicInsert(DynArr* arr, int val)שמכניסה מספר שלם למקום הפנוי הבא במערך. • אם המערך מלא, הפונקציה "מכפילה" פי 2 את גודל המערךומוסיפה את הערך החדש, תוך שמירה על הערכים הישנים. המערך מוצבע ע"י השדה dataהשדה len הוא אורך המערךused הוא אינדקס התא האחרון שבשימוש
תרגיל 1 (המשך) voiddynamicInsert(DynArr* arr, intval) { int *newarr; inti; if (?? 1 ??) { newarr = ?? 2 ??; for (i=0; i <= arr->used ; i++) ?? 3 ??; free(?? 4 ??); arr->data = ?? 5 ??; arr->len = ?? 6 ??; { arr->data[?? 7 ??] = val; } typedefstruct dyn { int *data;int len; int used; } DynArr;
תרגיל 1 (פתרון) void dynamicInsert(DynArr* arr, int val) { int *newarr; int i; if (arr->len-1 <= arr->used) { newarr = (int *)malloc(2*(arr->len)*sizeof(int)); for (i=0; i <= arr->used ; i++) newarr[i]=arr->data[i]; free(arr->data); arr->data = newarr; arr->len = 2*(arr->len); } arr->data[++(arr->used)] = val; } typedefstruct dyn { int *data;int len; int used; } DynArr;
תרגיל 1 (שימוש בפתרון) void main() { DynArr a; inti=0; a.len=4; a.used=3; if(!(a.data=(int *)malloc(4*sizeof(int)))){ printf("Problem allocating memory, please try again!!!\n"); return; } for(;i<=a.used;++i)//Fill the array with the sqare of the indices: *(a.data+i)=i*i; printf("Array BEFORE dynamic insertion:\n"); for(i=0;i<=a.used;++i)//Print the array before dynamic insertion: printf("%d\t",a.data[i]); printf("\n"); typedefstruct dyn { int *data;int len; int used; } DynArr;
תרגיל 1 (שימוש בפתרון - המשך) dynamicInsert(&a, 16); printf("Array AFTER dynamic insertion:\n"); for(i=0;i<=a.used;++i) //Print the array after dynamic insertion: printf("%d\t",a.data[i]); printf("\n"); free(a.data); } typedefstruct dyn { int *data;int len; int used; } DynArr;
תרגיל 2 (א) struct record { char name[20]; intserial_num; }; void readRecord(struct record r) { scanf("%s", r.name); scanf("%d", &r.serial_num); } void main() { struct record r; r.serial_num = 123; strcpy(r.name, "abc"); readRecord(r); printf("name: %s, serial: %d\n",r.name, r.serial_num); } מה תדפיס התוכנית הבאה ? name: abc, serial: 123
תרגיל 2 (ב) struct record { char name[20]; int serial_num; }; void readRecord(struct record *r) { scanf("%s", r->name); scanf("%d", &(r->serial_num)); } void main() { record r; readRecord(&r); printf("name: %s, serial: %d\n",r.name, r.serial_num); } מה תדפיס התוכנית הבאה ? מה שיוזן כקלט על ידי המשתמש
רשימה מקושרת – הגדרה ותכונות • רשימה מקושרת – שרשרת של רשומות. כל רשומה מכילה מצביע לרשומה הבאה או NULL (עבור הרשומה האחרונה). • בניגוד למערך, אין גישה מיידית לכל איבר, אלא על-ידי סריקה של הרשימה עד שמגיעים לאיבר המבוקש; היתרון לעומת מערך – הוספה ומחיקה יעילה של איברים. • לדוגמה: structdbase_rec { char *record; /* --> data field */ structdbase_rec *next; /* --> next field */ }; typedefstructdbase_rec dbase; • בדרך כלל מגדירים פונקציות להוספה, מחיקה וסריקה של רשימה בהתאם לצרכי המתכנת.
שאלה 1 • להלן הגדרה: typedefstruct node { int val; struct node *next; } node; • עבור רשימה משורשרת השלם את החלק החסר בקוד הבא כך שהפונקציה תשאיר מהרשימה רק את החוליות שבונות רשימה בסדר עולה ממש (לפי השדה val). • לדוגמה, אחרי הקריאה ל- void upper_list(node* first) הרשימה העליונה תהפוך לתחתונה:
שאלה 1 (המשך) • השלימו את קטע הקוד הבא: void upper_list(node* first){ node *temp; if( ?? 1 ?? ) return; while(?? 2 ??){ if( ?? 3 ??>= ?? 4 ??){ temp = ?? 5 ??; ?? 6 ?? ; free(temp) ; } else ?? 7 ?? ; } }
שאלה 1 (פתרון) voidupper_list(node* first) { node *temp; if( !first ) return; while(first->next){ if( first->val>=first->next->val){ temp = first->next; first->next=first->next->next ; free(temp) ; } else first=first->next; } }
שאלה 2 • בהתיחס להגדרת הצומת משאלה מס' 1, השלם את החלק החסר בקוד הבא כך שהפונקציה תשכפל כל צומת מס' פעמים השווה לערכו של משתנה ה- val שלו ואז תוסיף את הצמתים החדשים לרשימה ישר אחרי הצומת ממנו הם שוכפלו. void multiply(node* head){ node *temp; inti; while(head) { temp = head -> next; for(i=0; i< ?? 1 ??; i++) { head->next = ?? 2 ?? ; ?? 3 ?? = head -> val; head = ?? 4 ?? ; } ?? 5 ?? = ?? 6 ?? ; head = ?? 7 ??; } } לדוגמה, אחרי הביצוע של הפונקציה הנ"ל הרשימה העליונה תהפוך לתחתונה:
שאלה 2 (פתרון) void multiply(node* head) { node *temp; inti; while(head) { temp = head -> next; for(i=0;i<head->val-1; i++) { head->next = (node*)malloc(sizeof(node)); head->next->val = head -> val; head = head->next ; } head->next = temp ; head = temp; } }
שאלה 3 בהתייחס להגדרת הצומת משאלה מס' 1, השלם את החלק החסר בקוד הבא כך שהפונקציה תמחק את כל המופעים הכפולים של ערכים ברשימה מקושרת ממוינת (ותשאיר רק אחד מהם). void trim(node* lst){ node *aux; while( ?? 1 ?? && ?? 2 ??){ if(lst->val == ?? 3 ??){ aux = ?? 4 ?? ; lst->next = ?? 5 ?? ; free( ?? 6 ?? ); } else lst = ?? 7 ?? ; } }
שאלה 3 (פתרון) void trim(node* lst) { node *aux; while(lst!=NULL && lst->next!=NULL){ if(lst->val == lst->next->val){ aux = lst->next ; lst->next = lst->next->next ; free(aux); } else lst = lst->next ; } }