![]() |
.. (לתיקייה המכילה) | |
הבהרות ועדכונים | |
הבהרות ועדכונים להלן פירוט של הבהרות ועדכונים, בעקבות שאלות סטודנטים. בכל הבהרה/עדכון שלהלן מופיע בהתחלה סוג ההבהרה/עדכון. מודגש שאין שום שינויים מהדרישות המקוריות של התרגיל. כל העדכונים הרלוונטיים יושמו גם בקבצים המפורסמים לסטודנטים באתר הקורס וב – csl2. חלק יבש שאלה 1 הבהרה בעקבות שאלת סטודנט – אין שום שינויים בדרישות המקוריות של התרגיל. שימוש תקין ב – assert – הכוונה היא לשימוש שנעשה בהתאם לייעוד של פעולת assert. יש להקפיד על נימוק מדויק. שאלה 2 עדכון שמאפשר שחרור זיכרון – אין שום שינויים בדרישות המקוריות של הפונקציה flat_text. התוכנית הראשית תקרא לפונקציה כך : char *p = flat_text(words, 4); if (p!=NULL) { printf(“\n%s\n”, p); free(p); } הערה : מותר להשתמש ב – realloc, אבל עדיף להשתמש אך ורק ב – malloc וב – free . כמובן, יש להקפיד ולקיים את כל דרישות השאלה. חלק רטוב ----------------------------------------------------------------------------------------------------------- עדכון טכני שמאפשר שימוש מודולרי בפונקציות הרלוונטיות כפי שהייתה הכוונה המקורית – אין שום שינויים בדרישות המקוריות של התרגיל בקובץ challenge_system.h לגבי הפונקציה Result destroy_system(ChallengeRoomSystem *sys, int destroy_time, char **most_popular_challenge, char **challenge_best_time); הפרמטר השלישי ייקרא most_popular_challenge_p כלומר הפונקציה תוגדר כך : Result destroy_system(ChallengeRoomSystem *sys, int destroy_time, char **most_popular_challenge_p, char **challenge_best_time); ----------------------------------------------------------------------------------------------------------- הבהרה ובמידת הצורך הקלה לסטודנטים המתקשים – אין שום שינויים בדרישות המקוריות של התרגיל בנוגע להשלמת ההגדרה של הטיפוס ChallengeRoomSystem יש להשלים את ההגדרה בקובץ challenge_room_system_fields.h שימו לב שבסך הכל, ההגדרה הכוללת היא כמו שרשום בקובץ challenge_system.h typedef struct SChallengeRoomSystem { #include "challenge_room_system_fields.h" } ChallengeRoomSystem; ולכן, כמובן, צריך לרשום בקובץ challenge_room_system_fields.h רק את מה שצריך כך שזה יעבור קומפילציה ויעבוד נכון. שימו לב : הטיפוס ChallengeRoomSystem צריך, בין היתר, לתמוך ברשימה דינמית של מבקרים מטיפוס Visitor . כפי שהוגדר בתרגיל, הגדרת הרשימה, מימושה וניהולה נתון לשיקולכם ולבחירתכם. אפשר להשתמש ברשימה מקושרת ואפשר גם בדרכים אחרות, למשל – מערך אשר גודלו יעודכן מפעם לפעם. נא שימו לב שאסור לשנות את הקובץ challenge_system.h כפי שהוגדר ופורסם, אתם נדרשים לעדכן ו/או להוסיף מה שצריך רק בקובץ challenge_room_system_fields.h שימו לב שהשימוש בקובץ זה מספיק כדי לתמוך גם במימוש רשימת המבקרים כרשימה מקושרת. כך, למשל, ניתן להגדיר הגדרה כזו : struct st1 { int data1; struct st2 { int data2; struct st2 *next; } }; יחד עם זאת, אנו נאפשר להוסיף הגדרות נחוצות גם בקובץ נוסף system_additional_types.h אשר ימוקם לפני ChallengeRoomSystem ולא בתוכו. עדיף, כאמור, שלא להשתמש בו ולהסתפק בקובץ challenge_room_system_fields.h ----------------------------------------------------------------------------------------------------------- הבהרה – אין שום שינויים בדרישות המקוריות של התרגיל אם מבקר נכנס למערכת אזי מובטח שהוא יצא בזמן יותר גדול. מבקר לא יצא באותו זמן שבו הוא נכנס. לכן, אם הזמן הטוב ביותר של אתגר מסוים הוא 0, אזי זה אומר שכלל לא ביקרו בו מבקרים. אם בכל האתגרים של המערכת מתקיים שהזמן הטוב ביותר הוא 0, אזי זה אומר שכלל לא ביקרו מבקרים בכל המערכת. ----------------------------------------------------------------------------------------------------------- עדכון בהתאם להגדרות המקוריות של התרגיל כדי לאפשר שימוש מודולרי נכון בין הפונקציות – אין כאן שינוי בדרישות של התרגיל לגבי הפעולה room_of_visitor אשר מוגדרת בקובץ room_visitor.h הפעולה הזו יכולה להחזיר גם מצב שגיאה NOT_IN_ROOM במקרה שה-visitor לא נמצא בשום חדר, או, למעשה, לא נמצא במערכת. ----------------------------------------------------------------------------------------------------------- הבהרה – אין שום שינויים בדרישות המקוריות של התרגיל לגבי visitor שמגיע ומבקש לקבל חדר ואתגר – אזי אם הכל תקין וחוקי ויש בחדר המבוקש אתגר פנוי אזי במקרה זה ה-visitor נכנס לחדר ונרשם ברשימה הדינמית של המבקרים במערכת. אם לא ניתן למצוא עבורו אתגר פנוי אזי המבקר לא נכנס לחדר וגם לא נכנס למערכת. כלומר – אין מצב שבו יש מבקר ברשימה הדינמית של ה-system אבל הוא לא נמצא בשום חדר. אם הוא לא נמצא בשום חדר אזי הוא לא נמצא ברשימה הדינמית של ה-system כולו. ----------------------------------------------------------------------------------------------------------- הבהרה – אין שום שינויים בדרישות המקוריות של התרגיל בנוגע ל – Level : איפוס Level – הכוונה לשים שם 0. למעשה – המשמעות היא ברירת מחדל של רמה Easy. לא יינתן טסט שבו יינתן כפרמטר level לא תקין. ----------------------------------------------------------------------------------------------------------- הבהרה – אין שום שינויים בדרישות המקוריות של התרגיל בנוגע לשגיאות אפשריות שהפעולות השונות מחזירות : אם בפעולה מסוימת מתקיימים התנאים להחזרה של יותר משגיאה אחת, אזי השגיאה שתוחזר נקבעת לפי הסדר שבו מפורטות השגיאות האפשריות של הפעולה האמורה כפי שפורסם בקובץ pdf שמגדיר את התרגיל. הערה נוספת : התרגיל שלפנינו הוא תרגיל מצומצם ואינו דורש לכסות את כל מקרי השגיאה האפשריים בכל מצב. צריך לתמוך רק בשגיאות המצוינות בכל פעולה. אין צורך לתמוך בשגיאות אחרות אפשריות שאינן מצוינות. ניתן להניח שמצבים כאלה לא יינתנו בטסטים השונים. כך, למשל – אם משנים שם של חדר – ניתן להניח שלא יינתן שם חדש של חדר שזהה לשם קיים של חדר אחר. ----------------------------------------------------------------------------------------------------------- הבהרה – אין שום שינויים בדרישות המקוריות של התרגיל קובץ האתחול שניתן בפעולת create הוא קובץ תקין לחלוטין מבחינת תוכנו. ניתן להניח זאת. לא צריך לבדוק בו מקרי שגיאה. ----------------------------------------------------------------------------------------------------------- הבהרה – אין שום שינויים בדרישות המקוריות של התרגיל לא ייתכנו מקרים של כפילויות בשמות או במספרים מזהים. אם לא נדרש בפעולות השונות להתייחס למקרים כאלה, אזי לא צריך לטפל בכך וניתן להניח שלא יהיו מקרים כאלה. צריך להתייחס לכך רק בפעולות ששם זה מצוין. למשל – כאשר מגיע מבקר שכבר נמצא במערכת. ----------------------------------------------------------------------------------------------------------- קובץ הטסט לדוגמה challenge_system_test_1.c עודכן. אין שום שינויים בדרישות של התרגיל. העדכונים רלוונטיים לטסטים 1.4 1.9. טסט 1.4 כפי שמוגדר בקובץ הדוגמה challenge_system_test_1.c הטסט צריך להיות r=visitor_arrive(sys, "room_1", "visitor_3", 203, Easy, 8); ASSERT("1.4" , r==ILLEGAL_TIME) כיוון שהשגיאה הראשונה שמפורטת בפעולה זו היא ILLEGAL_TIME. טסט 1.9 כפי שמוגדר בקובץ הדוגמה challenge_system_test_1.c הטסט צריך להיות char *namep=NULL; r=most_popular_challenge(sys, &namep); ASSERT("1.9" , namep!=NULL && strcmp(namep, "challenge_1111")==0) free(namep); כיוון שבוחרים באתגר ששמו הוא הקטן ביותר לקסיקוגרפית. |
מהו סדר הטיפול בשגיאות בפעולה | |
באופן כללי לגבי טיפול בשגיאות צריך לטפל בהן לפי הסדר שמפורט בקובץ עדכון לגבי visitor_arrive() אשר רלוונטית לטיפוס הנתונים ChallengeRoomSystem סדר הטיפול בשגיאות בפונקציה זו צריך להיות ILLEGAL_TIME NULL_PARAMETER MEMORY_PROBLEM ILLEGAL_PARAMETER ALREADY_IN_ROOM NO_AVAILABLE_CHALLENGES כלומר NO_AVAILABLE_CHALLENGES מזוהה רק אם לא קיים מצב של ALREADY_IN_ROOM המימוש של הפונקציה צריך להיעשות באמצעות visitor_enter_room() ולכן סדר השגיאות צריך להיות תואם לגבי MEMORY_PROBLEM הסדר לגבי זיהוי המצב הזה עודכן ב 3 הפעולות visitor_arrive visitor_quit all_visitors_quit נשים לב שבטסטים שיבוצעו למעשה לא ממש ייבדק מצב של MEMORY_PROBLEM אבל צריך להתייחס אליו בקוד. קובץ עודכן בהתאם. בהצלחה ! |
מבחר הבהרות בהתאם לשאלות שנשאלו. | |
--------------------------------------------------------------------- פונקציות עזר שכותבים מופיעות כמובן רק בקבצי c ולא בקבצי h ובעיקרון הן צריכות להיות static הנושא של פונקציות static עדיין לא כלול בחומר של תרגיל הבית הזה ולכן אין הכרח להגדיר אותן static אם כי יותר נכון להגדיר אותן static. מותר להגדיר static בתרגיל הזה. --------------------------------------------------------------------- challenge כפי שמוגדר ב challenge.h ישנם, בין היתר, 2 שדות best_time מתעדכן בכל פעם שמבקר יוצא מחדר מסוים. num_visits מתעדכן בכל פעם שמבקר נכנס לחדר מסוים. העניין של זמן 0 ושל אין מבקרים רלוונטי כאשר רוצים למצוא אתגר עם הזמן הטוב ביותר. ולא לגבי אתגר פופולרי אם, לדוגמה, יש לנו זמן 2 באתגר מסוים ובאתגר אחר יש זמן 0 אזי לצורך חישוב הזמן - זמן 0 נחשב כאילו אין שם מבקרים בכלל ואנו ניקח את 2 בתור הזמן הטוב ביותר. אם בכל האתגרים יש זמן 0 אזי לצורך מציאת האתגר עם הזמן הטוב ביותר זה נחשב כאילו לא ביקרו מבקרים בשום אתגר ואז עבור שם האתגר נקבל NULL מספר המבקרים לגבי הפופולריות נקבע לפי השדה num_visits אשר מתעדכן כאשר מבקר נכנס לחדר, גם אם, עדיין, כמובן, לא יצא ממנו. --------------------------------------------------------------------- |
דיון עקרוני - טיפוסי נתונים בתרגיל בית 2 | |
שלום לכולם ! להלן מספר הבהרות כלליות בנוגע לתרגיל בית 2. אין באמור להלן שינוי כלשהו מהגדרת הדרישות העקרוניות של התרגיל. התיאור המובא כאן בא, בין היתר, כדי להבהיר את מטרותיו הלימודיות של התרגיל ומה אנחנו אמורים ללמוד במהלך הכנתו. התרגיל כולו עוסק בחיזוק הבנתנו ומיומנותנו בכלים חשובים ועיקריים בשפת C ובעיקר : struct pointer malloc - free התרגיל בא להראות כיצד ניתן באמצעות כלים אלה לתמוך בטיפוסי נתונים. במערכות גדולות ומורכבות, אנו מיישמים שיטות של הפשטה, הסתרה וגנריות. בתרגיל הנוכחי עדיין איננו עוסקים בשיטות אלה אלא נותנים את הדגש לעבודה נכונה עם strucrt - ים ומצביעים. בתרגיל הבית הבא אנו נעסוק בהפשטה ובטיפוסי נתונים מופשטים ADT. בתרגיל הבית הנוכחי ישנם למעשה ארבעה טיפוסי נתונים עיקריים : challenge visitor room system וישנו עוד טיפוס שהוא למעשה טיפוס עזר - challenge_activity. לכל טיפוס נתונים מוגדר מנשק של פעולות. הכוונה היא שהשימוש בין טיפוסי הנתונים השונים יהיה מודולרי. טיפוס הנתונים הראשי והעיקרי שלמעשה רק הוא יהיה חשוף למשתמש הוא טיפוס system. טיפוס זה כולל מערך של challenge אשר אורכו ידוע וקבוע מראש ואיננו משתנה מערך של room אשר אורכו ידוע וקבוע מראש ואיננו משתנה לכל room יש, בין היתר, מערך של challenge_activities אשר אורכו ידוע וקבוע מראש ואיננו משתנה. אם כן, כל המערכים שהוזכרו עד כאן נוצרים ע"י פעולות malloc מתאימות בפעולה create_system לאחר הקצאת מערך ה challenge נותר לתחל את כל איבריו בהתאם לאתגרים השונים שמוגדרים במערכת. לשם כך קיימת פעולת init_challenge לאחר הקצאת מערך rooms צריך לתחל כל חדר בנפרד. לשם כך קיימת פעולת init_room פעולה זו תקצה לחדר את המערך של challenge_activities ולאחר מכן תתחל כל איבר של המערך ע"י init_challenge_activity אם כך, כל הרעיון כאן הוא עבודה מודולרית וקישוריות נכונה בין האיברים השונים במערכים השונים ע"י עבודה נכונה עם מצביעים, וזהו הנושא העיקרי של תרגיל הבית הנוכחי - עבודה עם struct-ים ועם מצביעים. נשים לב שבעבודה "נקייה" עם טיפוסי נתונים מופשטים אנו נגדיר, לכל טיפוס נתונים מופשט פעולות create destroy אשר מבצעות בתוכן הקצאה (create) ושחרור (free). בתרגיל הנוכחי טיפוס הנתונים העיקרי והראשי הוא system ובו, אכן, מוגדרות פעולות create destroy בעבודה נכונה אנחנו נמשיך ונגדיר טיפוס זה כטיפוס נתונים מופשט - לא רלוונטי לתרגיל הבית הנוכחי. שאר הטיפוסים בתרגיל זה הם במעמד טיפוסי נתונים - טיפוסי עזר לטיפוס הראשי. גם הם טיפוסי נתונים עם מנשק ברור, אבל בהם הקפדנו פחות על פעולות create destroy והתאמנו את המנשק ביתר נוחות לרלוונטיות של מבנה הנתונים שאיתו אנו עובדים. לטיפוסים אלה ישנן הפעולות init והפעולה reset היא הפעולה ההפוכה לפעולה init לגבי הטיפוס visitor - המערכת צריכה לנהל רשימה דינמית של מבקרים. בניגוד לשאר הטיפוסים - אתגר, חדר, פעילות חדר - רשימת המבקרים היא רשימה דינמית אשר בהתחלה היא ריקה ותוך כדי פעילות המערכת יכולים להתווסף מבקרים או להיגרע מבקרים. מימוש הרשימה הזו יכול להיעשות באמצעות מערך אשר יהיה צריך מפעם לפעם לעדכן את אורכו באמצעות פעולות מתאימות של malloc free או realloc במידת הרלוונטיות ניתן ואפילו מומלץ לממש את הרשימה באמצעות רשימה מקושרת. במנשק הפעולות שמוגדר לטיפוס visitor ישנן הפעולות init_visitor reset_visitor אם מממשים את רשימת המבקרים באמצעות מערך אזי צריך קודם להקצות מערך ואחר כך לתחל את האיברים השונים באמצעות init_visitor שפועלת ברמה של מבקר יחיד. להקפיד על פרמטרים נכונים לפעולה. אם רוצים לנהל את רשימת המבקרים באמצעות רשימה מקושרת, אזי, צריך, עבור כל מבקר, לבצע קודם הקצאה מתאימה לפי טיפוס של איבר ברשימה מקושרת שתגדירו בעצמכם, ולאחר מכן ניתן לתחל את השדה המתאים באיבר הרשימה המקושרת באמצעות init_visitor הפעולה ההפוכה ל init_visitor היא reset_visitor. כאמור, ולסיכום, בתרגיל הבית הזה אנו נותנים יותר דגש על עבודה נכונה ומסיבית עם שדות של struct-ים באמצעות מצביעים וכל זה בסביבה של טיפוסי נתונים שיש ביניהם היררכיה ומודולריות. נשים לב שבטיפוסי נתונים מופשטים אנחנו נממש את הטיפוס כמצביע ל struct ונשתמש ב typedef תרגיל הבית הנוכחי מכין את הרקע לכך, ולעשה, הפונקציות השונות במנשקים השונים אשר מקבלות כפרמטרים טיפוסי נתונים מקבלות אותם באמצעות מצביעים. בתרגיל הבית הבא אנו ניתן שם טיפוס למצביעים הללו באמצעות typedef. תרגיל הבית הנוכחי אמור להיות יחסית מצומצם ולכן הקלנו בנושא ערכי שגיאה בפונקציות השונות. לא דקדקנו בכל מקרי הקצה האפשריים וההתייחסות תהיה רק למקרים אפליקטיביים עיקריים. נשים לב שבמערכות גדולות בדרך כלל נהוג שכל טיפוס נתונים מופשט ADT מספק גם ערכי שגיאה משלו. בתרגיל זה, מתוך הבנה שעדיין איננו עוסקים כאן בהסתרה מלאה וכדי לפשט הסתפקנו בהגדרה כללית של מקרי שגיאה הרלוונטית לכל הטיפוסים. כאמור, ניתן לראות כאן טיפוס נתונים עיקרי system שלמעשה רק הוא חשוף ללקוח המשתמש בתוכנית, ושאר הטיפוסים הם טיפוסי עזר. כל ההתעסקות בטיפוסי נתונים מובילה אותנו לאחד הנושאים המרכזיים ביותר בקורס - טיפוס נתונים מופשט ADT - ועל כך נעסוק בהמשך הקורס. בהצלחה לכל הסטודנטים. |