תרגול מס' 3
Download
1 / 23

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


  • 135 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

תרגול מס' 3

מבנים

בעייה לדוגמה

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


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

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 name> {

    <type name1> <field1>;

    <type name2> <field2>;

    .

    .

    <type namen> <fieldn>;

    };

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

    struct <struct name> <variable name>;

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

    struct Date_t {

    int day;

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

    int year;

    };

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

    struct Date_t d;


Structures1
Structures מבנים -

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

    <variable name>.<field name>;

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

    (*<pointer name>).<field name> ;

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

    <pointer name> -> <field name> ;

  • דוגמא:

    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;


שמוש במבנה בתוך מבנה

  • ניתן להגדיר בתוך 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 ?


שמוש במצביע למבנה בתוך מבנה

  • במקום להגדיר את 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 אלא למצביע אליו ! לכן קטע הקוד הנתון אינו תקין! כיצד ניתן לתקנו?


מבנים המתייחסים לעצמם

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

    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);

    }


dt1

31

DEC

1992

dt2

1

JAN

1993

?

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

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

    dt2.year = 1994;

    pdtyear = 1994;

    (dt1.next) year = 1994;

  • נוצרה כאן רשימה מקושרתבת שני איברים

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

pdt


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

  • הבעיה:

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

  • פתרון:

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


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

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? */

}


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

void free_list(Date *top){

Date *tmp;

while (top != NULL) {

tmp=top;

top=top->next;

free(tmp);

}

}


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

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? */

}


דוגמה נוספת לשימוש במבנים ומצביעים

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

    • קובץ ארועים 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


next ומצביעים

next

next

next

description

description

description

description

Historical Date

date

events list

next

פתרון אפשרי:

hist

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

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

event

date

events list

next

date

events list

next


מיבנים: ומצביעים

הגדרות

#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;


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

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

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;

}


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

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

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 ;

}


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

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

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 ;

}


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

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

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);

}


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

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

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 ;

}


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

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;

}


שיפורים אפשריים הנתונים

  • שחרור הזכרון בסוף התוכנית.

  • שחרור הזכרון שכבר הוקצה במידה וקרה כשלון במהלך ריצת הפונקציה readEvents.

  • הודעות שגיאה ברורות למשתמש.


ad