שאלה ב- c

crunch

New member
שאלה ב- c

כתבתי תוכנית שפותחת קובץ, קוראת את התוכן שלו וסוגרת אותו. היא חוזרת על זה מספר גדול של פעמים וכל פעם מקצה זכרון ואחרי מספר מסוים של מעברים בלולאה, הקובץ לא נפתח ומופיעה ההודעה שבתוכנית. בלי הקצאת הזיכרון התוכנית עובדת מצוין! יש למישהו מושג למה זה? התוכנית מצורפת.
 
הממ.... אני לא מתכנת C כ"כ, אבל....

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

crunch

New member
לא נראה לי שזה העניין

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

cganir

New member
אם אני זוכר נכון, עבור הקצאה בדוס

מתבצעת ב PAGES בגודל קבוע. המשמעות היא שאם אתה מקצה בית אחד, או 10 בתים, אתה עדיין מקצה PAGE בגודל קבוע (לא זכור לי בדיוק כמה - זה מאד תלוי בסביבת העבודה). אם אתה מקצה 100 פעם בית אחד , בעצם הקצית 100 פעם את גודל ה PAGE, וזה אולי מה שהורס לך.בנוסף חשוב לשחרר את הזכרון שהקצית, אחרת הזכרון פשוט נגמר !
 

cganir

New member
אחרי מבט נוסף בקוד שלך, הוא באמת

לא עושה כלום ! אולי תשנה אותו לקוד הבא ?
#include "stdio.h" #include "alloc.h" main() { FILE *in; int j=100000; while (j--) { char ch; if ((in = fopen("c:\\tc\\1.txt", "rt")) == NULL) { fprintf(stderr, "Cannot open input file.\n"); } while (!feof(in)) { ch=fgetc(in); } fclose(in); } }​
 

crunch

New member
בעניין הוא שהבעייה

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

cganir

New member
איך בדיוק אתה יודע שהבעיה

היא בפתיחת הקובץ ? בנוסף - הכנס את שורת ה ()fclose לתוך הבלוק שמתבצע רק אם פתיחת הקובץ הצליחה. יכול להיות שגם שם יש לך בעיה.
 

crunch

New member
מה שקורה זה שהכל עובד, כלומר

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

voguemaster

New member
כמה הצעות

אני ממליץ לך לבדוק את הערך המוחזר מ-fopen ובמקרה והוא NULL לבדוק את סוג ה-ERROR שקרה. בנוסף, אולי כדאי שתשקול להכניס את fclose לתוך הבלוק רק אם אכן הצלחת לפתוח את הקובץ אחרת אתה מסתכן ב-heap corruption. הסיבה לזה היא ששתי הפונקציות משתמשות ב-open ו-close פנימית, ואלו האחרונות משתמשות בהקצאת זיכרון דינמית (כן כן..) בנוסף, על כל הקצאת זיכרון הספריה שמנהלת הקצאות שומרת בלוק מידע כלשהו. אתה מקצה 100000 פעמים זיכרון, ויכול מאוד להיות שלספריה יש בעיה לטפל בכזאת כמות של הקצאות, לאו דווקא בגלל גודל הזיכרון אלא בגלל המודל של הרשימות המקושרות שמחזיקות את המידע על כל הקצאה. זה פשוט לא יעבוד לך... אני אנסה להריץ בלינוקס ואגיד לך מה קורה..
 

voguemaster

New member
הממ, ניסיתי

תחת לינוקס התוכנית עובדת. אני מניח שזה אכן קשור ליכולת של הספריה להקצות זיכרון. לדעתי ב-DOS פשוט הספריה כבר לא מסוגלת להקצות יותר והקריאה ל-FOPEN נכשלת. ד"א, מה שמפתיע זה שאין קריסה בקריאה ל-feof ול-fclose על מצביע קובץ ששווה ל-NULL כשהקריאה ל-FOPEN נכשלת.. מוזר...
 

crunch

New member
תודה ../images/Emo13.gif

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

voguemaster

New member
עוד הצעות

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

crunch

New member
תגובה

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