תרגול מס' 3

23
ססססס סס' ססססס סס'3 3 ססססס ססססס ססססס סססססס ססססס סססססססס סססס- סס[email protected]

Upload: gale

Post on 02-Feb-2016

67 views

Category:

Documents


0 download

DESCRIPTION

תרגול מס' 3. מבנים בעייה לדוגמה. לי-טל משיח [email protected]. הקצאת זיכרון דינמית - תזכורת. void* malloc(unsigned nbytes) הקצאת קטע זיכרון בגודל nbytes . אם ההקצאה הצליחה, מוחזר מצביע לקטע הזה בזיכרון, אחרת מוחזר הערך NULL שחרור הזכרון שהוקצה באופן דינמי מתבצע ע"י free . - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: תרגול מס' 3

33תרגול מס' תרגול מס'

מבניםמבניםבעייה לדוגמהבעייה לדוגמה

[email protected]לי-טל משיח

Page 2: תרגול מס' 3

הקצאת זיכרון דינמית - תזכורתהקצאת זיכרון דינמית - תזכורתvoid* malloc(unsigned nbytes)void* malloc(unsigned nbytes)

הקצאת קטע זיכרון בגודלnbytes אם ההקצאה הצליחה, מוחזר מצביע .NULLלקטע הזה בזיכרון, אחרת מוחזר הערך

שחרור הזכרון שהוקצה באופן דינמי מתבצע ע"י freefree..voidvoid handle_error( handle_error(const charconst char* msg) {* msg) { fprintf(stderr,"ERROR: %s\n",msg);fprintf(stderr,"ERROR: %s\n",msg); exit (1);exit (1);}}

intint main() { main() { intint t , *p; t , *p; p = (p = (intint*) malloc(*) malloc(sizeofsizeof((intint));)); ifif ( p == NULL) ( p == NULL)

handle_error("out of memory") ;handle_error("out of memory") ; *p = 5; t = * p;*p = 5; t = * p; free (p);free (p);

returnreturn 0; 0;}}

Page 3: תרגול מס' 3

Structures Structures מבניםמבנים --דרך ליצור טיפוסים חדשים ע"י הרכבה מטיפוסים קיימים

structstruct <struct name> { <struct name> {<type name1> <field1>;<type name1> <field1>;<type name2> <field2>;<type name2> <field2>;....<type name<type namenn> <field> <fieldnn>;>;

};};:הגדרת משתנה נעשית ע"י

structstruct <struct name> <variable name>; <struct name> <variable name>; דוגמא - מבנה המגדיר טפוס תאריך. חודשים שמורים בפורמט של שלושה

תוויםstructstruct Date_t { Date_t { intint day; day; charchar[4] month; [4] month; /* why 4 chars? *//* why 4 chars? */ intint year; year;};};

הגדרת משתנה מסוגdate:structstruct Date_t d; Date_t d;

Page 4: תרגול מס' 3

Structures Structures מבניםמבנים -- פנייה לשדה בתוך משתנה מסוגstruct:נעשית ע"י

<variable name>.<field name>;<variable name>.<field name>;כאשר נתון מצביע לstruct-:ניתן לגשת לשדה בצורה ישירה ,

(*<pointer name>).<field name> ;(*<pointer name>).<field name> ;:מכיוון שדרך זו מסורבלת, קיימת דרך נוספת ופשוטה יותר לגשת לשדה

<pointer name> -> <field name> ;<pointer name> -> <field name> ;:דוגמא

structstruct Date_t* p; Date_t* p;p=&d;p=&d;p->day=12; p->day=12; /* or (*p).day=12; *//* or (*p).day=12; */

:תוכנית דוגמאintint main() { main() { structstruct Date_t dt , *pdt; Date_t dt , *pdt; dt.day = 21;dt.day = 21; strcpy(dt.month , "NOV");strcpy(dt.month , "NOV"); pdt = &dt ;pdt = &dt ; pdt->year = 1971 ;pdt->year = 1971 ; printf ("The year is %d\n",dt.year);printf ("The year is %d\n",dt.year);}}

Page 5: תרגול מס' 3

typedeftypedefשם נוסף לטיפוס באמצעותשם נוסף לטיפוס באמצעות בדוגמת התאריך נוצר טיפוס בשםstruct Date_t. בכדי להמנע מהצורך ברשוםstruct בכל פעם, ניתן להעזר ב typedef בכדי

לתת לטיפוס שנוצר שם קצר יותר::'דרך א':דרך א

structstruct Date_t { .... same as before } ; Date_t { .... same as before } ; typedef typedef struct Date_t Date ;struct Date_t Date ;

