10 מבנים

Page 1

‫קורס מבוא למדעי המחשב‬ ‫סמסטר א' תשס"ח‬

‫שיעור עשירי‪:‬‬ ‫מבנים‬ ‫‪http://online.shenkar.ac.il/moodle‬‬

‫טיפוסי משתנים בשפת ‪C‬‬ ‫•‬

‫הכרנו במהלך הקורס את טיפוסי המשתנים הבסיסיים שניתן‬ ‫לייצג בשפת ‪ :C‬מספר שלם‪/‬ממשי‪ ,‬תו‪ ,‬מחרוזת‪ ,‬ומערך‪.‬‬

‫•‬

‫כשכתבנו תוכניות לפתרון בעיות כלשהן‪ ,‬יצגנו את נתוני התוכנית‬ ‫ע"י משתנים מהטיפוסים האלה‪.‬‬

‫•‬

‫כידוע‪ ,‬בבעיות מציאותית יכולים להיות אובייקטים מורכבים‪ ,‬שלא‬ ‫בהכרח מתאימים ליצוג ע"י מספר‪ ,‬תו‪ ,‬או אפילו מערך‪.‬‬ ‫•‬ ‫•‬

‫‪1‬‬

‫למשל בבעיות גיאומטריות מדובר על נקודות‪ ,‬ישרים‪ ,‬מצולעים‪ ,‬וכדומה‪.‬‬ ‫מינהלת‪-‬האוניברסיטה מטפלת בפקולטות‪ ,‬קורסים‪ ,‬סטודנטים‪ ,‬וכו'‪.‬‬


‫טיפוסי משתנים בשפת ‪C‬‬ ‫•‬

‫כשכותבים תוכנות לפתרון בעיות מציאותיות‪ ,‬נוח שיהיו לנו‬ ‫טיפוסי משתנים שמייצגים את האובייקטים המציאותיים האלה‪.‬‬ ‫•‬

‫•‬

‫•‬

‫למשל‪ ,‬לטיפול במספרים מרוכבים היינו רוצים טיפוס שייצג מספר‬ ‫מרוכב‪.‬‬ ‫לפתרון בעיות גיאומטריות נירצה למשל טיפוס שמתאר נקודה במישור‬ ‫וטיפוסים שמתארים מצולעים שונים‪.‬‬ ‫במערכת המידע של האוניברסיטה נירצה טיפוסי‪-‬משתנים עבור‬ ‫סטודנט‪ ,‬קורס‪ ,‬וכו' )שכל אחד מהם כולל כמה שדות‪-‬מידע רלוונטיים(‪.‬‬

‫יצירת טיפוסי משתנים חדשים‬

‫‪2‬‬

‫•‬

‫שפת ‪ C‬מאפשרת לנו להגדיר טיפוסי משתנים חדשים‬ ‫שיתאימו לבעיה שאנחנו רוצים לפתור‪.‬‬

‫•‬

‫טיפוס חדש כזה נקרא "מבנה" )‪ .(structure‬הפקודה‬ ‫שתשמש אותנו לכך היא ‪.struct‬‬

‫•‬

‫בדרך‪-‬כלל מבנה כולל כמה משתנים‪ ,‬שנקראים "שדות"‬ ‫)דוגמא בשקף הבא(‪.‬‬


‫הגדרת מבנה חדש – דוגמא‬ ‫•‬

‫•‬ ‫•‬

‫נקודה במישור מיוצגת על‪-‬ידי שתי קואורדינטות‪ X ,‬ו‪ .Y -‬הגדרת‬ ‫מבנה שייצג נקודה תיראה למשל כך‪:‬‬ ‫{ ‪struct point‬‬ ‫;‪double x‬‬ ‫;‪double y‬‬ ‫;}‬ ‫ההגדרה הזו לא תופיע בתוך פונקציה‪ ,‬אלא בתחילת הקובץ‬ ‫)בד"כ אחרי שורות ה‪.(#include -‬‬ ‫כעת ניתן להגדיר בתוכנית משתנים מהסוג הזה‪ ,‬כפי שניראה‬ ‫בשקף הבא‪.‬‬

‫הגדרת מבנה חדש – המשך הדוגמא‬ ‫•‬

‫•‬

