280 likes | 547 Views
תרגול מס' 14. שאלות ממבחנים - ADT שאלות ממבחנים - BASH. שאלות ממבחנים - ADT. שאלה 1 (מועד ב', אביב 2006).
E N D
תרגול מס' 14 שאלות ממבחנים -ADT שאלות ממבחנים - BASH
שאלות ממבחנים - ADT מבוא לתכנות מערכות - 234122
שאלה 1 (מועד ב', אביב 2006) • מבני נתונים מופשטים - ADT (40 נקודות): לצורך בקרת כניסה למתקן סודי של המוסד הוחלט להקים מערכת המצלמת את פניהם של הבאים למתקן ומאפשרת את כניסתם רק במידה והפנים זוהו כפנים של אחד העובדים. • לכל עובד יש שם ומספר ת"ז (ייחודי). בעת התקנת המערכת יצולם כל אחד מהעובדים ממספר זוויות צילום שונות (יתכן מספר שונה של תמונות לכל עובד) והתמונות יישמרו במערכת. • במנשק ומימוש המערכת נעזר ב-ADT בשם Image המייצג תמונה דיגיטאלית ותומך בין היתר בפעולות הבאות: • imageCopy: הפונקציה מקבלת תמונה ומחזירה העתק שלה • imageDestroy: משחררת את כל משאבי התמונה • imagesSimilarity: מקבלת שתי תמונות ומחזירה מספר ממשי בין 0 ל- 1 המשקף את מידת הדמיון בין התמונות. • ניתן להתייחס אל Image כאל "קופסא שחורה", אין צורךלתאר את מבנה הנתונים או המימוש שלו מבוא לתכנות מערכות - 234122
שאלה 1 (מועד ב', אביב 2006) • סעיף א' (20 נקודות): ממשו את קובץ המנשק של המודול SurveillanceSystem או בקיצור SurSys. על המנשק לתמוך בפונקציות הבאות בלבד: • CreateSurSys: יצירת SurSys. • AddWorker:הוספת עובד חדש למערכת (הפונקציה מקבלת את שמו ות"ז שלו). • AddWorkerImage: הוספת תמונה של עובד הקיים במערכת (מחזירה מספר סידורי לתמונה זו. מספר זה הנו ייחודי לעובד זה בלבד, אולם יתכן כי לעובדים אחרים ישנן תמונות עם מספר סידורי זהה) • RemoveWorker: מחיקת עובד מהמערכת (כולל כל התמונות שלו) • RemoveWorkerImage: מחיקת תמונה של עובד (על-פי ת"ז של העובד והמספר הסידורי של התמונה) • GetWorkerImages: החזרת אוסף כל התמונות של עובד מסוים. • CheckSimilarity: זיהוי עובד על סמך תמונה חדשה (הסבר בהמשך...) • DestroySurSys: הריסת ה-SurSys. • פונקציה מס' 7 מקבלת כפרמטר תמונה (Image) ומספר – threshold בין 0 ל- 1. על פונקציה זו להשוות את התמונה (ע"י שימוש בפונקציה imagesSimilarity) לכל תמונות העובדים שנשמרו במערכת. במידה ונמצאה תמונה שמידת הדמיון שלה גבוהה מה- threshold הפונקציה תחזיר ערך המשקף זיהוי מוצלח. אחרת, הפונקציה תחזיר ערך המשקף חוסר זיהוי. בנוסף, תחזיר הפונקציה בכל מקרה את ת"ז ושמו של העובד עבורו נמצא הדמיון הגדול ביותר. מבוא לתכנות מערכות - 234122
פתרון - סעיף א' • #ifndef SURSYS_H • #define SURSYS_H • #include"image.h" • #include<stdbool.h> • typedefstructSurSys_t *SurSys; • typedefenum{SUR_SYS_SUCCESS, SUR_SYS_FAIL, SUR_SYS_OUT_OF_MEMORY,...} SurSysResult; • SurSysCreateSurSys(); // or SurSysResultCreateSurSys(SurSys *system); • SurSysResultAddWorker(SurSys system, int id, constchar* name); • SurSysResultAddWorkerImage(SurSys system, int id, Imageimage, int* imageId); • SurSysResultRemoveWorker(SurSys system, int id); • SurSysResultRemoveWorkerImage(SurSys system, int id, intimageId); • SurSysResultGetWorkerImages(SurSys system, int id, Image** images, int* imagesSize); • SurSysResultCheckSimilarity(SurSys system, Imageimage, double threshold, • bool* match, int* bestID, char** bestName); • voidDestroySurSys(SurSys system); • #endif מבוא לתכנות מערכות - 234122
שאלה 1 (מועד ב', אביב 2006) • סעיף ב' (20 נקודות): • (8 נקודות) הציגו את מבנה הנתונים של SurSys כפי שיופיע בקובץ SurSys.c, עם כל ההגדרות הנלוות הנדרשות. אין צורך לממש אף פונקציה בסעיף זה. • (9 נקודות) ממשו את פונקציה 7 מסעיף א' על פי מבנה הנתונים שבחרתם בסעיף ב' 1. על המימוש להיות נכון ויעיל. המימוש צריך לתאר את האלגוריתם העיקרי במלואו (בפונקציה אחת או יותר), אין צורך לממש פונקציות מנשק של ADTs בסיסיים וגם לא פונקציות מנשק אחרות של SurSys. • (3 נקודות) ציינו 3 קודי שגיאה אפשריים שונים (ספציפיים ל-SurSys) המוחזרים ע"י פונקציות המנשק (אין לציין "בעיה בהקצאת זיכרון", וגם לא קודי שגיאה של ADT(s)בסיסיים). מבוא לתכנות מערכות - 234122
פתרון - סעיף ב' 1 #include"SurSys.h" #include"set.h" /* the struct of the ADT */ structSurSys_t{ Set workers; }; /* internal struct (not ADT) */ typedefstructWorker_t { intid; char* name; Set workerImages; } Worker; /* internal struct (not ADT) */ typedefstructWorkerImage_t { intid; Imageimage; } WorkerImage; מבוא לתכנות מערכות - 234122
פתרון -סעיף ב' 2 SurSysResultCheckSimilarity(SurSys system, Imageimage, double threshold, bool* match, int* id, char** name) { if (system == NULL || match == NULL || id == NULL || name == NULL || image == NULL) return SUR_SYS_BAD_PARAM; if (threshold < 0 || threshold > 1) return SUR_SYS_INVALID_THRESHOLD; doublemaxSimilarity = 0.0; char* tempName = NULL; SET_FOREACH(Worker, worker, system->workers) { SET_FOREACH(WorkerImage, image, worker->workerImages) { double similarity = imagesSimilarity(image->image, image); if (similarity > maxSimilarity) { maxSimilarity = similarity; *id = worker->id; tempName = worker->name;}}} מבוא לתכנות מערכות - 234122
פתרון - סעיף ב' 2 - המשך if (tempName != NULL) { *name = malloc(strlen(tempName) + 1); if (*name == NULL) returnSUR_SYS_OUT_OF_MEMORY; strcpy(*name, tempName); } *match = maxSimilarity > threshold; returnSUR_SYS_SUCCESS; } מבוא לתכנות מערכות - 234122
פתרון - סעיף ב' 3 • קודי שגיאה אפשריים: • SUR_SYS_INVALID_THRESHOLD • SUR_SYS_IMAGE_DOESNT_EXIST • SUR_SYS_WORKER_ALREADY_EXISTS מבוא לתכנות מערכות - 234122
שאלה 2 • ברשותנו הקובץ student.h המגדיר את המחלקה Student.מכיוון שבמחשב עליו אתם עובדים יש רק מהדר של C ולא של C++, עליכם לכתובADT בשםStudent שיכלול את אותה פונקציונליות כמו המחלקה Student. • עליכם לחלק את הקוד בין שני קבציםstudent_adt.h ו-student_adt.c ולציין איזה חלק של הקוד יכלול כל קובץ. • הניחו שמישהו אחר כבר כתב את course_adt.hושקיים set.hמתאים • אין צורך להקפיד על constcorrectness • אין צורך לממש את הפונקציות מבוא לתכנות מערכות - 234122
שאלה 2 #ifndef STUDENT_H_ #define STUDENT_H_ #include"course.h" #include<set>classStudent{enum { MAX_COURSES = 30 }; char* name; Course *courses[MAX_COURSES]; intnumCourses; doublecalculateAverageGrade(); public:Student(constchar*); ~Student(); voidaddCourse(constCourse&); voidremoveCourse(constCourse&); doublegetAverage() const ; constchar* getName() const ; set<Course> getFailedCourses(); boolisHonorsStudent() const ; friendbooloperator<(constStudent&, constStudent&); // order by name classNoCoursesException {}; // the student has no courses yet classHasAllCoursesException {}; // the student has MAX_COURSES courses classCourseExistsException {}; // the student already took the course classCourseMissingException {}; // the student is not registered to the course};#endif/* STUDENT_H_ */ מבוא לתכנות מערכות - 234122
שאלה 2 – student_adt.h #ifndef STUDENT_H_ #define STUDENT_H_ #include"course_adt.h" #include"set.h" typedefstructstudent_t* Student; typedefenum { STUDENT_SUCCESS, STUDENT_NULL_ARG, STUDENT_OUT_OF_MEMORY, STUDENT_NO_COURSES, STUDENT_HAS_ALL_COURSES, STUDENT_COURSE_EXISTS, STUDENT_COURSE_MISSING } StudentResult; StudentstudentCreate(constchar*); voidstudentDestroy(Student); StudentResultstudentAddCourse(Student, Course); StudentResultstudentRemoveCourse(Student, Course); StudentResultstudentGetAverage(Student, double* result); constchar* studentGetName(Student); StudentResultstudentGetFailedCourses(Student, Set* result); boolstudentIsHonored(Student); intstudentCompare(Student, Student); #endif/* STUDENT_H_ */ מבוא לתכנות מערכות - 234122
שאלה 2 – student_adt.c #include"student_adt.h" #define MAX_COURSES 30 structstudent_t { char* name; Course *courses[MAX_COURSES]; intnumCourses; }; מבוא לתכנות מערכות - 234122
שאלה 3 • נתון מימוש פשוט של רשימה מקושרת (דו-כיוונית) של מספרים שלמים (int) • תזכורת: ברשימה דו-כיוונית לכל צומת יש שני מצביעים - אחד לצומת שאחריו ואחר לצומת אשר לפניו. אם לא קיים כזה צומת אזי המצביע מכיל NULL. typedefstructnode_t *Node;structnode_t{intn;Nodenext;Nodeprevious;}; • כיתבו פונקציה המקבלת רשימה מקושרת שכזו ומסירה ממנה צמתים כך שכל מספר שהופיע ברשימה לפני הרצת הפונקציה מופיע בדיוק פעם אחת ברשימה לאחר הרצת הפונקציה • למשל הרשימה (1 2 2 3 2) תהפוך ל-(1 2 3) לאחר הרצת הפונקציה • הערות: • אין צורך לשמור על סדר כלשהו ברשימה • ניתן להניח כי כל הצמתים של הרשימה הוקצו דינאמית ואינם בשימוש במקום אחר מבוא לתכנות מערכות - 234122
שאלה 3 - פתרון voidremoveByValue(Node head, int n) { for(Nodeptr = head; ptr ; ptr = ptr->next) { if (ptr->n != n) { continue; } if (ptr->previous) { ptr->previous->next = ptr->next; } if (ptr->next) { ptr->next->previous = ptr->previous; } Nodetmp = ptr; ptr = ptr->previous; free(tmp); } } NoderemoveDuplicates(Node head) { for(Nodeptr = head; ptr; ptr = ptr->next) { removeByValue(ptr->next, ptr->n); } return head; } מבוא לתכנות מערכות - 234122
שאלה 4 • נתון פונקציה גנרית (טמפלייט) למיון מערך: template <classT>voidbubble_sort(T* array, int size) { for(int i = 0; i < size; i++) { for(int j = 0; j < size - 1; j++) { if (array[j+1] < array[j]) { T temp = array[j]; array[j] = array[j+1]; array[j+1] = temp;}}}} • מסתבר שבמחשב שברשותנו יש רק מהדר שלC ולא של C++, ועלינו להחליף את כל הקוד הגנרי בC++- בקוד גנרי שיעבור הידור ב-C. • כיצד תראה הפונקציה הגנרית הממיינת מערך ב-C? • שימו לב שהפונקציה אמורה להתאים לכל טיפוס שניתן למיון ולא רק לטיפוסים בסיסיים. • הסבירו כל פרמטר שהפונקציה מקבלת. מבוא לתכנות מערכות - 234122
שאלה 4 - פתרון voidbubble_sort(void** array, int size, int(*compare)(void*, void*)) { for(int i = 0; i < size; i++) { for(int j = 0; j < size - 1; j++) { if (compare(array[j+1],array[j]) > 0) { void* temp = array[j]; array[j] = array[j+1]; array[j+1] = temp; } } } } • פירוש הפרמטרים לפונקציה: • array הוא מערך העצמים כאשר כל איבר הוא מצביע לעצם כלשהו • size הוא גודל המערך • compare הוא מצביע לפונקציה המשווה בין שני עצמים ומחזירה מספר המייצג את הסדר ביניהם (כמו strcmp עבור מחרוזות למשל) מבוא לתכנות מערכות - 234122
שאלה 4 - המשך • נניח שמוגדר הטיפוס הבא המכיל נתוני סטודנט: structstudent_t { intid; char *name; }; typedefstudent_t* Student; • אנו רוצים למיין סטודנטים לפי מספר ת"ז שלהם. מה צריך להגדיר עבור הטיפוס הזה כדי שניתן יהיה להשתמש בפונקציה שכתבנו למיון מערך של סטודנטים? • כתבו את הקריאה לפונקצית המיון ואת הקוד הנדרש כך שקריאה זו תתקמפל. מבוא לתכנות מערכות - 234122
שאלה 4 - פתרון • עלינו לממש פונקצית השוואה מתאימה אשר משווה סטודנטים לפי מספר ת"ז שלהם: intstudentCompare(void* a, void* b) { Student student1 = a; Student student2 = b; return student1->id - student2->id; } • הקריאה לפונקציה (בהינתן מערך וגודלו) תיראה כך: bubble_sort(array, n, studentCompare); מבוא לתכנות מערכות - 234122
שאלות ממבחנים - BASH מבוא לתכנות מערכות - 234122
שאלה 1 • למשה יש מאגר גדול של מסמכים תחת התיקיה docs ובמשך עבודתו הוא צריך פעמים רבות למצוא את כל המסמכים תחת docs המכילים מילה מסוימת. • בכל השאלה יש להניח שאנו ממוקמים בתיקית האב של התיקיה docs. • סעיף א': כתבו פקודת טרמינל יחידה(ניתן להשתמש ב-pipeline) אשר מציגה את שמות הקבצים השונים בתיקיה docs המכילים את המילה "banana" כמילה עצמאית (לא תת מילה). אם אין כאלו קבצים הפקודה אינה מדפיסה כלום. • בסעיף זה אין להשתמש בדגל -l של הפקודה grep. • ניתן להניח שתחת התיקיה docs קיימים מספר קבצים. grep"banana" -w docs/* | cut -d":" -f1 | uniq מבוא לתכנות מערכות - 234122
שאלה 1 - המשך • מסתבר שבגלל ריבוי המסמכים ביצוע הפקודה שהצעתם בסעיף א' לוקח יותר מדי זמן (משה לא ידוע בסבלנותו) ולכן משה חשב על הפתרון הבא: • במקום לחפש את המילה בכל המסמכים בכל פעם מחדש, משה יכתוב תסריט אשר יוצר אינדקס שיאפשר חיפוש מהיר. לאחר קצת חשיבה משה החליט לממש את האינדקס כך: • ליצור את התיקיה index • לכל מילה אשר מופיעה בלפחות מסמך אחד ב-docs יווצר קובץ בשמה תחת התיקיה index אשר יכיל את רשימת הקבצים בהם היא מופיעה • למשל, אם המילה "apple" מופיעה ב-3 מסמכים ב-docs: fruits.txt, monkies.txt ו-juices.txt אז תחת התיקיה index יווצר קובץ בשם apple אשר תוכנו יהיה: monkies.txt fruits.txt juices.txt • סעיף ב': בהינתן אינדקס שכזה תחת התיקיה index, כתבו את הפקודה החדשה להצגת שמות הקבצים השונים המכילים את המילה "banana" כמו בסעיף א' if [[ -f index/banana ]] ; then cat index/banana; fi מבוא לתכנות מערכות - 234122
שאלה 1 - המשך • כתבו את התסריט make-index אשר בונה את התיקיה index כך שתכיל קובץ לכל מילה המופיעה במסמך כלשהו בתיקיה docs. • ניתן להניח שכל המסמכים נמצאיםישירות תחת התיקיה docs (והיאאינה מכילה תיקיות נוספות) make-index • #!/bin/bash • function addToIndex { • whileread -a line; do • forwordin ${line[*]}; do • if[[ ! (-f index/$word )|| ( `grep $1 index/$word` == "" ) ]] ; then • echo$1>> index/$word • fi • done • done • } • mkdir index • forf in `lsdocs`; do • cat docs/$f| addToIndex $f • done מבוא לתכנות מערכות - 234122
שאלה 2 • הינכם נדרשים לכתוב תסריט בשם create_makefile אשר מייצר קובץ Makefile בצורה אוטומטית • יש להניח כי בספריית העבודה קיימים רק קבצי קוד מקור בשפת C (*.h, *.c) • יש להניח כי הקבצים מבצעיםinclude בצורה תקינה ושאין שגיאות תחביר בקבצים • שם המטרה הראשית (קובץ ההרצה) ינתן כפרמטר לתסריט • אין להשתמש בקבצים זמניים • הקובץ שיווצר צריך לעמוד במספר כללים אשר מפורטים בדוגמה ובהמשך מבוא לתכנות מערכות - 234122
שאלה 2 • דוגמה: בספריית העבודה קיימים 4 קבצים – a.c, a.h, b.c, b.h אשר תוכנם נתון להלן • עבור הפרויקט הנתון הרצת הפקודה create_makefileprog תיצור קובץ בשם Makefile בעל התוכן הבא. • שימו לב כי הינכם נדרשים להגדיר מאקרו עבורהקומפיילר ועבור רשימת קבצי האובייקט. • בקובץ הפלט תהיה מטרה עבור כל קובץ ובנוסף מטרהעבור קובץ ההרצה אשר שמה זההלפרמטר שמועברלתסריט. • הנחייה: השתמשו בפלט של הפקודה gcc–MM *.cכדי ליצור שלד ממנו תיצרו את קובץ ה – Makefile. a.c: #include "a.h" int main() { return 0; } a.h: #include <stdio.h> b.c: #include "b.h" void f() { } b.h: #include "a.h" void f(); CC=gcc OBJS=a.ob.o prog: $(OBJS) $(CC) a.ob.o -o prog a.o: a.ca.h $(CC) -c a.c b.o: b.cb.ha.h $(CC) -c b.c מבוא לתכנות מערכות - 234122
שאלה 2 - פתרון create_makefile • #!/bin/bash • function print_makefile { • echoCC=gcc • objs=`gcc -MM *.c | grep ":" | cut -f1 -d":"` • echoOBJS=$objs • echo$1: '$OBJS' • echo' $(CC)' $objs -o $1 • echo • while read –a line; do • echo${line[*]} • echo-n ' $(CC) –c ' • forfin ${line[*]}:2; do • if[[ "$f" = *.c ]] ; thenecho -n "$f " • fi • done • echo • done • } • gcc -MM *.c | print_makefile $1 > makefile מבוא לתכנות מערכות - 234122
בהצלחה במבחנים מבוא לתכנות מערכות - 234122