מעתה, השמותDate ו struct Date_tהם שמות שונים לאותו טיפוס :ניתן גם להגדיר טפוס של מצביע למבנה

typedeftypedef struct Date_t *pDate; struct Date_t *pDate; או

typedeftypedef Date *pDate; Date *pDate; :'דרך ב':דרך ב:ניתן לבצע את שני השלבים יחדיו

typedeftypedef struct Date_t { struct Date_t { intint day; day; charchar[4] month; [4] month; int int year;year;} Date;} Date;typedeftypedef Date *pDate; Date *pDate;

Page 6: תרגול מס' 3

שמוש במבנה בתוך מבנהשמוש במבנה בתוך מבנה ניתן להגדיר בתוךstruct שדה מטיפוס structאחר

typedeftypedef struct Date_t { struct Date_t { intint day; day; charchar month[4]; month[4]; intint year; year;} Date ;} Date ;typedeftypedef struct Person_t { struct Person_t { charchar* name;* name;

intint height; height; Date birth;Date birth;} Person ;} Person ;

-גישה לשדה של הstruct :הפנימי Person p ;Person p ;Person *pp=&p;Person *pp=&p;p.birth.year = 1994p.birth.year = 1994pp->birth.year = 1994;pp->birth.year = 1994;

מדוע לאpp->birth->year?

Page 7: תרגול מס' 3

שמוש במצביע למבנה בתוך מבנהשמוש במצביע למבנה בתוך מבנה במקום להגדיר אתbirthכשדה מטפוס date מצביע ניתן היה להגדירו כ

Date מטיפוס structל-typedeftypedef struct Date_t { struct Date_t { intint day; day; char char month[4];month[4]; intint year; year;} Date ;} Date ;typedeftypedef struct Person_t { struct Person_t { charchar* name;* name;

intint height; height; Date* birth; Date* birth; / * or sturct Date_t* birth; *// * or sturct Date_t* birth; */} Person ;} Person ;

-גישה לשדה של הstruct :הפנימי Person Person p ; p ;Person Person *pp=&p;*pp=&p;p.birth->year = 1994p.birth->year = 1994pp->birth->year = 1994;pp->birth->year = 1994;

שמו לב: כאשר הקצאנו אתp Person לא הקצנו כחלק ממנו מקום למבנה! כיצד אינו תקין לכן קטע הקוד הנתון אלא למצביע אליו !Dateמטיפוס

ניתן לתקנו?

Page 8: תרגול מס' 3

מבנים המתייחסים לעצמםמבנים המתייחסים לעצמם מטיפוס מצביע למבנה עצמו:מצביעיםמצביעיםבבהגדרת מבנה ניתן להשתמש

typedeftypedef struct Date_t { struct Date_t { intint day; day; charchar month[4]; month[4]; int int year;year; structstruct Date_t* next; Date_t* next;} Date ;} Date ;

:הדבר מאפשר לשמור את כתובתו של מבנה אחר מאותו טיפוס בתוך המבנהintint main() { main() {

Date dt1, dt2, *pdt ;Date dt1, dt2, *pdt ;dt1.day = 31 ; dt1.day = 31 ; strcpy(dt1.month,”DEC”);strcpy(dt1.month,”DEC”);dt1.year = 1992 ;dt1.year = 1992 ;

dt2.day = 1 ; dt2.day = 1 ; strcpy(dt2.month,”JAN”);strcpy(dt2.month,”JAN”);dt2.year = 1993 ;dt2.year = 1993 ;

pdt = &dt2;pdt = &dt2;dt1.next = &dt2; dt1.next = &dt2;

printf ("Year in dt1: %d\n",dt1.year);printf ("Year in dt1: %d\n",dt1.year); printf ("Year in dt2: %d\n",(dt1.next)->year);printf ("Year in dt2: %d\n",(dt1.next)->year);}}

Page 9: תרגול מס' 3

תמונת הזכרון לפני ביצוע פקודות תמונת הזכרון לפני ביצוע פקודות ההדפסהההדפסה

ניתן לשנות את ערכו של השדהyear של המשתנה dt2 בכמה

אופנים:

dt2.year = 1994;

pdtyear = 1994;

(dt1.next) year = 1994; רשימה מקושרתרשימה מקושרתנוצרה כאן

בת שני איברים מה צריך להיות ערכו של

כדי שנדע dt2 ב nextהשדה שאין איבר נוסף ?

pdt

31DEC1992

1JAN1993

?

dt1

dt2

Page 10: תרגול מס' 3

רשימה מקושרת של מבנים המוקצים רשימה מקושרת של מבנים המוקצים באופן דינמיבאופן דינמי

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

בסדר הפוך לסדר הקריאהבסדר הפוך לסדר הקריאה:פתרון:פתרון

רשימה מקושרת של תאריכיםרשימה מקושרת של תאריכים

Page 11: תרגול מס' 3

רשימה מקושרת של מבנים המוקצים רשימה מקושרת של מבנים המוקצים באופן דינמיבאופן דינמי

intint main() { main() { Date *top = NULL, *tmp = NULL ;Date *top = NULL, *tmp = NULL ; intint d,y ; d,y ;

charchar m[4]; m[4];while (scanf("%d %s %d", &d ,m , &y) != EOF){ while (scanf("%d %s %d", &d ,m , &y) != EOF){ /* is the check good /* is the check good

enough ? */ enough ? */ tmp = (Date*) malloc(tmp = (Date*) malloc(sizeofsizeof(Date));(Date)); if if (tmp == NULL) (tmp == NULL) free_list(top);free_list(top); tmp->day = d ;tmp->day = d ; strcpy(tmp->month ,m);strcpy(tmp->month ,m); tmp->year = y ;tmp->year = y ; tmp->next = top ;tmp->next = top ; top = tmp; top = tmp; }} while (tmp != NULL) {while (tmp != NULL) { printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year);printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year); tmp = tmp->next ;tmp = tmp->next ; }}

/* what should come here? *//* what should come here? */}}

