שאלית קצת דחופה בC...

  • פותח הנושא neko
  • פורסם בתאריך

neko

New member
שאלית קצת דחופה בC...

מהם בעצם משתנים סטטיים בC? למה הם מועילים? הבנתי שההבדל הוא שהם ממשיכים "להתקיים" אחרי שהפונק' בה הם הוגדרו מסיימת את פעולתה... ומה אם יש משתנה גלובלי בעל אותו שם? האם לא תהייה "דריסה"?
 

ברנדל

New member
בגדול

משתנה סטטי כמשתנה גלובלי הוא בעל אורך חיים של, מרגע יצירתו עד סיום התוכנית. בניגוד למשתנה גלובלי, תחום ההכרה (היכן שהוא מוכר) לא כולל את כל התוכנית אלא רק את הטווח בו הוא מוכר. מכאן שניתן להשתמש בו במקומות שונים והוא ייצג בהם מובנים שונים. הגדרה בתוך קובץ, מחוץ לכל בלוק (כמו גלובלי) המשתנה יוכר רק בתוך הקובץ , לא יוכר בקבצים אחרים. ערכו ישמר כמובן, כערך האחרון שניתן לו. בתוך פונקציה: המשתנה יעבור איתחול רק פעם אחת (בכניסה הראשונה לפונקציה) לאחר מכן בכל כניסה לפונקציה תהיה התעלמות משורת האתחול של הנשתנה. לדוגמא:
int Func() { static int i = 10; ++i; return i; }​
בקריאה השלישית הפונקציה תחזיר 13 ולא 11, כי המשתנה שומר על ערכו (טווח אורך החים שלו הוא עד סיום התוכנית, ולא מתבצע אתחול מחדש. ניתן לנצל עובדה זו גם למובנים אחרים, נניח שיש לך שורת אתחול בפונקציה שאורכת זמן רב, והיא גם קבועה , חבל לך לאתחל כל פעם מחדש לדוגמא
static const double numbers[] = {23,45,56.8,32,11,78,54,77,32};​
הפונקציה כל פעם משתמשת באותו מערך ואין לה צורך לאתחל מחדש. שימוש נוסף שלישי הוא בתוך מחלקה. משתנה סטטי בתוך מחלקה מוכר ע"י כל האוביקטים השייכים למחלקה, אך אינו שייך לשום אוביקט. כידוע כאשר במחלקה יש משתנה כגון int n, הרי כל אוביקט רואה את ה n שהוא מכיר והוא בעל ערך שונה עבור כל אוביקט,לפי הערכים שאותו אוביקט שם לו. משתנה סטטי הוא בעל ערך זהה עבור כל האוביקטים, ממש כמשתנה גלובלי, רק שהוא מוכר רק ע"י אוביקטי המחלקה. ניתן לפנות אליו ע"י אופרטור טווח הכרה , מאתחלים אותו מחוץ למחלקה, ע"י אופרטור זה. ניתן לשנות את ערכו ע"י אופרטור טווח הכרה ללא שיוך לשום אוביקט.
 

neko

New member
../images/Emo51.gif לשניכם (מבחן עוד שעה ../images/Emo5.gif)

 

zagzagzag

New member
ניסיון להסבר

משתנה סטטי שמוגדר בתוך פונקציה, מוקצה על חלק ה-data של התוכנית (לא על המחסנית, כמו משתנים "רגילים"), ולכן הערך שלו ישמר בין קריאות לפונקציה. כאשר מגדירים משתנה גלובלי סטטי, טווח ההכרה שלו יהיה רק עד סוף הקובץ שבו הוא מוגדר (כלומר, אי אפשר לגשת אליו מחוץ לקובץ). לא תהיה דריסה אם תגדיר משתנה סטטי גלובלי ומקומי באותו שם, מאותה סיבה שלא תהיה דריסה אם תגדיר משתנה "רגיל" גלובלי ומשתנה מקומי באותו השם (אני לא בטוח בקשר להסבר הזה...)
 

neko

New member
../images/Emo46.gif../images/Emo7.gif../images/Emo46.gif../images/Emo7.gif../images/Emo46.gif../images/Emo7.gif../images/Emo46.gif../images/Emo7.gif../images/Emo46.gif../images/Emo7.gif../images/Emo46.gif

אוףףףףףףףףףףף!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! איזה מבחן מעצבן. הכל הלך חלק ונחמד, השאלה על המשתנים הסטטיים הלכה נפלא בזכותכם, הכל היה כ"כ טוב... ואז הגיע שאלת תכנות זוועתית! אבל, וזה הקטע הדבילי, היא לא הייתה זוועתית תכנותית, אלא אלגוריתמית (ועוד בקורס שנקרא "סדנת תכנות" ומתיימר להיות כולו בלימוד שפת C ועבודה בUNIX)... אוף. כתוב פונק' המקבלת מערך בגודל N של מספרים שלמים (חיוביים ושליליים), ומחזירה את הסכום החלקי המקסימלי (סכום מקסימלי של כמה איברים צמודים במערך) ואת אינדקס ההתחלה והסיום שלהם (ע"י פויינטרים כמובן). וכל זאת בזמן לינארי... זה הוגן זה????!?!?!??!?
 

