מבנים

BravoMan

Active member
אז ככה:

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

נתחיל לפי הסדר:
הפונקציה getname תעבוד, אבל היא עושה דבר מוזר ומיותר: היא מחזירה את הכתובת שקיבלה. למה?
פונקציה gets לא מבצעת הקצאות, היא רק ממלאת את הזיכרון שאתה נותן לה, לכן הכתובת למערך תווים ש-getname קיבלה לא תשתנה בתוך getname.

אז אין שום סיבה ש-getname תחזיר את הכתובת.

הפונקציה add1 תקינה, אבל יש בה כפילות מיותרת של איפוס next.
זה לא מפריע לעבודת התוכנית, אבל בודק עיקש עלול להוריד על זה ניקוד. שים לב שאת next מאפסים בכל מקרה, אז לא חייבים לעשות זאת בשני מקומות שונים.

הבלגן האמתי נמצא בפונקציה add_student, והיא כבר לא תעבוד, ואפילו לא תתקמפל!
השגיאות מתחילות בכותרת הפונקציה: לפרמטר הראשון אין שם, והפרמטר השני כנראה אמור להיות מצביע למערך תווים בשם name אבל בפועל הוא תו בודד בשם nam (בלי e בסוף).

בהמשך, אתה מנסה להשתמש ב-name אבל בפונקציה הזו name לא הוגדר.

ואז מגיע טעות לוגית קטנה, שאומנם לא תשפיע על ריצת התוכנה, אבל היא מיותר לחלוטין, והיא שגורמת לי לחשוב שלא כ"כ הבנת איך עובדים עם מצביעים:
הצורה שבה אתה קורה לפונקציה getname:

name = getname(name);

אין שום סיבה לדבר כזה: כבר שמת ב-name כתובת של זיכרון שהקצאת.
אין שום סיבה לדרוס כתובת זו.
להפך: אם getname היית מחזירה כתובת שונה, בלי לשחרר את המקורית, היית לך דליפה.

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

pitbol3

New member
תודה

אבל האם לא הייתי צריך להתייחס לשני המבנים הנוספים? נניח תתחיל לקרוא מ Slist, זה נראה שכל המבנים קשורים זה לזה... אשמח להסבר על הקשר בין המבנים.

ד"א, אני לא לומד את זה בקורס אלא לומד בעצמי(ונעזר בחומרים של קורסים שונים :p)
 

BravoMan

Active member
תאה צודק! לא שמתי לב שאתה

לא מקצה מקום ל-info (מבנה מסוג student) וישר מנסה להשתמש בו, מה שכמובן לא תקין בעליל ויגרום לקריסה.

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

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

כעיקרון, כשעובדים עם רשימות מקושרות, יש 2 אפשרויות:
האפשרות הפשוטה יותר למימוש אבל גם ה-"מלוכלכת יותר" היא שטיפוס אחד (מבנה) יכיל גם את הנתונים שרוצים לשמור (למשל שדות של שם, גיל וכו') וגם מצביע לאיבר הבא ברשימה שהוא מאותו סוג.

האפשרות השנייה, ויותר נפוצה היא שיש 2 מבנים נפרדים, שמתחלקים בתפקידים.
זו למעשה האפשרות שניסית לממש כאן:
יש מבנה student שהתפקיד שלו זה להחזיק את המידע על הסטודנט עצמו, ויש מבנה slist שתפקידו להחזיק "צומת ברשימה" (או חוליה בשרשרת, או איך שתרצה לקרוא לזה).

המבנה הזה מכיל למעשה רק 2 פריטי מידע:
א) היכן נמצא המידע של הצומת (כלומר, מידע של הסטודנט עצמו).
ב) היכן נמצאת הצומת הבאה ברשימה.

שים לב, ש-slist לא באמת מכיל את student, הוא רק "יודע" איפה המידע הזה נמצא.

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

אצלך, יש עדיין קצת ברדק.

אז הנה מה שאני ממליץ לך לעשות:
תמחק את הפונקציות שכתבת, ותתחיל מחלוקת תפקידים:
1. פונקציה שמייצרת סטודנט חדש.
היא לא צריכה לדאוג לרשימה או מערך, לא אכפת לה כמה סטודנטים יש וכו'.
התפקיד שלה הוא להקצות מקום לשמירת פרטים של סטודנט בודד, לקלוט את המידע עבור סטודנט זה, ולהחזיר למי שקרא לה את הכתובת בה המידע נשמר.

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

2. פונקציות שמנהלות רשימה:
תתחיל עם פונקציית הוספה, אבל בהמשך תוסיף פונקציות למחיקה או שליפה.

פונקציית הוספה, תקבל אובייקט סטודנט מוכן (למעשה כתובת שלו), היא לא תיגע באובייקט עצמו, אלא תעטוף אותו באובייקט רשימה שהיא תיצור ותוסיף אותו למקום הנכון ברשימה.

מקווה שההסבר הזה מובן.
בהצלחה!
 
למעלה