Presentation is loading. Please wait.

Presentation is loading. Please wait.

מבנים קרן כליף. ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים.

Similar presentations


Presentation on theme: "מבנים קרן כליף. ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים."— Presentation transcript:

1 מבנים קרן כליף

2 ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים  גודל מבנה בזיכרון 2 © Keren Kalif

3 מבנה (struct) - מוטיבציה  אם נרצה לשמור בתוכנית שלנו 3 תאריכים, נצטרך להגדיר 9 משתנים : int day1, month1, year1, day2, month2…  אם היינו רוצים מערך שיכיל אוסף של תאריכים, כנראה שהיינו מגדירים 3 מערכים, כאשר הראשון היה מחזיק את הימים, השני את החודשים והשלישי את השנים  כדי להעביר נתוני חודש לפונקציה, צריך להעביר 3 פרמטרים..  היינו רוצים להמציא טיפוס חדש שיכיל את כל הנתונים של תאריך. לטיפוס זה יהיו 3 שדות : יום, חודש ושנה  טיפוס חדש שאנחנו יוצרים נקרא " מבנה " (struct) 3 © Keren Kalif

4 מבנה - דוגמא struct Date { int day; int month; int year; };}; void main() { Date d; d.day = 23; d.month = 8; d.year = 2008; cout << "The date is " << d.day << "/" << d.month << "/" << d.year << endl; } Date: d.day ??? 1000 d.month ??? d.year ??? Date: d.day 23 1000 d.month ??? d.year ??? Date: d.day 23 1000 d.month 8 d.year ??? Date: d.day 23 1000 d.month 8 d.year 2008 שם הטיפוס החדש 4 © Keren Kalif הגדרת מבנה המכיל אוסף של שדות הגדרת משתנה מטיפוס המבנה פניה לשדות המשתנה יהיה באמצעות נקודה

5 מבנה - תחביר  כדי לייצר מבנה חדש נגדיר אותו בתחילת הקובץ ( לפני ההצהרות על הפונקציות ) struct { ; };  פנייה לשדה של משתנה של מבנה היא ע " י. 5 © Keren Kalif