DNile

New member
לא יודע לגבי הוגן,

אבל תואר אוניברסאי זה לא משהו שבא בקלות. יישום אלגוריתמים בשפת מחשב לא שווה הרבה אלא אם כן אתה יודע איך ליצור אלגוריתמים כמו שצריך. לגבי השאלה שלך, היא לא נראית לי קשה במיוחד, ובהחלט הגיוני לתת אותה לסטודנט בתואר למדעי המחשב. הפתרון אגב, הוא יחסית פשוט, אתה פשוט מתקדם במערך, סוכם את כל האיברים שהגעת אליהם עד עכשיו, ושומר בצד את האינדקס והערך של התת סדרה המקסימלית. גם אם אתה נתקל במספרים שליליים שמורידים לך כביכול את הסכום, אתה ממשיך לסכום אותם - אלא אם כן הסכום כבר נהיה שלילי. במקרה זה, אתה מתחיל לסכום תת סדרה חדשה, שמתחילה ישר אחרי המספר שממנו הסכום נהיה שלילי. למה זה עובד? תאר לך מצב כזה:
2,5,-1,4,-20​
אמנם תוך כדי התקדמות את מגיע לסכום 7, ואח"כ הוא יורד ל6, אבל ישר אח"כ הוא מגיע ל10, ולכן תת הסדרה המקסימלית היא 4 האיברים הראשונים. לגבי הסיבה שאתה מפסיק לסכום ברגע שאתה מגיע לסכום שלילי: להמשיך לסכום מזה הרגע לא יעזור, כי הסכום השלילי פשוט מוריד לך את התוצאה לדוגמה:
1,2,2,-7,4,5,6​
במקום להוסיף 4 ל-2, ולהיות תקוע עם הסכום 2, עדיף פשוט להתחיל מ4, ואז הסכום הוא 4. מקווה שהסברתי את עצמי מספיק טוב.
 

galh

New member
תהיה כנה...

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

משועמם14

New member
מה ???

לפי מה שאתה אומר, במבחן לא יכולות להיות שאלות מתחכמות, וזה ממש לא נכון. מבחן צריך להיות בנוי בערך בצורה הבאה לפי דעתי - 60% שאלות שמי שפתר תרגילים כל הסמסטר יכול לפתור בלי בעיה, ו 40% שאלות בדיוק בסגנון הנ"ל. אין סיבה שמבחן יהיה קל מידי, צריך לשמור על רמה - ואי אפשר לעשות זאת רק עם שאלות קלות, כמו שאתה מציע.
 

אלדד28

New member
אין שום קשר לשאלות קשות/קלות

