slide1
Download
Skip this Video
Download Presentation
תרגול מס' 3

Loading in 2 Seconds...

play fullscreen
1 / 23

תרגול מס' 3 - PowerPoint PPT Presentation


  • 141 Views
  • Uploaded on

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

loader
I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.
capcha
Download Presentation

PowerPoint Slideshow about 'תרגול מס' 3' - gale


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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript
slide1

תרגול מס' 3

מבנים

בעייה לדוגמה

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

slide2
הקצאת זיכרון דינמית - תזכורת

void* malloc(unsigned nbytes)

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

void handle_error(const char* msg) {

fprintf(stderr,"ERROR: %s\n",msg);

exit (1);

}

int main() {

int t , *p;

p = (int*) malloc(sizeof(int));

if ( p == NULL)

handle_error("out of memory") ;

*p = 5; t = * p;

free (p);

return 0;

}

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

struct {

;

;

.

.

;

};

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

struct ;

  • דוגמא - מבנה המגדיר טפוס תאריך. חודשים שמורים בפורמט של שלושה תווים

struct Date_t {

int day;

char[4] month; /* why 4 chars? */

int year;

};

  • הגדרת משתנה מסוג date:

struct Date_t d;

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

.;

  • כאשר נתון מצביע לstruct-, ניתן לגשת לשדה בצורה ישירה:

(*). ;

  • מכיוון שדרך זו מסורבלת, קיימת דרך נוספת ופשוטה יותר לגשת לשדה:

-> ;

  • דוגמא:

struct Date_t* p;

p=&d;

p->day=12; /* or (*p).day=12; */

  • תוכנית דוגמא:

int main() {

struct Date_t dt , *pdt;

dt.day = 21;

strcpy(dt.month , "NOV");

pdt = &dt ;

pdt->year = 1971 ;

printf ("The year is %d\n",dt.year);

}

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

struct Date_t { .... same as before } ;

typedef struct Date_t Date ;

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

typedef struct Date_t *pDate;

  • או

typedef Date *pDate;

  • דרך ב':
  • ניתן לבצע את שני השלבים יחדיו:

typedef struct Date_t {

int day;

char[4] month;

int year;

} Date;

typedef Date *pDate;

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

typedef struct Date_t {

int day;

char month[4];

int year;

} Date ;

typedef struct Person_t {

char* name;

int height;

Date birth;

} Person ;

  • גישה לשדה של ה-struct הפנימי:

Person p ;

Person *pp=&p;

p.birth.year = 1994

pp->birth.year = 1994;

  • מדוע לא pp->birth->year ?
slide7
שמוש במצביע למבנה בתוך מבנה
  • במקום להגדיר את birth כשדה מטפוסdate ניתן היה להגדירו כמצביעל-struct מטיפוס Date

typedef struct Date_t {

int day;

char month[4];

int year;

} Date ;

typedef struct Person_t {

char* name;

int height;

Date* birth; / * or sturct Date_t* birth; */

} Person ;

  • גישה לשדה של ה-struct הפנימי:

Person p ;

Person *pp=&p;

p.birth->year = 1994

pp->birth->year = 1994;

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

typedef struct Date_t {

int day;

char month[4];

int year;

struct Date_t* next;

} Date ;

  • הדבר מאפשר לשמור את כתובתו של מבנה אחר מאותו טיפוס בתוך המבנה:

int main() {

Date dt1, dt2, *pdt ;

dt1.day = 31 ;

strcpy(dt1.month,”DEC”);

dt1.year = 1992 ;

dt2.day = 1 ;

strcpy(dt2.month,”JAN”);

dt2.year = 1993 ;

pdt = &dt2;

dt1.next = &dt2;

printf ("Year in dt1: %d\n",dt1.year);

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

}

slide9
dt1

31

DEC

1992

dt2

1

JAN

1993

?

תמונת הזכרון לפני ביצוע פקודות ההדפסה
  • ניתן לשנות את ערכו של השדה year של המשתנה dt2 בכמה אופנים:

dt2.year = 1994;

pdtyear = 1994;

(dt1.next) year = 1994;

  • נוצרה כאן רשימה מקושרתבת שני איברים
  • מה צריך להיות ערכו של השדה next ב dt2 כדי שנדע שאין איבר נוסף ?

pdt

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

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

  • פתרון:

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

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

int main() {

Date *top = NULL, *tmp = NULL ;

int d,y ;

char m[4];

while (scanf("%d %s %d", &d ,m , &y) != EOF){ /* is the check good enough ? */

tmp = (Date*) malloc(sizeof(Date));

if (tmp == NULL)

free_list(top);

tmp->day = d ;

strcpy(tmp->month ,m);

tmp->year = y ;

tmp->next = top ;

top = tmp;

}

while (tmp != NULL) {

printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year);

tmp = tmp->next ;

}

/* what should come here? */

}

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

void free_list(Date *top){

Date *tmp;

while (top != NULL) {

tmp=top;

top=top->next;

free(tmp);

}

}

slide13
העתקת מבנים בדרך פשוטה יותר

int main() {

Date *top = NULL, *tmp = NULL ;

Date d;

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

tmp = (Date*) malloc(sizeof(Date));

if (tmp == NULL)

free_list(top);

*tmp=d ;

tmp->next = top ;

top = tmp;

}

while (tmp != NULL) {

printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year);

tmp = tmp->next ;

}

free_list(top);

return 0;

}