6 איתחול מבנה  ניתן לאתחל מבנה בשורת ההגדרה כמו שמאתחלים מערך : void main() { Date d= {23, 8, 2003}; cout << "The date is " << d.day << "/" << d.month << "/”<< d.year << endl; }  הערך הראשון יושם בשדה הראשון, הערך השני בשדה השני וכו '  יש לוודא התאמה בין טיפוס השדה לערך  השמת ערכים שלא בשורת ההגדרה ניתן לבצע רק שדה - שדה ע " י השמה struct Date { int day, month, year; }; 6 © Keren Kalif

7 איתחול מבנה - דוגמא struct Student { char name[20]; float age; long id; }; void main() { Student stud = {"momo", 23.5, 111111}; cout << "The student's details:\nname=" << stud.name << ", age=" << stud.age << ", id=" << stud.id << endl; } אין מניעה שאחד משדות המבנה יהיה מערך 7 © Keren Kalif

8 איתחול מבנה המכיל מערך - דוגמא const int SIZE = 3; struct Course { int grades[SIZE]; int code; }; void main() { Course c= { {90,80,85}, 10801}; cout << c.code << “ is the course code and the grades are: “; for (int i=0 ; i < SIZE ; i++) cout << c.grades[i] << “ “; cout << endl; } 8 © Keren Kalif course_t: c.grades ??? 1000 ??? c.code ??? int: i ??? 1016 course_t: c.grades 90 1000 80 85 c.code 10801 int: i ??? 1016

9 השמת מבנים  השמה בין מבנים מעתיקה שדה - שדה  אם אחד השדות הוא מערך, מועתק באופן אוטומטי איבר - איבר בניגוד להשמה בין מערכים שאינם בתוך מבנה ( צריך בלולאה להעתיק איבר - איבר ) 9 © Keren Kalif

10 השמת מבנים – דוגמאת student struct Student { char name[6]; float age; int id; }; void main() { Student s1 = {"momo", 23.5, 111111}; Student s2; s2 = s1; cout << "The second student's details:\nname=" << s2.name << ", age=" <<s2.age << ", id=" << s2.id << endl; } Student : s1.name[6] ??? 1000 s1.age ??? s1.id ??? Student : s2.name[6] ??? 1016 s2.age ??? s2.id ??? Student : s1.name[6] “momo” 1000 s1.age 23.5 s1.id 111111 Student : s2.name[6] ??? 1016 s2.age ??? s2.id ??? Student : s1.name[6] “momo” 1000 s1.age 23.5 s1.id 111111 Student : s2.name[6] “momo” 1016 s2.age 23.5 s2.id 111111 10 © Keren Kalif

11 נשים לב..  אם היינו רוצים לבצע השמה לאחד משדות המבנה שהוא מחרוזת, היינו צריכים להשתמש ב - strcpy. כאשר פונים לאחד השדות מתייחסים אליו כמו למשתנה מטיפוס השדה void main() { Student s1; strcpy(s1.name, “momo”); s1.age = 23.5; s1.id = 111111; cout << "The second student's details:\nname=" << s1.name << ", age=" <<s1.age << ", id=" << s1.id << endl; } struct Student { char name[6]; float age; long id; }; 11 © Keren Kalif

12 העברת מבנה לפונקציה  כאשר מעבירים מבנה לפונקציה, מועבר העתק שלו, בדיוק כמו העברת פרמטר ממשתנה פרימיטיבי המשתנה מועבר by value אם נשנה את אחד משדות המבנה בפונקציה, השינוי לא ישפיע על המשתנה המקורי כדי שהפונקציה תשנה את המשתנה המקורי, יש להעבירה by pointer או by reference 12 © Keren Kalif

13 העברת מבנה לפונקציה - דוגמא  פונקציה המדפיסה תאריך struct Date { int day, month, year; }; void printDate(Date d, char delimiter) { cout << d.day << delimiter << d.month << delimiter << d.year; } void main() { Date d1 = {31, 8, 2007}; printDate(d1, '/'); cout << endl; printDate(d1, '-'); cout << endl; } העברת העתק של המבנה לפונקציה Date : d1.day ??? 1000 d1.month ??? d1.year ??? הזיכרון של ה- main Date : d1.day 31 1000 d1.month 8 d1.year 2007 הזיכרון של printDate Date : d.day 31 2000 d.month 8 d.year 2007 char: delimiter ‘/’ 2012 Date : d.day 31 2000 d.month 8 d.year 2007 char: delimiter ‘-’ 2012 13 © Keren Kalif

14 פונקציה המחזירה את הפרש הדקות בין 2 זמנים ( הנחה : הראשון גדול מהשני ) struct Clock { int hour, minute; }; int diffMinutes(Clock c1, Clock c2) { int minutes1 = c1.hour*60 + c1.minute; int minutes2 = c2.hour*60 + c2.minute; return minutes1 - minutes2; } void main() { Clock c1 = {12, 30}; Clock c2 = {11, 15}; int diff = cout << "The diff is “ << diff << “ minutes\n”; } Clock : c1.hour ??? 1000 c1.minute ??? Clock : c2.hour ??? 1008 c2.minute ??? int: diff ??? 1016 הזיכרון של ה- main Clock : c1.hour 12 1000 c1.minute 30 Clock : c2.hour ??? 1008 c2.minute ??? int: diff ??? 1016 Clock : c1.hour 12 1000 c1.minute 30 Clock : c2.hour 11 1008 c2.minute 15 int: diff ??? 1016 diffMinutes(c1, c2); הזיכרון של diffMinutes Clock : c1.hour 12 2000 c1.minute 30 Clock : c2.hour 11 2008 c2.minute 15 int: minutes1 ??? 2016 int: minutes2 ??? 2020 Clock : c1.hour 12 2000 c1.minute 30 Clock : c2.hour 11 2008 c2.minute 15 int: minutes1 750 2016 int: minutes2 ??? 2020 Clock : c1.hour 12 2000 c1.minute 30 Clock : c2.hour 11 2008 c2.minute 15 int: minutes1 750 2016 int: minutes2 675 2020 Clock : c1.hour 12 1000 c1.minute 30 Clock : c2.hour 11 1008 c2.minute 15 int: diff 75 1016 14 © Keren Kalif

15 struct Clock { int hour, minute; }; Clock addMinutes(Clock c, int minutes) { Clock newClock; newClock.minute = c.minute + minutes; newClock.hour = c.hour + newClock.minute/60; newClock.minute %= 60; newClock.hour %= 24; return newClock; } void printClock(Clock c) { if (c.hour < 10) cout << "0”; cout << c.hour << “:”; if (c.minute < 10) cout << "0”; cout << c.minute; } Clock : c1.hour ??? 1000 c1.minute ??? Clock : c2.hour ??? 1008 c2.minute ??? int: toAdd ??? 1016 דוגמא void main() { Clock c1, c2; int toAdd; cout <<"Enter time and minutes to add:”; cin >> c1.hour >> c1.minute >> toAdd; cout << "The time is: “; printClock(c1); c2 = cout << "\nThe new time is: “; printClock(c2); cout << endl; } addMinutes(c1, toAdd); 15 © Keren Kalif הזיכרון של ה- main Clock : c.hour 12 3000 c.minute 50 הזיכרון של printClock Clock : c.hour 12 2000 c.minute 50 Clock : nc.hour ??? 2008 nc.minute ??? int: minutes 30 2016 הזיכרון של addMinutes Clock : c1.hour 12 1000 c1.minute 50 Clock : c2.hour ??? 1008 c2.minute ??? int: toAdd 30 1016 Clock : c.hour 12 2000 c.minute 50 Clock : nc.hour ??? 2008 nc.minute 80 int: minutes 30 2016 Clock : c.hour 12 2000 c.minute 50 Clock : nc.hour 13 2008 nc.minute 80 int: minutes 30 2016 Clock : c.hour 12 2000 c.minute 50 Clock : nc.hour 13 2008 nc.minute 20 int: minutes 30 2016 Clock : c1.hour 12 1000 c1.minute 50 Clock : c2.hour 13 1008 c2.minute 20 int: toAdd 30 1016

16 דוגמאות פלט נוספות  אתם מוזמנים להריץ על " יבש " להבנת האלגוריתם 16 © Keren Kalif

17 פניה לשדה של מצביע למבנה  כאשר יש מצביע למבנה נפנה לשדותיו באמצעות חץ : <- struct Date { int day, month, year; }; void main() { Date d = {28, 8, 2008}; Date* pD = &d; cout << "The year is " << d.year << endl; cout year << endl; cout << "The year is " << (*pD).year << endl; } 1000 המשתנהd פניה לשדה d.year Date : d.day 28 1000 d.month 8 d.year 2008 Date *: pD 1000 1012 17 © Keren Kalif

18 העברת מבנה לפונקציה כמצביע / הפניה  כאשר מעבירים מבנה לפונקציה, מועבר העתק שלו, בדיוק כמו העברת פרמטר ממשתנה פרימיטיבי  כדי שהפונקציה תשנה את המשתנה המקורי : יש להעבירו by pointer, כלומר להעביר את כתובת המבנה או להעבירו by reference  כאשר מעבירים לפונקציה מבנה by value המכיל מערך, עותק של המערך מועבר, ולא רק כתובת ההתחלה שלו, ולכן שינוי הערך בפונקציה לא ישפיע על המערך המקורי 18 © Keren Kalif

19 struct Clock { int hour, minute; }; void addMinutes(Clock * c, int minutes) { c->minute += minutes; c->hour += c->minute/60; c->minute %= 60; c->hour %= 24; } void printClock(Clock c) { if (c.hour < 10) cout << “0”; cout << c.hour; if (c.minute < 10) cout << “0”; cout << c.minute; } void main() { Clock c1; int toAdd; cout << “Enter time and minutes to add: “; cin >> c1.hour >> c1.minute >> toAdd; cout << "The time is: “; printClock(c1); addMinutes(&c1, toAdd); cout << "\nThe new time is: “; printClock(c1); cout << endl; } נשים לב לשימוש בחץ מאחר ו- c הוא מצביע! פונקציה המקבלת זמן ומגדילה אותו – by pointer העברת כתובת של המבנה לפונקציה, כדי שהפונקציה תוכל לשנות את המבנה 19 © Keren Kalif הזיכרון של ה- main Clock : c1.hour ??? 1000 c1.minute ??? int: toAdd ??? 1008 Clock : c.hour 23 3000 c.minute 50 הזיכרון של printClock Clock *: c 1000 3000 int: minutes 75 הזיכרון של addMinutes Clock : c1.hour 23 1000 c1.minute 50 int: toAdd 75 1008 Clock : c1.hour 23 1000 c1.minute 125 int: toAdd 75 1008 Clock : c1.hour 25 1000 c1.minute 125 int: toAdd 75 1008 Clock : c1.hour 25 1000 c1.minute 5 int: toAdd 75 1008 Clock : c1.hour 1 1000 c1.minute 5 int: toAdd 75 1008

20 void main() { Clock c1; int toAdd; cout << “Enter time and minutes to add: “; cin >> c1.hour >> c1.minute >> toAdd; cout << "The time is: “; printClock(c1); addMinutes(c1, toAdd); cout << "\nThe new time is: “; printClock(c1); cout << endl; } פונקציה המקבלת זמן ומגדילה אותו – by ref העברת הפניה של המבנה לפונקציה, כדי שהפונקציה תוכל לשנות את המבנה 20 © Keren Kalif הזיכרון של ה- main Clock : c1.hour ??? 1000 c1.minute ??? int: toAdd ??? 1008 Clock : c1.hour 23 1000 c1.minute 50 int: toAdd 75 1008 Clock : c1.hour 23 1000 c1.minute 125 int: toAdd 75 1008 Clock : c1.hour 25 1000 c1.minute 125 int: toAdd 75 1008 Clock : c1.hour 25 1000 c1.minute 5 int: toAdd 75 1008 Clock : c1.hour 1 1000 c1.minute 5 int: toAdd 75 1008 struct Clock { int hour, minute; }; void addMinutes(Clock & c, int minutes) { c.minute += minutes; c.hour += c.minute/60; c.minute %= 60; c.hour %= 24; } void printClock(Clock c) { if (c.hour < 10) cout << “0”; cout << c.hour; if (c.minute < 10) cout << “0”; cout << c.minute; } Clock : c.hour 23 3000 c.minute 50 הזיכרון של printClock Clock : c int: minutes 75 הזיכרון של addMinutes הפעם השימוש הוא עם נקודה

21 השוואה בין מבנים  בניגוד למשתנה פרימיטיבי, לא ניתן להשוות בין מבנים ע " י אופרטורי ההשוואה : ==, =!, >,, =<  סיבות : יתכן ואחד משדות המבנה אינו ניתן להשוואה ע " י אופרטורים אלו, למשל מערך או מחרוזת אם ישנם כמה שדות במבנה, לא ברור לפי מה נחליט לאיזה שדה חשיבות גדולה יותר ( למשל השוואה בין סטודנטים : לפי ת. ז. או לפי שם ?), וכמובן הקומפיילר אינו יכול לנחש זאת  כדי להשוות בין מבנים עלינו לכתוב פונקציות מתאימות  גם לביצוע פעולות חשבון עלינו לכתוב פונקציות ( האם מוגדרת פעולת החיבור בין 2 סטודנטים ? ועבור שני מערכים ?) 21 © Keren Kalif

22 השוואה בין מבנים  מאחר ולא ניתן להשוות בין מבנים ע " י האופרטור == עלינו לכתוב פונקציה המשווה בין מבנים struct Clock { int hour, minute; }; bool equalClock(Clock c1, Clock c2) { return (c1.hour == c2.hour && c1.minute == c2.minute); } 22 © Keren Kalif

23 השוואה בין מבנים - דוגמא struct Clock { int hour, minute; }; int compareClocks(Clock c1, Clock c2) } if (c1.hour == c2.hour) { if (c1.minute == c2.minute) return 0; else if (c1.minute < c2.minute) return -1; else return 1; { else if (c1.hour < c2.hour) return -1; else return 1; { void main() } Clock c1={12,30}, c2={11,30}, c3={12,30}; cout << "Result for c1 and c2: " << compareClocks(c1, c2) << endl; cout << "Result for c1 and c3: " << compareClocks(c1, c3) << endl; cout << "Result for c2 and c3: " << compareClocks(c2, c3) << endl; { 23 © Keren Kalif

24 מבנה בתוך מבנה  אחד משדות המבנה יכול להיות מבנה אחר דוגמא : struct Date { int day, month, year; }; struct Student { char name[20]; Date birthday; float average; };  היה אפשר גם כך, אבל עדיף שלא.. struct Student { char name[20]; int day, month, year; float average; }; 24 © Keren Kalif

25 מבנה בתוך מבנה - דוגמא struct Date } int day, month, year; }; struct Student { char name[20]; Date birthday; float average; }; void main() { Student s; cout << "Enter name of student and average:\n"; cin >> s.name >> s.average; cout << "Please enter DOB: "; cin >> s.birthday.day >> s.birthday.month >> s.birthday.year; cout << "The student's detailes: \n"; cout << "Name: " << s.name << ", Average: " << s.average << ", DOB: " << s.birthday.day << "-" << s.birthday.month << "-" << s.birthday.year << endl; { 25 © Keren Kalif

26 אתחול מבנה בתוך מבנה struct Date } int day, month, year; }; struct Student { char name[20]; Date birthday; float average; }; void main() { Student s = {"gogo", {23,8,1985}, 95.3}; cout << "The student's detailes: \n"; cout << "Name: " << s.name << ", Average: " << s.average << ", DOB: " << s.birthday.day << "-" << s.birthday.month << "-" << s.birthday.year << endl; { 26 © Keren Kalif

27 מבנה בתוך מבנה ופונקציות - דוגמא struct Date } int day, month, year; }; struct Student { char name[20]; Date birthday; float average; }; void printDate(Date d) { cout << d.day << "-" << d.month << "-" << d.year; } void printStudent(Student s) { cout << "Name: " << s.name << ", Average: " << s.average << ", DOB: "; printDate(s.birthday); cout << endl; } void main() { Student s; cout << "Enter name of student and average:\n"; cin >> s.name >> s.average; cout << "Please enter DOB: "; cin >> s.birthday.day >> s.birthday.month >> s.birthday.year; cout << "The student's detailes: \n”; printStudent(s); { 27 © Keren Kalif

28 יעילות  כאשר מעבירים מבנה לפונקציה העתק שלו מועבר למחסנית של הפונקציה  מבנה יכול להכיל המון שדות ולכן פעולת ההעתקה יכולה להיות " יקרה " מבחינת זמן אנחנו כמובן לא נרגיש זאת  לכן, אם מעבירים מבנה לפונקציה, והפונקציה אינה משנה את המבנה, נעדיף להעביר מצביע או הפניה למבנה, כדי לחסוך את ההעתקה במקרה זה גם נעביר את המצביע או ההפניה כ - const כהצהרה על כך שהפונקציה לא תשנה את תוכנו 28 © Keren Kalif

29 מבנה בתוך מבנה ויעילות - דוגמא struct Date { int day, month, year; }; struct Student { char name[20]; Date birthday; float average; }; void printDate(const Date& d) { cout << d.day << "-" << d.month << "-" << d.year; } void printStudent(const Student& s) { cout << "Name: " << s.name << ", Average: " << s.average << ", DOB: "; printDate(s.birthday); cout << endl; } void main() { Student s; cout << "Enter name of student and average:\n"; cin >> s.name >> s.average; cout << "Please enter DOB: "; cin >> s.birthday.day >> s.birthday.month >> s.birthday.year; cout << "The student's detailes: \n”; printStudent(s); { 29 © Keren Kalif

30 מערך של מבנים  נרצה לשמור במערך את אוסף הסטודנטים הרשומים בכיתה const int MAX_STUDENTS = 3; struct Student { char name[20]; float average; }; void main() { Student students[MAX_STUDENTS] = { {"momo", 90.5}, } "yoyo", 85}, } "gogo", 78.6} }; cout << "The second student is: “ << students[1].name << endl; } הסטונדט השני במערך הסוגריים הכחולים עבור איתחול המערך, וכל זוג סוגריים ירוקים מאתחלים מבנה אחד בתוך המערך 30 © Keren Kalif

31 העברת מערך מבנים לפונקציה const int MAX_STUDENTS = 3; struct Student { char name[20]; float average; }; void printFail(const Student students[], int size) { int i; for (i=0 ; i < size ; i++) if (students[i].average < 60) cout << students[i].name << “ “; cout << endl; } void main() { Student students[MAX_STUDENTS] = { {"momo", 50.5}, {"yoyo", 55}, {"gogo", 78.6} }; cout << "The faied students: “; printFail(students, MAX_STUDENTS); } 31 © Keren Kalif

32 העברת מערך מבנים לפונקציה  בדיוק כמו מערך רגיל, מועברת כתובת ההתחלה... const int MAX=3; struct Student { char name[20]; float average; }; void readStudents(Student students[], int size) { int i; for (i=0 ; i < size ; i++) { cout << "Enter name and average for student #“ << i+1 << “:”; cin >> students[i].name >> students[i].average; } } void printStudents(const Student students[], int size) { for (int i=0 ; i < size ; i++) cout << "Name: “ << students[i].name << “\tAverage: “ << students[i].average << endl; } עובדים על המערך המקורי 32 © Keren Kalif void main() { Student students[MAX]; readStudents(students, MAX); cout << "All students: \n”; printStudents(students, MAX); }

33 גודל מבנה בזיכרון  גודל כל משתנה מסוג מבנה יהיה סכום גודלי השדות מעוגל כלפי מעלה לכפולה של 4 33 © Keren Kalif struct Date { int day; int month; int year; }; struct A { int num; char ch; }; struct B { char arr[10]; int num; }; void main() { cout << "sizeof(Date)=" << sizeof(Date) << endl; cout << "sizeof(A)=" << sizeof(A) << endl; cout << "sizeof(B)=" << sizeof(B) << endl; }

34 גודל מבנה בזיכרון (2) 34 © Keren Kalif struct Date { int day, month, year; char delimiter; }; struct Student { char name[3]; Date birthday; }; void main() { cout << sizeof(Date) << endl; cout << sizeof(Student) << endl; }

35 ביחידה זו למדנו :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים  גודל מבנה בזיכרון 35 © Keren Kalif


Download ppt "מבנים קרן כליף. ביחידה זו נלמד :  מהו מבנה (struct)  איתחול מבנה  השמת מבנים  השוואת מבנים  העברת מבנה לפונקציה  מבנה בתוך מבנה  מערך של מבנים."

Similar presentations


Ads by Google