זו שאלת "טריק". אם אני הייתי מגיע למבחן הזה, הייתי פותר את השאלה הזו בקלות, אבל תוכניתן אחר שהוא תוכניתן יותר טוב ממני אבל במקרה לא מכיר את השאלה היה עלול לאבד את השאלה הזו סתם. אני מסכים עם הגישה לפיה 60% מהמבחן צריך להיות "החומר" ו-40% מהמבחן צריך להיות הבנתי, אבל בשביל זה לא צריך טריקים. אפשר לעשות שאלות לא טריוויאליות שדורשות הבנה, אבל לא דורשות "ידע מוקדם".
 

אלדד28

New member
אני מסכים.

"שאלות טריוויה" במדעי המחשב הן שאלות שקל נורא לפתור אם אתה יודע את התשובה, וקשה מאוד אם אתה לא יודע אותה.
 

DNile

New member
דווקא את זאת אינני מכיר..

או לפחות אני לא זוכר שנתקלתי בה. אמרו זמן לינארי, אז כמעט ברור שזה צריך להתבצע כשאתה עובר על המערך כולו מספר פעמים קבוע. ישבתי עם דף ועפרון, לקחתי דוגמאות קלט שיכולות להקשות עליי, וחשבתי על האלגוריתם. היה וכן ראיתי את הפתרון לאלגוריתם הזה אי פעם, אני מתנצל בשם התת מודע שלי :) לגבי שלמותו של האלגוריתם - מאחר ולא ניסחתי את זה בצורה אלגוריתמית, אכן היה מקום לא להבין את זה בשלמותו. כשאני אומר שמפסיקים לסכום, זה אומר ש"נגמרה תת סדרה", ואין טעם לסכום את האיברים בתוך התת סדרה הנ"ל עם האיברים שאחריו. זה לא אומר שמפסיקים לסכום. במקרה של 10,20,30-100,100, מפסיקים לסכום אחרי ה100-, כששמרנו בצד את הסכום המקסימלי שהגענו אליו עד עכשיו: 60. ואז סוכמים את ה100, ומחליטים שהתת סדרה הזאת גדולה יותר מהתת סדרה הקודמת שראינו, אז קובעים ש100 הוא הפתרון. אם היה אחרי ה100 איזה -10, לא היינו שומרים בצד את התוצאה 90, כי 100 גדול מ90. אבל אם אחרי ה-10 הזה היה עוד 100, היינו מגיעים ל190, ומחליטים שזאת הסדרה המקסימלית. לגבי 10,20,-10, זה לא שאני מחליט שהסכום של התת סדרה הוא הסכום שהגעתי אליו עד שנאלצתי להפסיק לסכום, אני עדיין מחשב את המקסימום בסדרה, ואם אני רואה שה-10 לא תורם לי, אז אני לא שומר בצד את התת סדרה עד אליו, אבל אני לא מאבד תקווה ומחליט שצריך להפסיק לספור את התת סדרה אחרי -10, כי יכול להיות שאני אמצא אחר כך מספר גדול יותר מ10, שלמעשה תורם לי. ובסופו של דבר, בעיצוב האלגוריתם יש לתת את הדעת למצב שבו כל המספרים שליליים, ולוודא שהאלגוריתם אכן בוחר את המספר השלילי שהכי קרוב ל0 בתור התת סדרה המקסימלית(תת סדרה של איבר אחד).
 

אלדד28

New member
אני עדיין לא מסכים איתך.