Page 12: תרגול מס' 3

רשימה מקושרת של מבנים המוקצים רשימה מקושרת של מבנים המוקצים באופן דינמיבאופן דינמי

void free_list(Date *top){void free_list(Date *top){Date *tmp;Date *tmp;whilewhile (top != NULL) { (top != NULL) {

tmp=top;tmp=top;top=top->next;top=top->next;free(tmp);free(tmp);

} } } }

Page 13: תרגול מס' 3

העתקת מבנים בדרך פשוטה יותרהעתקת מבנים בדרך פשוטה יותרintint main() { main() { Date *top = NULL, *tmp = NULL ;Date *top = NULL, *tmp = NULL ; intint d,y ; d,y ;

charchar m[4]; m[4];while (scanf("%d %s %d", &d ,m , &y) != EOF){ while (scanf("%d %s %d", &d ,m , &y) != EOF){ /* is the check good /* is the check good

enough ? */ enough ? */ tmp = (Date*) malloc(tmp = (Date*) malloc(sizeofsizeof(Date));(Date)); if if (tmp == NULL) (tmp == NULL) free_list(top);free_list(top); tmp->day = d ;tmp->day = d ; strcpy(tmp->month ,m);strcpy(tmp->month ,m); tmp->year = y ;tmp->year = y ; tmp->next = top ;tmp->next = top ; top = tmp; top = tmp; }} while (tmp != NULL) {while (tmp != NULL) { printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year);printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year); tmp = tmp->next ;tmp = tmp->next ; }}

/* what should come here? *//* what should come here? */}}

intint main() { main() { Date *top = NULL, *tmp = NULL ;Date *top = NULL, *tmp = NULL ; Date dDate d;;

while (scanf("%d %s %d", while (scanf("%d %s %d", &d.day ,d.mon , &d.year&d.day ,d.mon , &d.year) == 3){) == 3){

tmp = (Date*) malloc(tmp = (Date*) malloc(sizeofsizeof(Date));(Date)); if if (tmp == NULL) (tmp == NULL) free_list(top);free_list(top); *tmp=d ;*tmp=d ;

tmp->next = top ;tmp->next = top ; top = tmp; top = tmp; }} while (tmp != NULL) {while (tmp != NULL) { printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year);printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year); tmp = tmp->next ;tmp = tmp->next ; }}

free_list(top);free_list(top);return 0;return 0;

}}

Page 14: תרגול מס' 3

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

קרו בתאריך מסויים. התוכנית תקרא קובץ המכיל ארועים הסטוריים, לאחר מכן תקלוט תאריכים ועבור כל אחד מהם תגיד אילו אירועים היסטוריים

מאלו שבקובץ קרו באותו התאריך קובץ ארועיםevents:

1 1 JAN 404 Last gladiator competition JAN 404 Last gladiator competition 6 6 MAYMAY 1889 Eiffel tower completed1889 Eiffel tower completed21 21 NOV 1794 Honolulu harbor discoveredNOV 1794 Honolulu harbor discovered1 1 JAN 1852 First public bath in NYJAN 1852 First public bath in NY1 1 JAN 379 King basilius the great bornJAN 379 King basilius the great born21 21 NOV 1971 First tackoff of theconcordeNOV 1971 First tackoff of theconcorde6 6 MAYMAY 1915 Orson Welles born1915 Orson Welles born6 6 MAY 1626 Manahatan purchused for 24$MAY 1626 Manahatan purchused for 24$21 21 NOV 1971 First landing of the concordeNOV 1971 First landing of the concorde