‫דוגמא להגדרת משתנים מהטיפוס החדש‪:‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪struct point P1,P‬‬ ‫‪,P2‬‬ ‫;‪2‬‬ ‫;‪return 0‬‬ ‫}‬ ‫בכך הגדרנו שתי נקודות )שני משתנים מסוג מבנה ‪,(point‬‬ ‫שלכל אחת מהן יש שני שדות‪.‬‬

‫‪P1‬‬

‫‪3‬‬

‫‪P2‬‬

‫‪x‬‬

‫‪x‬‬

‫‪y‬‬

‫‪y‬‬


‫הגדרת מבנה חדש – המשך הדוגמא‬ ‫ניתן לגשת לכל אחד מהשדות של מבנה ולכתוב‪/‬לקרוא‬ ‫אליו‪/‬ממנו‪ .‬למשל‪:‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪struct point P1,P‬‬ ‫‪,P2‬‬ ‫;‪2‬‬ ‫;‪P1.x = 6‬‬ ‫;‪P1.y = 7‬‬ ‫‪P2‬‬ ‫‪P1‬‬ ‫;‪P2.x = 4‬‬ ‫;‪P2.y = 2‬‬ ‫‪x 4‬‬ ‫‪x 6‬‬ ‫‪printf(“%g‬‬ ‫‪printf‬‬ ‫‪(“%g\\n”, P1‬‬ ‫;)‪P1.y‬‬ ‫‪y 2‬‬ ‫‪y 7‬‬ ‫;‪return 0‬‬ ‫)יודפס ‪(7‬‬ ‫}‬

‫נושאי השיעור היום‬ ‫מבנים‪:‬‬ ‫•‬ ‫•‬ ‫•‬ ‫•‬ ‫•‬ ‫•‬

‫הגדרה ואיתחול‬ ‫פעולות על מבנים‬ ‫מבנים ופונקציות‬ ‫מבנים ומצביעים‬ ‫מבנה בתוך מבנה‬ ‫מערכים של מבנים‬

‫הקצאה דינאמית‪ :‬הקצאת משתנים במהלך ריצת התוכנית‬

‫‪4‬‬


‫מבנים ‪ -‬תיאור פורמלי‬ ‫•‬

‫•‬

‫•‬

‫הגדרת מבנה )טיפוס משתנה חדש(‪:‬‬ ‫{שם הטיפוס החדש ‪struct‬‬ ‫{שם‬ ‫;שם‪-‬שדה טיפוס‬ ‫‪…..‬‬ ‫;שם‪-‬שדה טיפוס‬ ‫;}‬ ‫הגדרת משתנה מהסוג החדש שהגדרנו‪:‬‬ ‫;שם משתנה שם הטיפוס החדש ‪struct‬‬ ‫פנייה לשדה של משתנה שהוא מבנה נעשית ע"י‬

‫‪.‬‬

‫שם השדה שם המשתנה‬

‫הגדרת מבנה חדש ‪ -‬הדוגמא הקודמת‬

‫‪P1‬‬

‫‪5‬‬

‫‪P2‬‬

‫‪6‬‬

‫‪x‬‬

‫‪4‬‬

‫‪x‬‬

‫‪7‬‬

‫‪y‬‬

‫‪2‬‬

‫‪y‬‬

‫>‪#include<stdio.h‬‬ ‫{ ‪struct point‬‬ ‫;‪double x‬‬ ‫;‪double y‬‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫‪struct point P1,P‬‬ ‫‪,P2‬‬ ‫;‪2‬‬ ‫; ‪P 1 .x = 6‬‬ ‫; ‪P 1 .y = 7‬‬ ‫; ‪P 2 .x = 4‬‬ ‫; ‪P 2 .y = 2‬‬ ‫‪printf(“%g\\n”, P1‬‬ ‫‪printf(“%g‬‬ ‫;)‪P1.y‬‬ ‫;‪return 0‬‬ ‫}‬


‫איתחול מבנים‬ ‫•‬

‫גם משתנים מטיפוס חדש אפשר לאתחל בשורת ההגדרה‪.‬‬ ‫למשל בהתייחס לדוגמא הקודמת‪:‬‬ ‫‪struct point P = {6‬‬ ‫;}‪{6,7‬‬ ‫• השדה ‪ x‬של המשתנה ‪ P‬יאותחל ל‪ 6-‬והשדה ‪ y‬ל‪.7-‬‬

‫•‬

‫באופן כללי‪ ,‬האיתחול הוא לפי סדר השדות בהגדרת המבנה‪,‬‬ ‫כלומר האיבר הראשון ברשימת האיתחול יכנס לשדה הראשון‪,‬‬ ‫השני לשני‪ ,‬וכן הלאה )אם האיתחול הוא חלקי‪ ,‬השאר יאותחל‬ ‫באפסים(‪.‬‬

‫מבנים – הגדרה‬ ‫•‬ ‫•‬ ‫•‬ ‫•‬

‫‪6‬‬

‫מהם מבנים‬ ‫הגדרת מבנים‬ ‫איתחול מבנים‬ ‫שאלות?‬


‫פעולות על מבנים‬ ‫•‬

‫השמה מתבצעת בצורה הרגילה‪:‬‬ ‫•‬ ‫•‬

‫•‬

‫‪P1 = P‬‬ ‫‪P2‬‬ ‫;‪2‬‬ ‫התוכן של ‪ P2‬פשוט מועתק לתוך ‪) .P1‬העתקה שדה‪-‬שדה(‬ ‫אם אחד השדות הוא מערך אז גם הוא מועתק )שינוי שלו ב‪-‬‬ ‫‪ P1‬לא ישפיע על ‪.(P2‬‬

‫•‬

‫פעולות השוואה )== והאחרות( ופעולות חשבון אינן פועלות‬ ‫עבור מבנים )זה לא יתקמפל(‪.‬‬ ‫• כלומר נצטרך לכתוב פונקציות עבור הפעולות שנירצה ליישם‬ ‫)למשל נשווה את כל אחד מהשדות כדי לבצע השוואה(‪.‬‬

‫דוגמא‪ ::‬פונקציה להשוואת מבני ‪point‬‬ ‫דוגמא‬ ‫(‪int equal‬‬ ‫‪equal(struct‬‬ ‫)‪struct point p, struct point q‬‬ ‫{‬ ‫‪return ( (p.x‬‬ ‫)‪(p.x == q.x‬‬ ‫‪q.x) && ((p.y‬‬ ‫))‪p.y == q.y‬‬ ‫))‪q.y‬‬ ‫}‬

‫אם הנקודות זהות יוחזר ‪ ,1‬ואחרת ‪0‬‬

‫‪7‬‬


‫דוגמא לשימוש במבנים‬ :‫נכתוב פונקציה שמחשבת מרחק בין שתי נקודות‬

double dist( struct point p, struct point q) { double d; d = (p.x (p.x – q.x)*( q.x)*(p.x p.x – q.x) q.x) + ((p.y p.y– –q.y)*( q.y)*(p.y p.y--q.y); q.y); return sqrt( sqrt(d); }

‫ המשך‬- ‫דוגמת שימוש במבנים‬ …. int main() { struct point p,q p,q;; printf(“ printf (“Enter Enter x and y coord. coord. of the first point\ point\n”); scanf(“% scanf (“%lf%lf lf%lf”, ”, & &p.x,&p.y p.x,&p.y); ); printf(“ printf (“Enter Enter x and y coord. coord. of the second point\ point\n”); scanf(“% scanf (“%lf%lf lf%lf”, ”, & &q.x,&q.y q.x,&q.y); ); printf(“ printf (“Their Their distance is %g\ %g\n”, dist(p,q dist(p,q)); )); return 0;

}

8


‫פונקציות ומבנים‬ ‫•‬

‫איך מבני הנקודות מועברים לפונקציה?‬

‫פונקציות ומבנים‬

‫‪9‬‬

‫•‬

‫איך מבני הנקודות מועברים לפונקציה?‬

‫•‬

‫הם מועברים על ידי העתקת הערכים של השדות שלהם‬ ‫לפרמטרים של הפונקציה‪.‬‬ ‫• כמו במשתנים רגילים )‪ ,(call by value‬כמו עבור ‪.int‬‬ ‫• שינוי הנקודה בפונקציה לא ישנה את הנקודה ב‪.main -‬‬

‫•‬

‫פונקציה יכולה גם להחזיר מבנה‪ ,‬כמו כל משתנה אחר )גם‬ ‫במקרה הזה הערכים יועתקו(‪.‬‬


‫פונקציות ומבנים – נקודה לתשומת‪-‬לב‬ ‫•‬

‫אם אחד השדות של המבנה הוא מערך‪ ,‬ומעבירים את המבנה‬ ‫הזה לפונקציה‪ ,‬אז המערך מועתק )לא רק כתובת המערך‬ ‫מועברת(‪.‬‬

‫•‬

‫כלומר אם נשנה בפונקציה מערך שהוא שדה של מבנה‪ ,‬אז לא‬ ‫תהיה לזה השפעה על המערך המקורי‪.‬‬

‫•‬

‫למשל אם נגדיר את המבנה הבא‪:‬‬ ‫‪struct int_array_10‬‬ ‫‪int_array_10‬‬ ‫{‬ ‫[‪int array‬‬ ‫‪array[10‬‬ ‫;]‪10‬‬ ‫;]‬ ‫;}‬

‫פונקציות ומבנים – נקודה לתשומת‪-‬לב‬ ‫אז הפונקציה הבאה לא תשפיע על המשתנה שמועבר אליה‪:‬‬ ‫(‪void zero_array‬‬ ‫‪zero_array(struct int_array_10‬‬ ‫)‪int_array_10 A‬‬ ‫{‬ ‫;‪int i‬‬ ‫;‪for(ii=0; i<10‬‬ ‫(‪for‬‬ ‫)‪10; i++‬‬ ‫מה שמאופס הוא העתק של המערך‪ ,‬כי מערך‬ ‫=]‪A.array[[i‬‬ ‫‪A.array‬‬ ‫‪]=0‬‬ ‫;‪0‬‬ ‫בתוך מבנה מועתק בהעברה לפונקציה‬ ‫}‬ ‫ כדי לשנות את המערך המקורי נשתמש במצביע‪ ,‬כפי שניראה בהמשך )או‬‫שנעביר לפונקציה מצביע למבנה או שנגדיר במבנה מצביע במקום מערך(‬

‫‪10‬‬


‫מבנים ‪ -‬פעולות‬ ‫•‬

‫השמה בין מבנים מותרת )מתבצעת העתקה שדה‪-‬שדה(‬ ‫פעולות השוואה ופעולות חשבון לא עובדות‬ ‫ניתן להעביר מבנים לפונקציה ולהחזיר ממנה מבנה‪ ,‬והם‬ ‫מועתקים אליה וממנה‪ ,‬כמו טיפוס‪-‬משתנה רגיל )כמו ‪(int‬‬ ‫מערך בתוך מבנה מועתק בהעברה לפונקציה ובחזרה ממנה‬

‫•‬

‫שאלות?‬

‫•‬ ‫•‬ ‫•‬

‫מבנים ומצביעים‬ ‫•‬

‫אם המבנה שלנו מורכב מהרבה מאוד משתנים‪ ,‬אז העתקת כל‬ ‫המבנה לתוך הפרמטרים של הפונקציה דורשת זמן וזיכרון רבים‪.‬‬

‫•‬

‫כמו‪-‬כן‪ ,‬כמו במשתנים רגילים‪ ,‬לפעמים נירצה לשנות יותר‬ ‫ממבנה אחד מתוך הפונקציה )ולא רק להחזיר מבנה אחד(‪.‬‬

‫•‬

‫כדי לטפל בשני הנושאים האלה נוכל לשלוח לפונקציה מצביעים‬ ‫למבנים‪ ,‬כמו ששלחנו מצביעים למשתנים מסוגים אחרים‪.‬‬ ‫•‬

‫‪11‬‬

‫בקריאה לפונקציה ישוכפל רק המצביע לכל מבנה‪ ,‬ובעזרת המצביע נוכל‬ ‫לשנות את המבנה המקורי‪.‬‬


‫מבנים ומצביעים‬ ‫בדיוק כמו טיפוסי‪-‬משתנים שהכרנו בעבר‪ ,‬אפשר להגדיר מצביע‬ ‫לטיפוס שהוא מבנה )כתובת ההתחלה של מבנה היא כתובת‬ ‫השדה הראשון שלו(‪ .‬למשל‪:‬‬

‫‪P‬‬

‫‪P.x‬‬

‫‪P.y‬‬

‫‪5‬‬ ‫‪6‬‬

‫‪struct point P={5‬‬ ‫;}‪P={5,6‬‬ ‫;‪struct point *ptr‬‬ ‫;‪ptr‬‬ ‫; ‪ptr = &P‬‬

‫‪ptr‬‬

‫מצביעים ומבנים – גישה לשדות המבנה‬ ‫•‬

‫בדוגמא הזאת‪ ,‬כדי להגיע לשדות של ‪ P‬דרך ‪ ptr‬שמצביע על ‪,P‬‬ ‫אפשר להשתמש ב‪ * -‬כרגיל‪:‬‬ ‫*( •‬ ‫‪(*ptr‬‬ ‫‪ptr).‬‬ ‫‪ P.‬שקול ל‪).xx = 3; -‬‬ ‫‪P.x‬‬ ‫‪x=3‬‬ ‫*( •‬ ‫‪(*ptr‬‬ ‫‪ptr).‬‬ ‫‪ P.‬שקול ל‪).yy = 7; -‬‬ ‫‪P.y‬‬ ‫‪y=7‬‬

‫)צריך סוגריים כי אחרת לנקודה יש קדימות(‬

‫‪12‬‬


‫מצביעים ומבנים – גישה לשדות המבנה‬ ‫•‬

‫בדוגמא הזאת‪ ,‬כדי להגיע לשדות של ‪ P‬דרך ‪ ptr‬שמצביע על ‪,P‬‬ ‫אפשר להשתמש ב‪ * -‬כרגיל‪:‬‬ ‫*( •‬ ‫‪(*ptr‬‬ ‫‪ptr).‬‬ ‫‪ P.‬שקול ל‪).xx = 3; -‬‬ ‫‪P.x‬‬ ‫‪x=3‬‬ ‫*( •‬ ‫‪(*ptr‬‬ ‫‪ptr).‬‬ ‫‪ P.‬שקול ל‪).yy = 7; -‬‬ ‫‪P.y‬‬ ‫‪y=7‬‬

‫)צריך סוגריים כי אחרת לנקודה יש קדימות(‬ ‫•‬

‫אבל בדרך‪-‬כלל נשתמש לצורך זה בסימון מקוצר‪ :‬חץ >‪-‬‬ ‫‪ptr‬‬‫‪ P.‬שקול ל‪ptr->x = 3; -‬‬ ‫‪P.x‬‬ ‫‪x=3‬‬ ‫‪ptr‬‬‫‪ P.‬שקול ל‪ptr->y = 7; -‬‬ ‫‪P.y‬‬ ‫‪y=7‬‬

‫•‬

‫כלומר משמעות החץ היא גישה לשדה במבנה שמצביעים עליו‪.‬‬

‫•‬ ‫•‬

‫מצביעים ומבנים ‪ -‬דוגמא‬ ‫• פונקציית ההשוואה כשמועברים מצביעים‪:‬‬ ‫)‪int equal( struct point *p, struct point *q‬‬ ‫{‬ ‫‪return ((p‬‬‫‪((p->x == q‬‬‫‪q->x) && (p‬‬‫‪(p->y == q‬‬‫;))‪q->y‬‬ ‫}‬ ‫‪equal(&P1‬‬ ‫‪equal(&P‬‬ ‫‪1,&P‬‬ ‫‪,&P2‬‬ ‫הקריאה לפונקציה ע"י )‪2‬‬ ‫)הגישה עם חץ היא לשדה של המבנה שמצביעים עליו(‬ ‫במקום‪:‬‬

‫(‪int equal‬‬ ‫‪equal(struct‬‬ ‫)‪struct point p, struct point q‬‬

‫‪equal(P1‬‬ ‫‪equal(P‬‬ ‫‪1, P2‬‬ ‫הקריאה לפונקציה ע"י )‪P2‬‬

‫{‬

‫‪return ( (p‬‬ ‫‪(p.x == q.x) && (p‬‬ ‫))‪(p.y == q.y‬‬ ‫)הגישה עם נקודה היא לשדה של מבנה(‬

‫‪13‬‬

‫}‬


‫מצביעים ומבנים – עוד דוגמא‬ ‫נחשב את המרחק כשמועברים מצביעים ולא המבנים עצמם‪:‬‬ ‫‪double dist(struct‬‬ ‫)‪dist(struct point *p, struct point *q‬‬ ‫{‬ ‫‪double d,dx,dy‬‬ ‫;;‪d,dx,dy‬‬ ‫‪dx = p‬‬ ‫;‪p-->x - q->x‬‬ ‫‪dy = p‬‬ ‫;‪p-->y - q->y‬‬ ‫‪d = dx‬‬ ‫‪dx**dx + dy‬‬ ‫‪dy**dy‬‬ ‫;;‪dy‬‬ ‫(‪return sqrt‬‬ ‫;)‪sqrt(d‬‬

‫}‬ ‫איך תיראה הקריאה ב‪?main-‬‬

‫\‪printf(“The distance is %g‬‬ ‫&(‪%g\n”, dist‬‬ ‫))‪dist(&P1,&P2‬‬

‫מבנים ומצביעים‬ ‫•‬ ‫•‬ ‫•‬

‫‪14‬‬

‫כמו עם טיפוסי‪-‬משתנים רגילים‬ ‫גישה לשדות של המבנה המוצבע ע"י >‪-‬‬ ‫שאלות?‬


‫מבנים – כתיבה מקוצרת‬ ‫שמו של הטיפוס החדש שהגדרנו הוא ‪struct point‬‬ ‫אפשר לחסוך את כתיבת המילה ‪ struct‬באמצעות הפקודה‬ ‫‪ ,typedef‬שמאפשרת לתת שם חדש לטיפוס‪-‬משתנה‪:‬‬ ‫{ ‪struct point‬‬ ‫;‪double x‬‬ ‫;‪double y‬‬ ‫;}‬ ‫‪typedef struct point point_t‬‬ ‫;;‪point_t‬‬

‫•‬ ‫•‬

‫שם חדש טיפוס קיים‬

‫מבנים – כתיבה מקוצרת‬ ‫אפשר גם לכתוב את שתי השורות יחד באופן הבא‪:‬‬ ‫{ ‪typedef struct point‬‬ ‫;‪double x‬‬ ‫;‪double y‬‬ ‫‪} point_t‬‬ ‫;;‪point_t‬‬ ‫•‬

‫‪15‬‬

‫בזכות ה‪ typedef -‬נוכל לכתוב ‪ point_t‬במקום לכתוב‬ ‫‪) struct point‬זה שקול לחלוטין(‪ .‬למשל‪:‬‬ ‫‪double dist(point_t‬‬ ‫)‪dist(point_t *p, point_t *q‬‬


‫עוד על ‪typedef‬‬ ‫•‬

‫נציין שהפקודה ‪ typedef‬יכולה לשמש גם כדי לתת שם חדש‬ ‫לטיפוס קיים שאיננו מבנה‪.‬‬

‫•‬

‫למשל אם נרצה לתת שם מיוחד ל‪-‬‬ ‫‪unsigned int‬‬ ‫אפשר לכתוב‪:‬‬ ‫‪typedef unsigned int UINT‬‬ ‫;;‪UINT‬‬ ‫שם חדש‬

‫•‬

‫שם קיים‬

‫עכשיו בכל מקום בתוכנית שנרצה נוכל להשתמש ב‪UINT-‬‬ ‫כדי להגדיר ‪.unsigned int‬‬ ‫;‪unsigned int ui‬‬ ‫‪ UINT ui‬שקול ל‪ui; -‬‬ ‫;;‪ui‬‬

‫מבנה בתוך מבנה‬

‫‪16‬‬

‫•‬

‫שדות של מבנה יכולים להיות בעצמם מבנים אחרים‪.‬‬

‫•‬

‫לדוגמא‪ ,‬נאמר שנירצה להגדיר מבנה שמתאר מלבן במישור‬ ‫שמקביל לצירים‪.‬‬


‫מבנה בתוך מבנה ‪ -‬דוגמא‬ ‫•‬

‫מלבן שמקביל לצירים נקבע על‪-‬ידי שני קודקודים נגדיים כאלה‪:‬‬

‫‪p‬‬ ‫‪q‬‬

‫מבנה בתוך מבנה‬ ‫אפשר להגדיר את זה על‪-‬ידי הקואורדינטות של שני הקודקודים‪:‬‬ ‫{ ‪struct rect‬‬ ‫‪double xl, xh,‬‬ ‫‪xh, yl‬‬ ‫;‪yl,, yh‬‬ ‫;‪yh‬‬ ‫;}‬ ‫אבל יותר נוח וברור להגדיר ע"י ‪ 2‬נקודות‪:‬‬ ‫{ ‪struct rect‬‬ ‫;‪point_t p‬‬ ‫;‪point_t q‬‬ ‫;}‬ ‫‪typedef struct rect rect_t‬‬ ‫;;‪rect_t‬‬

‫‪17‬‬


‫מבנה בתוך מבנה ‪ -‬אתחול‬ ‫•‬

‫גם מבנה שיש בתוכו מבנה אפשר לאתחל בשורת ההגדרה‪:‬‬ ‫‪rect_t r = { {5,6} , {10,‬‬ ‫;} }‪10,2‬‬

‫‪q‬‬

‫‪p‬‬

‫כרגיל ערך האיתחול הראשון משוייך לשדה הראשון‪ ,‬השני לשני‪,‬‬ ‫וכן הלאה )ובאיתחול חלקי השאר מאותחל לאפסים(‪.‬‬ ‫•‬

‫אפשר כמובן גם לאתחל כל שדה ישירות אחרי ההגדרה‪:‬‬ ‫;‪r.p.x = 5‬‬ ‫;‪r.p.y = 6‬‬ ‫;‪r.q.x = 10‬‬ ‫;‪10‬‬ ‫;‪r.q.y = 2‬‬

‫מערך של מבנים‬ ‫•‬

‫כמו טיפוסי משתנים אחרים‪ ,‬אפשר גם להגדיר מערך של מבנים‪.‬‬

‫•‬

‫למשל‪ ,‬אפשר להגדיר מערך של נקודות‪:‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪point_t point_arr‬‬ ‫;]‪point_arr[[20‬‬ ‫;]‪20‬‬ ‫…‬ ‫}‬

‫‪18‬‬


‫מערך של מבנים ‪ -‬דוגמא‬ ‫•‬

‫נכתוב פונקציה שמקבלת מערך של מלבנים‪ ,‬ומחזירה‬ ‫מצביע למלבן עם האלכסון הארוך ביותר‪.‬‬

‫•‬

‫שם הפונקציה יהיה ‪MaxRect‬‬ ‫הפרמטרים שהיא תקבל‪ :‬מערך של מלבנים )כלומר‬ ‫הכתובת של המלבן הראשון במערך(‪ ,‬וגודל המערך‪.‬‬ ‫הערך המוחזר‪ :‬מצביע למלבן‬

‫•‬ ‫•‬

‫תכנון הפונקציה ‪MaxRect‬‬

‫‪19‬‬

‫•‬

‫הפונקציה תעבור על המערך ותחשב לכל מלבן את אורך‬ ‫האלכסון שלו‪.‬‬

‫•‬

‫היא תשמור את האורך המקסימלי שנמצא עד עכשיו ואת‬ ‫אינדקס המלבן שבו הוא נמצא‪.‬‬

‫•‬

‫אם האלכסון הנוכחי גדול יותר מהמקסימלי שהיה עד עכשיו‪,‬‬ ‫נעדכן את המקסימום ואת האינדקס‪.‬‬

‫•‬

‫בסוף יוחזר מצביע באמצעות האינדקס ששמרנו‪.‬‬


‫איך ניראה מערך של מלבנים בזיכרון‬ ‫המלבנים נשמרים‬ ‫ברצף בזיכרון‬ ‫‪rect_t‬‬ ‫‪rect_t‬‬ ‫‪rect_t‬‬ ‫‪rect_t‬‬ ‫‪rect_t‬‬

‫כל מלבן מכיל שני‬ ‫שדות מסוג נקודה‬ ‫‪point_t p‬‬ ‫‪point_t q‬‬

‫כל נקודה מכילה שני‬ ‫שדות מסוג ‪double‬‬ ‫‪double x‬‬ ‫‪double y‬‬ ‫‪double x‬‬ ‫‪double y‬‬

‫‪rect_t‬‬ ‫‪rect_t‬‬

‫מלבן עם אלכסון מקסימלי – ‪MaxRect‬‬ ‫(‪rect_t* MaxRect‬‬ ‫*‪rect_t‬‬ ‫[‪MaxRect(rect_t arr‬‬ ‫מועברים המערך וגודלו )‪arr[ ], int size‬‬ ‫{‬ ‫‪double max=0‬‬ ‫;‪max=0‬‬ ‫אורך האלכסון המקס' עד כה מאותחל לאפס‬ ‫לאפס‬ ‫אינדקס המלבן המקס' עד כה מאותחל‬ ‫‪int i, max_index‬‬ ‫=‪max_index‬‬ ‫;‪=0‬‬ ‫‪for (i‬‬ ‫)‪(i = 0 ; i < size ; i++‬‬ ‫עוברים בלולאה על כל המלבנים‬ ‫{‬ ‫נבדק אורך האלכסון‪.‬‬ ‫(‪if ((dist‬‬ ‫‪dist(arr‬‬ ‫[‪arr[[i].p, arr‬‬ ‫)‪arr[i].q) > max‬‬ ‫{‬ ‫אם מצאנו ארוך יותר אז‬ ‫‪max = dist(arr‬‬ ‫[‪dist(arr[[i]. p, arr‬‬ ‫מעדכנים את המקסימום ;)‪arr[i].q‬‬ ‫;‪max_index = i‬‬ ‫והאינדקס‬ ‫}‬ ‫}‬ ‫מחזירים מצביע למלבן המקסימלי‬ ‫;‪return arr + max_index‬‬ ‫;‪max_index‬‬ ‫)כתובת ההתחלה ועוד האינדקס שלו(‬ ‫}‬

‫‪20‬‬


‫אתחול מערך של מבנים‬ ‫•‬

‫גם מערך של מבנים אפשר לאתחל בשורת ההגדרה‪ ,‬על‪-‬ידי‬ ‫כתיבת ערכי איתחול לכל מבנה לפי הסדר‪.‬‬

‫•‬

‫לדוגמא עבור מערך של מלבנים‪:‬‬ ‫[‪rect_t arr‬‬ ‫]‪arr[20‬‬ ‫‪20] = { {{ 3,4} , {{5‬‬ ‫‪5,6}} ,‬‬ ‫‪{{ 4,7} , {9‬‬ ‫}}‪{9,10‬‬ ‫} … ‪10}} ,‬‬

‫• מבנה בתוך מבנה‬ ‫• מערך של מבנים‬ ‫• שאלות?‬

‫‪21‬‬


‫מבנים – עוד דוגמא‬ ‫מבנים יכולים כאמור להכיל שדות מסוגים שונים‪.‬‬ ‫דוגמא למבנה שמייצג סטודנט )בהנחה ששמו באורך של פחות‬ ‫מ‪ 40 -‬תווים(‪:‬‬ ‫{‪struct student‬‬ ‫;‪int id‬‬ ‫‪char name[4‬‬ ‫;]‪name[40‬‬ ‫;‪double average‬‬ ‫;}‬ ‫;‪typedef struct student student_t‬‬ ‫;‪student_t‬‬

‫•‬ ‫•‬

‫מבנים ‪ -‬סטודנט‬ ‫נוכל למשל להגדיר מערך של הסטודנטים בכיתה‪:‬‬ ‫)נניח ש‪ CLASS_SIZE -‬הוא קבוע‬ ‫שמכיל את מס' הסטודנטים בכיתה(‬

‫•‬

‫‪22‬‬

‫‪# define CLASS_SIZE 50‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪student_t class[CLASS_SIZE‬‬ ‫‪….‬‬ ‫}‬ ‫נכתוב לדוגמא פונקציה שמדפיסה את שמות הסטודנטים‬ ‫המצטיינים ומחזירה את מספרם‬


‫דוגמא‪ :‬פונקציה למציאת המצטיינים‬ ‫‪int top_students‬‬ ‫)] [‪top_students((student_t students‬‬ ‫{‬ ‫;‪int i, cnt = 0‬‬ ‫)‪for(ii = 0; i < CLASS_SIZE; i++‬‬ ‫(‪for‬‬ ‫{‬ ‫‪if (students[i‬‬ ‫‪(students[i].‬‬ ‫‪].average‬‬ ‫)‪average > 90‬‬ ‫)‪90‬‬ ‫{‬ ‫‪printf(“%s‬‬ ‫‪printf‬‬ ‫‪(“%s\\n”, students[i‬‬ ‫;)‪students[i].name‬‬ ‫;‪cnt++‬‬ ‫‪cnt‬‬ ‫;‪++‬‬ ‫}‬ ‫}‬ ‫כאמור מחזירים את מספר המצטיינים‬ ‫;‪return cnt‬‬ ‫;‪cnt‬‬ ‫}‬

‫מבנים ‪ -‬סיכום‬

‫‪23‬‬

‫•‬

‫שימוש במבנים מאפשר הגדרת טיפוסי משתנים חדשים‬ ‫שקרובים לעולם‪-‬הבעיה שאנחנו פותרים‪.‬‬

‫•‬

‫אפשר להשתמש בהם כמו בטיפוסים רגילים מבחינת הגדרת‬ ‫מערך של מבנים‪ ,‬מצביעים על מבנה‪ ,‬העברה לפונקציה )למעט‬ ‫העובדה שמערכים מועתקים(‪ ,‬וכו'‪.‬‬

‫•‬

‫לא ניתן להשתמש בפעולות החשבון וההשוואה הרגילות על‬ ‫מבנים ‪ -‬יש להגדיר פונקציות עבורן בהתאם לצורך )רק פעולת‬ ‫ההשמה מוגדרת‪ ,‬ובה מתבצעת גם העתקת מערכים(‪.‬‬

‫•‬

‫ע"י ‪ typedef‬ניתן לחסוך את כתיבת המילה ‪.struct‬‬


‫קורס תכנות – שיעור עשירי‪ :‬מבנים‬

‫שאלות נוספות?‬

‫‪24‬‬


Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.