שאלות מראיון ראשון בצורן לתפקיד מהנדס תוכנה לתחום הסלולר
ע"י: admin
שאלות מראיון ראשון בצורן לתפקיד מהנדס תוכנה לתחום הסלולר
1. כתוב MACRO ב- C שמחזיר את המקסימום מבין 2 מספרים
העקרון החשוב בכתיבת Macroים הוא "לרפד" את הפרמטרים בסוגריים כדי למנוע מצבים לא רצויים:
#define MAX_OF_2(X,Y) (((X)>(Y))?(X):(Y))
2. איך היית ממש את זה ב- C++
ב- C++ אפשר להשתמש בפונ' inline:
inline int max_of_2(int x, int y) { return (((x)>(y))?(x):(y)); }
3. אם לא היינו רוצים להגביל את עצמנו ל- int בלבד – איך היינו עושים זאת
ב- C++ אפשר להשתמש ב- Class מסוג Template ואז אפשר "להחליף" ת'int ב- double, float...
4. מה ההבדל בין 2 האפשרויות
באפשרות הראשונה ה- compiler מחליף – טקסטואלית – כל "מופע" ואילו באפשרות השניה מתבצעת החלפה של הקריאה לפונ' ה- inline בקטע הקוד שלה – ואז המשתנים הם לוקליים לפונ' ולא שייכים לבלוק ממנו היא נקראת (בניגוד ל- Macro).
5. איזו אפשרות יעילה יותר
האפשרות הראשונה יעילה יותר מפני שהיא לא מערבת את המחסנית – אלא ישירות לתוך הקוד...
6. מה זה פונ' וירטואלית ובשביל מה זה שימושי
פונ' וירטואלית משמשת אותנו ב- C++ על מנת לממש polymorphism – מגדירים virtual function ב- class שאותו יורשים וממשים את אותה הפונ' בצורה שונה בתוך class "הבן". כעת, אם יש לנו database של מצביעים ל- class מסוג "אבא" שיכולים "להחביא" objectים מסוג "בן"...
7. איך ה- CPU יודע בזמן ריצה לאיזו פונ' לגשת עבור אובייקט מסויים
לכל class יש virtual table שבזמן קומפילציה "מתמלאת" עם כתובות המתאימות של הפונ' האמיתיות של ה class. לכל object יש פוינטר לטבלה הזאת ואז בזמן ריצה ניגשים לטבלה הנכונה ושם יש רק entry אחת שמתאימה לפונ' הזאת...
8. נניח שאתה רוצה עשות אופטימיזציה להקצאות של זיכרון בגודל קבוע
אפשר להקצאות את כל המרחב מלכתכילה וכל פעם ש"מבקשים" בלוק – לתת פוינטר ו"לתעד" את זה ב- database. אפשר לעשות זאת מחסנית שכל הזמן מחזיקה את הפוינטרים לבלוקים ה"פנויים". כשמקצים זיכרון עושים POP למחסנית וכשמשחררים – עושים PUSH.
9. נניח שאתה רוצה לבדוק שהמשתמש (בבלוק) לא "חרג" מגבולות הזיכרון שהוקצה לו – איך תעשה זאת
במקום להקצות בכל פעם X BYTES – נקצה X+20 BYTES ו"נרשום" חתימה מיוחדת שלנו על 10 ה- BYTES הראשונים וגם על 10 ה- BYTES האחרונים. וכך כאשר המשתמש ישחרר ת'בלוק – נוכל לבדוק האם החתימה שלנו עדיין קיימת או שהתבצעה מריחה של הזיכרון (בהזדמנות הזאת אפשר להזכיר reference counters בשביל לעקוב אחר הזיכרון שהוקצה כבר...).
10. נניח שהבלוק בגודל 8 BYTE – זה אומר שלנהל "יעלה" לנו הרבה ביחס לגודל – איך משפרים זאת
מאחר וניתן "להשתמש" בבלוק כל עוד לא הקצו אותו – נשתמש בבלוקים בתור רשימה מקושרת שכל בלוק מצביע לבלוק הפנוי הבא. ככה נוכל לנהל ת'זיכרון ע"י שימוש בזיכרון עצמו...
11. יש מערך של unsigned char. ב- offset 20 יש פוינטר למערך של intים. מצא את האיבר השלישי במערך הintים
העיקרון פה אומר שצריך לזכור שפוינטר הוא 4 BYTES ואילו unsigned char/char הוא רק BYTE 1. אז נשאלת השאלה – אם באיבר עם offset 20 יש פוינטר למערך של int – אז איפה "מתחבאים" עוד 3 BYTES. "מסתבר" שהם מתחבאים בהמשך המערך הראשי (יעני באיברים עם offset 21, 22 ו 23). אז איך עושים זאת (המערך הראשי נקרא arr) – בעיקרון צריך להגדיר פוינטר ל- int ולהעתיק לתוכו 4 BYTES החל מהכתובת עם offset 20 של המערך הראשי – ואז יש לנו את הפוינטר למערך הintים – כעת פשוט מאוד לגשת לאיבר השלישי במערך...
int *ptr2array;
memcpy(arr + 20, &ptr2array, 4);
printf(“Here’s the 3rd element in the array: %d\n”, *( ptr2array+2));