:הפעלת התוכנית והפלט המתקבל% important_dates events% important_dates eventsenter date: enter date: 21 NOV 197121 NOV 1971First takeoff of the concordeFirst takeoff of the concordeFirst landing of the concordeFirst landing of the concordeenter date: enter date: 23 NOV 199923 NOV 1999Nothing specialNothing special

Page 15: תרגול מס' 3

::פתרון אפשריפתרון אפשרינשמור רשימה מקושרת של תאריכים

לכל תאריך נשמור רשימה של ארועים שקרו בתאריך זה

date

events list

next

date

events list

next

Historical Date

date

events list

next

next

next

next

next

event

description

description

description

description

hist

Page 16: תרגול מס' 3

::מיבניםמיבניםהגדרות

#define#define MAX 100 MAX 100 /* Max line lenth*//* Max line lenth*/מבנה תאריך

typedeftypedef struct Date_t { struct Date_t { intint day; day; charchar[4] month; [4] month; intint year; year;} Date;} Date;

מבנה אירוע typedeftypedef struct Event_t { struct Event_t { charchar* desc ;* desc ;

structstruct Event_t *next; Event_t *next;} Event;} Event;

מבנה תאריך הסטורי typedeftypedef struct HistoricalDate_t { struct HistoricalDate_t { Date dt ;Date dt ;

Event *events_list;Event *events_list;struct HistoricalDate_t *next ;struct HistoricalDate_t *next ;

} HistoricalDate;} HistoricalDate;

Page 17: תרגול מס' 3

פונקציות עזר – טיפול בקלטפונקציות עזר – טיפול בקלטקריאת תאריך מערוץ קלט נתון (הקצאת התאריך באחריות הקורא !)

intint getDate(FILE* fd, Date* dt) { getDate(FILE* fd, Date* dt) {

ifif (dt == NULL) (dt == NULL) return 0 ;return 0 ;

ifif (fscanf (fd, “%d %s %d ”, &(dt->day),dt->month, &(dt->year))==3) (fscanf (fd, “%d %s %d ”, &(dt->day),dt->month, &(dt->year))==3) returnreturn 1; 1; returnreturn 0; 0; }}

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

intint getEvent(FILE* fd, Date* dat, char* bf) { getEvent(FILE* fd, Date* dat, char* bf) { ifif (dat == NULL || bf == NULL) (dat == NULL || bf == NULL) returnreturn 0 ; 0 ;

ifif (getDate(fd,dat) ==0 || fgets(bf, MAX, fd)==NULL) (getDate(fd,dat) ==0 || fgets(bf, MAX, fd)==NULL)returnreturn 0; 0;

returnreturn 1; 1;}}

Page 18: תרגול מס' 3

פונקציות עזר – הקצאת צמתים פונקציות עזר – הקצאת צמתים ואתחולםואתחולם

הקצאת צומת ארוע הסטוריEvent* allocEvent(Event* allocEvent(charchar* ev) { * ev) {

Event *new_event;Event *new_event;

ifif (ev == NULL) (ev == NULL)

returnreturn NULL ; NULL ;

new_event=(Event*)malloc(new_event=(Event*)malloc(sizeofsizeof(Event));(Event));

ifif (new_event== NULL) (new_event== NULL)

returnreturn NULL; NULL;

new_event->desc=(char*)malloc(strlen(ev)+1);new_event->desc=(char*)malloc(strlen(ev)+1);

if if (new_event->desc == NULL) {(new_event->desc == NULL) {

free (new_event) ;free (new_event) ;

returnreturn NULL; NULL;

}}

strcpy(new_event->desc,ev);strcpy(new_event->desc,ev);

new_event->next = NULL ;new_event->next = NULL ;

returnreturn new_event ; new_event ;

}}

Page 19: תרגול מס' 3

פונקציות עזר – הקצאת צמתים פונקציות עזר – הקצאת צמתים ואתחולםואתחולם

הקצאת צומת תאריך הסטוריHistoricalDate* allocHistoriaclDate(Date dt) { HistoricalDate* allocHistoriaclDate(Date dt) {

HistoricalDate *new_hdate;HistoricalDate *new_hdate;

new_hdate=(HistoricalDate*) malloc(sizeof(HistoricalDate));new_hdate=(HistoricalDate*) malloc(sizeof(HistoricalDate));

if if (new_hdate == NULL) (new_hdate == NULL)

returnreturn NULL ; NULL ;

new_hdate ->dt = dt ;new_hdate ->dt = dt ;

new_hdate ->events_list = NULL;new_hdate ->events_list = NULL;

new_hdate ->next = NULL ;new_hdate ->next = NULL ;

returnreturn new_hdate ; new_hdate ;

} }