את כל השאלות הטריקיות אפשר לפתור לבד. העניין הוא שאם אתה יודע את התשובה עליהן הן לוקחות שניה, ואם לא הן יכולות לקחת גם ימים. גם את אלגוריתם דייקסטרה יכולת להמציא בכוחות עצמך. זה לא שהוא נורא מסובך. זה כמו השאלה של הרובוט שאוסף מטבעות מלוח, ויכול לזוז רק ימינה ולמטה. אז ישבתי עליה במשך כמה שעות והגעתי בכוחות עצמי לתשובה. כשהגעתי לתשובה הבנתי שמישהו שעושה כרגע מבחן במדעי המחשב בחיים לא היה פותר אותה אם הוא לא היה מכיר אותה. אני בדעה שמבחן צריך לבדוק דברים מסוימים, וטריקים זה לא אחד מהם. ואתה יודע מה, מבחן ב-C לא צריך לבחון אותך על פתרון בעיות. בשביל זה יש קורסים באלגוריתמיקה.
 

neko

New member
בדיוק מה שהתכוונתי. מה גם שמבחנים

באלגוריתמיקה (רוב המבחנים) הם בחומר פתוח. השאלה הטריקית הייתה יכולה להיות לגיטימית בתרגיל לבית שיש שבוע לחשוב עליו, אבל במקסימום שעה של מבחן - לא מודד כלום חוץ מהמצב המנטלי הנוכחי של הנבחן. מה לעשות שבאותו רגע לא ממש עלה לי בראש הפתרון. לדעתי, זה נועד לנרמל את הציונים. היה לו ברור שרוב האנשים לא יצליחו, וככה הוא תכנן להשיג ממוצע יפה של 80+- במבחן.
 

אלדד28

New member
מסכים עם כל מילה.

מה לעשות שבתואר הראשון של מדעי המחשב המבחנים מכוונים לממוצע נמוך, משהו בין 70 לבין 80 (טוב, זה תלוי בעצם איפה, בבר-אילן מכוונים ל-120 בערך), ויש גם כמה קורסים מסננים שבהם אם אתה לא מגיע כתוכניתן ותיק אתה כנראה הולך להיכשל (קורסים כמו חישוביות וסיבוכיות, או ++C, או מבני נתונים).
 

אלדד28

New member
מסכים עם כל מילה.

מה לעשות שבתואר הראשון של מדעי המחשב המבחנים מכוונים לממוצע נמוך, משהו בין 70 לבין 80 (טוב, זה תלוי בעצם איפה, בבר-אילן מכוונים ל-120 בערך), ויש גם כמה קורסים מסננים שבהם אם אתה לא מגיע כתוכניתן ותיק אתה כנראה הולך להיכשל (קורסים כמו חישוביות וסיבוכיות, או ++C, או מבני נתונים).
 

neko

New member
DNILE - הפתרון שלך לא מספק...

למשל לסדרה הבאה:
10 20 30 -100 100​
האלג' יסכום 60, יגיע ל-100 ויחזיר 60 כסכום הסופי, בעוד שהיה אמור להחזיר 100. בנוסף, קיימת בעיה עם המשך הסכימה כאשר נתקלים במספר שלילי:
10 20 -10 -50​
לפי האלג' שלך, יסכמו 10 20 ו-10, ואז יוחזר 20 בעוד היה אמור להיות מוחזר 30. אבל את זה אפשר לפתור ע"י החזקת משתנה בנוסף למשתנה הסוכם. בקיצור, השאלה מאד לא הוגנת, בייחוד בהתחשב בכך שהנושא הסכומים החלקיים נלמד בקורס אלגוריתמים בתחילת השנה, והמבחן הוא הקרוב (ככה שעדיין לא חזרתי על זה).
 

neko

New member
סליחה, תיקון: באלג' כמו שתארת אותו,

דווקא המצב הזה היה עובד. המצב שלא היה עובד הוא ההפוך:
100 -150 10 20 30​
היה מוחזר 60 במקום 100.
 

neko

New member
עוד בעיה: למשל הסדרה

20 -10 5​
לפי האלג' שלך, יסכם 20, המינוס-10, ואז 5 (כי לא הגענו לסכום שלילי) ויוחזר 15 במקום 20. בקיצור - השאלה הרבה יותר טריקית ממה שנדמה...
 
למעלה