int main() {

Date *top = NULL, *tmp = NULL ;

int d,y ;

char m[4];

while (scanf("%d %s %d", &d ,m , &y) != EOF){ /* is the check good enough ? */

tmp = (Date*) malloc(sizeof(Date));

if (tmp == NULL)

free_list(top);

tmp->day = d ;

strcpy(tmp->month ,m);

tmp->year = y ;

tmp->next = top ;

top = tmp;

}

while (tmp != NULL) {

printf("%d %s %d\n",tmp->day, tmp->mon, tmp->year);

tmp = tmp->next ;

}

/* what should come here? */

}

slide14
דוגמה נוספת לשימוש במבנים ומצביעים
  • הבעיה: ברצוננו לכתוב תוכנית המחזירה את האירועים ההסטוריים אשר קרו בתאריך מסויים. התוכנית תקרא קובץ המכיל ארועים הסטוריים, לאחר מכן תקלוט תאריכים ועבור כל אחד מהם תגיד אילו אירועים היסטוריים מאלו שבקובץ קרו באותו התאריך
    • קובץ ארועים events:

1 JAN 404 Last gladiator competition

6 MAY 1889 Eiffel tower completed

21 NOV 1794 Honolulu harbor discovered

1 JAN 1852 First public bath in NY

1 JAN 379 King basilius the great born

21 NOV 1971 First tackoff of theconcorde

6 MAY 1915 Orson Welles born

6 MAY 1626 Manahatan purchused for 24$

21 NOV 1971 First landing of the concorde

    • הפעלת התוכנית והפלט המתקבל:

% important_dates events

enter date: 21 NOV 1971

First takeoff of the concorde

First landing of the concorde

enter date: 23 NOV 1999

Nothing special

slide15
next

next

next

next

description

description

description

description

Historical Date

date

events list

next

פתרון אפשרי:

hist

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

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

event

date

events list

next

date

events list

next

slide16
מיבנים:

הגדרות

#define MAX 100 /* Max line lenth*/

מבנה תאריך

typedef struct Date_t {

int day;

char[4] month;

int year;

} Date;

מבנה אירוע

typedef struct Event_t {

char* desc ;

struct Event_t *next;

} Event;

מבנה תאריך הסטורי

typedef struct HistoricalDate_t {

Date dt ;

Event *events_list;

struct HistoricalDate_t *next ;

} HistoricalDate;

slide17
פונקציות עזר – טיפול בקלט

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

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

if (dt == NULL)

return 0 ;

if (fscanf (fd, “%d %s %d ”, &(dt->day),dt->month, &(dt->year))==3)

return 1;

return 0;

}

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

int getEvent(FILE* fd, Date* dat, char* bf) {

if (dat == NULL || bf == NULL)

return 0 ;

if (getDate(fd,dat) ==0 || fgets(bf, MAX, fd)==NULL)

return 0;

return 1;

}

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

הקצאת צומת ארוע הסטורי

Event* allocEvent(char* ev) {

Event *new_event;

if (ev == NULL)

return NULL ;

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

if (new_event== NULL)

return NULL;

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

if (new_event->desc == NULL) {

free (new_event) ;

return NULL;

}

strcpy(new_event->desc,ev);

new_event->next = NULL ;

return new_event ;

}

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

הקצאת צומת תאריך הסטורי

HistoricalDate* allocHistoriaclDate(Date dt) {

HistoricalDate *new_hdate;

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

if (new_hdate == NULL)

return NULL ;

new_hdate ->dt = dt ;

new_hdate ->events_list = NULL;

new_hdate ->next = NULL ;

return new_hdate ;

}

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

מציאת תאריך הסטורי ברשימת תאריכים

HistoricalDate* find(HistoricalDate* first,Date dt){

if (first == NULL)

return NULL ;

if (first->dt.day == dt.day &&

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

first->year == dt.year)

return first ;

return find(first->next,dt);

}

הדפסת רשימת ארועים הסטוריים:

void printEvents(Event* ev) {

if ( ev == NULL )

return;

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

printEvents(ev->next);

}

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

בניית מבנה הנתונים

HistoricalDate* readEvents(FILE* fd) {

char buff[MAX];

Date dt ;

HistoricalDate *first=NULL , *cur = NULL;

Event *ev =NULL;

while (getEvent(fd,&dt,buff)) {

cur = find(first,dt) ;

if (cur == NULL) { /* incase the date doesn't exist, add this date to be the first in the list */

cur = allocHistoricalDate(dt);

if (cur == NULL)

return NULL ;

cur->next = first ;

first = cur ;

}

ev = allocEvent(buff);

if (ev == NULL) return NULL ;

ev->next = cur->events_list;

cur->events_list = ev ;

}return first ;

}

slide22
התוכנית הראשית

int main(int argc, char* argv[]) {

FILE* ifd = NULL;

HistoricalDate* hist = NULL , *cur = NULL;

Date dt ;

if (argc != 2)

return 1 ;

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

return 2 ;

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

fclose(ifd);

if (hist == NULL)

return 3 ;

while (getDate(stdin,&dt)) {

cur = find(hist,dt) ;

if (cur == NULL)

printf (“Nothing special\n”);

else

printEvents(cur->events_list);

}

return 0;

}

slide23
שיפורים אפשריים
  • שחרור הזכרון בסוף התוכנית.
  • שחרור הזכרון שכבר הוקצה במידה וקרה כשלון במהלך ריצת הפונקציה readEvents.
  • הודעות שגיאה ברורות למשתמש.
ad