סיימתי לאחרונה מסלול ראיונות בג'נגו ולצערי לא התקבלתי, בניגוד למה שאנשים רושמים בפורום קיבלתי יחס טוב לאורך כל השלבים, בכל מפגש נציגת HR הציעה שתיה וכיבוד מהמטבח והמראיינים היו נחמדים מאוד.
ראיון ראשון:
מתחיל בראיון HR כללי, קצת הסבר על החברה וקצת שאני אספר על עצמי, לא משהו מיוחד. לאחר מכן שאלת ה-MALLOC הידועה הפיתרון שלי לשאלה:
void* my_malloc(int size)
{
int new_size;
int *p;
if(size<=0)
return NULL;
size+=sizeof(int);
if (new_size%16 == 0)
new_size = size;
else
new_size=((size/16)+1)*16;
if(new_size<=512)
p=(int*)malloc_small(new_size);
else
p=(int*)malloc_big(new_size);
*p=new_size;
p+=sizeof(int);
return (void*)p;
}
void free(void* p)
{
int* tmp = (int*)p;
tmp--;
if(*tmp<=512)
free_small(tmp);
else
free_big(tmp);
}
ראיון שני:
שאלת הטיימרים, בשאלה זו חשוב לשלוט היטב בעבודה עם רשימה מקושרת, חשוב מאוד לדעת ולהבין לעומק את פעילות המיון והמחיקה עם פוינטר לפוינטר, כמו כן חשוב להכיר ולהשתמש ב-STATIC. בהתחלה השאלה מתייחסת למצב שבו ממיינים את הרשימה ורק לאחר מכן מבצעים את הריצה על הרשימה, בהמשך הוא מסבך את השאלה ומוסיף מצב שבו מוסיפים איבר תוך כדי ריצה, התוספת גורמת לכך שיש צורך להגדיר מונה שהוא STATIC בקובץ הפתרון הסופי כולל התוספת נראה כך:
typedef void(*func)(void);
struct timers
{
int time;
func function;
struct timers *next;
};
static int count = 0;
static struct timers *head;
void add_timer(void(*func)(void), int seconds)
{
struct timers** list;
struct timers* new_timer = (struct timers*)malloc(sizeof(struct timers));
if (new_timer == NULL)
return;
new_timer->time = seconds;
new_timer->function = func;
new_timer->next = NULL;
for (list = &head ; *list != NULL ; list = &(*list)->next)
{
if (new_timer->time < (*list)->time)
{
new_timer->next = *list;
break;
}
}
*list = new_timer;
}
void run_timer()
{
struct timers *to_free;
while(head != NULL)
{
to_free = head;
Sleep((head->time) - count);
head->function();
count = head->time;
head = head->next;
free(to_free);
}
}
לאורך הראיון נשאלתי הרבה מאוד על מצביעים, כולל ציור דיאגרמת זכרון, כלומר על מי כל מצביע וכיצד פוינטר לפוינטר עובד.
ראיון שלישי:
בראיון השלישי ניתנה לי הפונקציה:
char* numToString(int a,int b)
{
char buff[100];
sprintf(buff,"<%d , %d>",a,b);
return buff;
}
נשאלתי מה לא נכון לגביה, התשובה היא ש-BUFF משתנה מקומי ולכן ביציאה מהפונקציה עלול להכיל זבל, נתבקשתי להציע דרכים חלופיות כאשר לכל דרך צריך להסביר יתרונות וחסרונות, לדוגמא שימוש ב-MALLOC בפונקציה עצמה, הגדרת ה-BUFF על ידי המשתמש ושליחת ה-BUFF לפונקציה, והפתרון הטוב ביותר הוא הגדרת משתנה סטאטי בקובץ של הפונקציה.
חשוב לשלוט היטב ביתרונות מול החסרונות כגון סיבוך המשתמש, זמני ריצה, הקצאות זכרון מקרי קצה וכו'.
ע"י: בוגר123
לא ראיתי את השאלה מקווה שהתשובה עוד תהיה רלוונטית..
בכל אופן הגודל או ניצול הזכרון אינו מהווה עניין בשאלה, המראיין מחפש שליטה עמוקה בצורת העבודה של C, הבעיה היא כפי שרשמתי קודם, בצורת הקצאה כזאת, הקצאה סטטית בפונקציה, זו הקצאה שנקראת הקצאה מקומית (לוקאלית) הבעיה במצב כזה היא שהמערך BUFF מוקצה על ה- STACK , ברגע שנעזוב את הפונקציה לא ידוע לנו מה קורה בזכרון זה, יכול להיות שבמקרה לא ייפגע אבל מבחינת המחשב אזור זה לא שמור יותר, לכן על מנת להגדיר משתנה כמו מערך בפונקציה יש צורך להקצות אותו דינמית (Malloc) ולהחזיר מצביע לאזור המוקצא.
הבעיה היא בוודאות הנכונה כיוון שדיברנו עליה בראיון והוא אישר שזו הבעיה.
ואני לא לגמרי יודע למה לא התקבלתי... בגדול היה ראיון טוב ועניתי כמעט על הכל נכון, בסוף הוא אמר שהיה ראיון טוב אבל שיש סיכוי שהם רוצים מישהו יותר מנוסה... קצת הזוי בהתחשב בעובדה שמהתחלה ידעו שאני בוגר אוניברסיטה ללא נסיון.
ע"י: 1_אורח_כללי
לפי דעתי הבעיה זאת ההקצאה של הBUFFER
מקצים גודל בלוק של 100 בתים בשביל מחרוזת של מקסימום 24 תווים עבור INT
לכן ביציאה מהפונקציה בקריאה מרובה בשביל להרכיב מחרוזת קצרה תפסת מקום מאוד גדול בזכרון ויש פה ניצול גרוע של שכבות הזכרון,
לכן לאחר הקריאה לפונקציה sprint הייתי מזין את האורך של המחרוזת לתוך משתנה לוקלי חדש
ואז בעזרת הקצאה דינמית יוצר buffer חדש באורך הרצוי בשביל המחרוזת ומשחרר את הbuffer המקורי מהזכרון לאחר שהעתקתי בין המחרוזות בעזרת strcpy או לולאה.
אשמח לחוות דעתך :]
ע"י: 1_אורח_כללי
היי,
למה בראיון השלישי אתה טוען שהבעיה היא בbuf?
הוא אכן משתנה מקומי ומכיל זבל עד לקריאה של sprint ולאחריה הוא יכיל את המחרוזת הרצויה כולל את האיבר NULL בסוף המערך ולכן buff הוא מצביע לתחילת המערך HENCE לתחילת המחרוזת ולכן בחזרה מהפונקציה הוא איננו זבל אלא כתובת בזכרון שבה מאוחסנת המחרוזת!
למה דרך אגב לא עברת את הראיון השלישי?
ע"י: בוגר123
זה צריך להיות size%16....
בנוגע לשאלה- אומרים לך שבמערכת מסויימת אין malloc , free
אלא יש : os_malloc_big , os_malloc_small , free_big , free_small
אתה צריך לבנות פונקציה שמקצה ופונקציה שמשחררת, הטיפוס BIG מתייחס לגדלים שגדולים מ-512 בתים. צריך לשים לב ששומרים מקום בגודל 4 בתים בהתחלה על מנת לשמור שם את גודל ה-MALLOC, כדי שפונקציית FREE תדע איזה גודל היא משחררת
ע"י: 1_אורח_כללי
היי,
תוכל לכתוב בבקשה מה הייתה שאלת ה-MALLOC.
דרך אגב, נראה שאתה בודק האם שארית החלוקה של new_size ב-16 שווה אפס, עוד לפני שאתחלת את new_size????
תודה