Page 20: תרגול מס' 3

פונקציות עזר – טיפול במבנה הנתוניםפונקציות עזר – טיפול במבנה הנתונים מציאת תאריך הסטורי ברשימת תאריכים

HistoricalDate* find(HistoricalDate* first,Date dt){HistoricalDate* find(HistoricalDate* first,Date dt){ ifif (first == NULL) (first == NULL)

return NULL ;return NULL ; ifif (first->dt.day == dt.day && (first->dt.day == dt.day &&

strcmp(first->dt.month,dt.month) == 0 && strcmp(first->dt.month,dt.month) == 0 && first->year == dt.year) first->year == dt.year)

returnreturn first ; first ; returnreturn find(first->next,dt); find(first->next,dt); }}

הדפסת רשימת ארועים הסטוריים:voidvoid printEvents(Event* ev) { printEvents(Event* ev) {

ifif ( ev == NULL ) ( ev == NULL ) returnreturn;;

printf (“%s\n”, ev->desc);printf (“%s\n”, ev->desc); printEvents(ev->next);printEvents(ev->next);

}}

Page 21: תרגול מס' 3

פונקציות עזר – טיפול במבנה הנתוניםפונקציות עזר – טיפול במבנה הנתוניםבניית מבנה הנתונים

HistoricalDate* readEvents(FILE* fd) {HistoricalDate* readEvents(FILE* fd) {charchar buff[MAX]; buff[MAX]; Date dt ;Date dt ;HistoricalDate *first=NULL , *cur = NULL; HistoricalDate *first=NULL , *cur = NULL; Event *ev =NULL;Event *ev =NULL;whilewhile (getEvent(fd,&dt,buff)) { (getEvent(fd,&dt,buff)) {cur = find(first,dt) ;cur = find(first,dt) ;ifif (cur == NULL) { (cur == NULL) { /* incase the date doesn't exist, add this date to be the /* incase the date doesn't exist, add this date to be the first in the list */ first in the list */cur = allocHistoricalDate(dt); cur = allocHistoricalDate(dt); if if (cur == NULL)(cur == NULL)returnreturn NULL ; NULL ;cur->next = first ;cur->next = first ;first = cur ;first = cur ;}}ev = allocEvent(buff);ev = allocEvent(buff);if if (ev == NULL) (ev == NULL) returnreturn NULL ; NULL ;ev->next = cur->events_list;ev->next = cur->events_list;cur->events_list = ev ;cur->events_list = ev ;}}return return first ;first ;

}}

Page 22: תרגול מס' 3

התוכנית הראשיתהתוכנית הראשיתintint main( main(intint argc, argc, charchar* argv[]) {* argv[]) {

FILE* ifd = NULL;FILE* ifd = NULL;

HistoricalDate* hist = NULL , *cur = NULL;HistoricalDate* hist = NULL , *cur = NULL;

Date dt ;Date dt ;

if if (argc != 2) (argc != 2)

returnreturn 1 ; 1 ;

ifif ((ifd = fopen(argv[1],”r”))==NULL) ((ifd = fopen(argv[1],”r”))==NULL)

returnreturn 2 ; 2 ;

hist = readEvents(ifd); hist = readEvents(ifd); /*creating the database*//*creating the database*/

fclose(ifd);fclose(ifd);

ifif (hist == NULL) (hist == NULL)

returnreturn 3 ; 3 ;

while while (getDate(stdin,&dt)) {(getDate(stdin,&dt)) {

cur = find(hist,dt) ;cur = find(hist,dt) ;

if if (cur == NULL) (cur == NULL)

printf (“Nothing special\n”);printf (“Nothing special\n”);

else else

printEvents(cur->events_list);printEvents(cur->events_list);

}}

returnreturn 0; 0;

}}

Page 23: תרגול מס' 3

שיפורים אפשרייםשיפורים אפשריים

.שחרור הזכרון בסוף התוכנית.שחרור הזכרון בסוף התוכנית שחרור הזכרון שכבר הוקצה במידה וקרה כשלון במהלך ריצת שחרור הזכרון שכבר הוקצה במידה וקרה כשלון במהלך ריצת

..readEventsreadEventsהפונקציה הפונקציה .הודעות שגיאה ברורות למשתמש. הודעות שגיאה ברורות למשתמש