ממש נואש.. שפת C

arik23m

New member
ממש נואש.. שפת C

יש לי בעיה בתוכנית ואני משתגע למה המחשב מציב לי ערך במערך שלא ביקשתי ממנו!!! אנסה קצת לפרט את העניין: יש לי מערך בהקצאה דנמית נניח ARR כשאני מקצה לו מחדש כל פעם INT חדש בREALLOC עד כאן הכל יופי אך באיזה שהוא שלב כאשר אני עוקב אחריו בDEBUG אני רואה שהוא מציב לי ערך שלא ביקשתי ממנו להציב והוא מבצע את זה אחרי פקודה של הקצאת זיכרון למערך אחר! שלא קשור כלל למערך ARR המדובר! איך אני פותר ת´בעיה... שאלו אותי אם חסר מידע או יש צורך להעלות את הקוד.. אנא תגובותיכם.
 

arik23m

New member
אוקיי , הקוד קצת ארוך כמובן...

אני חייב עזרה.. אני מדבר על המערך NetoVarOfB שהוא הבעייתי והמערך השני הוא ArrOfVar שאחרי שאני מבצע לו השמה של num1 מתבצעת השמה גם למערך NetoVarOfB באופן מוזר!! בבקשה פיתרון!!
 

arik23m

New member
אני רק רוצה למקד אותך

אנחנו מדברים על הפונקציה IsSubset כמה מילים על התרגיל עצמו.. אני מקבל כקלט 2 קבצים אחד מהם הוא קבוצה (SET) ואחד מהם הוא יחס (RELATION) שמתאים לקבוצה בפונקציה IsSubsetאני בודק שאכן היחס הוא שייך לקבוצה אותה קיבלתי בקובץ הראשון בנוסף אני אוגר לי את האיברים מתוך הקובץ השני (היחס-קובץ B) בתוך מערך משלי. פעם אחת מערך של איברים כפי שהם מסודרים בקובץ היחס ArrOfVar . פעם אחת ופעם אחת איברים ללא אפשרות לחזרה על איבר שכבר נמצא במערך. NetoOfB. מקווה שלא תרתע מלהכנס לענינים קצת...
 

voguemaster

New member
אוקיי כמה הערות

אז ככה. אני לא רוצה להישמע רע או משהו כזה, אבל הצורה שבה אתה בונה את המערכים ממש לא לעניין. אבל בוא נתעלם מזה לרגע אחד ונתמקד בבעיה של ניהול הזיכרון. הטעות שהפילה אותך היא שימוש לא נכון בפונקציה realloc. בפונקציה realloc אתה אמור להעביר את הגודל החדש של בלוק הזיכרון המבוקש. שים לב לשורה הבאה מהקוד שלך:
ArrOfVar=(int*)realloc(ArrOfVar, sizeof(ArrOfVar)+sizeof(int) );​
יש לך פה באג עצבני. מה שאתה עושה פה הוא להקצות מערך בגודל פוינטר ל-INT ועוד מקום ל-INT נוסף. כשאתה כותב sizeof( ArrofVar), אתה אומר לקומפיילר לקחת את הגודל של המשתנה ArrOfVar, שכידוע לך, הוא מצביע לשלם וגודלו קבוע (4 בתים!!). הטעות לך היא שהנחת ש-sizeof תתן לך את הגודל של המערך ואז רק תיאלץ להוסיף גודל של מספר שלם אחד. לא כך המצב. מה שקורה בפועל זה שההקצאה שלך תמיד מקצה גודל בלוק של מצביע ל-INT ו-INT נוסף, וככל שהמשתנה NumOfB הולך וגדל אתה מתחיל לכתוב למקומות בזיכרון שהם לא המערך שלך (כנראה המערך השני!
). אתה למעשה עובר את סוף המערך. הצורה לפתור את הבעיה היא כזו, בהנחה ש-NumOfB הוא מספר האלמנטים שיש במערך כרגע:
ArrOfVar=(int*)realloc(ArrOfVar, (NumOfB+1) * sizeof(int) );​
מה שיקצה מערך בגודל מספר האיברים שיש לך כרגע בתוכו פלוס אחד. אם יש לך רק מספר אחד במערך, הוא ירצה מערך בגודל 2 מספרים וכיוב´. שמתי לב שאתה עושה את אותה הטעות בשורה נוספת כשאתה רוצה להוסיף את המספר למערך הנטו שלך (שאם הבנתי נכון לא אמור להכיל חזרות של מספרים..) באותה גישה תשתמש במשתנה NetoOfB כדי לחשב את גודל המערך החדש, בדיוק באותו אופן כמו שרשמתי למעלה.. ואם תרצה כמה הצעות לגבי איך לכתוב את זה טוב יותר ונקי יותר, דבר איתי.
בהנחה כמובן שזה מזיז לך..
אלי
 

חובבן

New member
הצעה מכיוון אחר

אם אתה עובד ב ++C תעבור ל <>vector של ה STL זה יפתור לך הרבה בעיות בחיים.
 

arik23m

New member
תמיד פתוח להצעות ייעול../images/Emo70.gif

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

voguemaster

New member
מי כמוני היה שמח אם זה היה כך

תראה לי מקום אחד שבו זה רשום ידידי... אני אוריד את הכובע
 

arik23m

New member
כפי שאמרתי אני כרגע לא ליד המחשב

שלי ואין לי את בורלנד על ידי.. אבל תבדוק שם בhelp אני לא אוהב לדבר כשדברים לא מונחים לי ליד העיניים כמובן כפי שאמרתי יכול להיות שהצדק עמך ואת זה אני אבדוק כשאחזור הביתה. מה בענין ההצעות ייעול שדיברנו עליהם... אני באמת רוצה להשכיל.. talk to me
 

arik23m

New member
למה פה sizeof מחזירה את הערך

הנכון -גודל האמיתי של המערך. זאת הבדיקה שביצעתי. (גודל המערך 10)*2 בתים=20 בתים. לכן הרשתי לעצמי להשתמש בה. (הורדתי את בורלנד רק בשביל לבדוק...
)
 

dror989

New member
לפי דעתי..

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

ke

New member
נראה לי שאתה צודק

שיחקתי עם זה פעם קצת, ויש הבדל בין int a[10] לבין int* b. בראשון a הוא מערך של 10 int-ים ולכן הגודל שלו הוא 10 int-ים, ובשני a הוא מצביע ולכן הגודל שלו הוא כשל מצביע (ולא מה שמוצבע).
 

voguemaster

New member
הגיוני מאוד! ../images/Emo13.gif

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

זה נורא פשוט - ואתם צודקים, אבל רק בשביל להיות פורמליים: SIZEOF מחזירה גודל של *טיפוס* של משתנה - ולא גודל של משתנה. כאשר הקומפיילר נתקל בפונקציה (לא בדיוק פונקציה אבל נניח):
sizeof(myvar)​
הוא בעצם מחזיר את גודל הטיפוס, ולא את גודל המשתנה. כמובן שהוא יודע את גודל הטיפוס, כי כל משתנה ב-C חייב להיות מוגדר. "מצביע ל-X" הוא סוג של טיפוס. גודל כל המצביעים בפלטפורמת WIN32, היא תמיד 32 סיביות. במהלך התוכנית, אפשר לשנות להם את ערך ההצבעה, וכן לבקש הקצאת זיכרון, כך שכתובת הזיכרון החדש תישמר באותו מצביע. אין קשר בין שטח הזיכרון שאליו מכוון המצביע, לבין גודל *הטיפוס* של מצביע. זה שאפשר לכתוב:
int* myarray ... myarray[x]=Y​
זה רק עניין של SYNTAX. השפה מאפשרת לפנות לכל תא בזיכרון דרך אינדקס, בדומה לפניה למערכים רגילים. לעומת זאת, טיפוס מסוג "מערך של Y פעמים הטיפוס X" הוא *אינו* מצביע. הוא משתנה רגיל לכל דבר, ולכן גודל הטיפוס שלו ידוע (Y*גודל הטיפוס X). הערה: רוב הקומפיילרים *כן* מיישמים מערך כזה כמצביע, אבל זהו לא מצביע רגיל שאפשר להתייחס אליו בצורה רגילה, לדוגמה: אי אפשר לשנות את ההצבעה שלו, ואי אפשר להקצות עבורו זיכרון. למעשה הוא כבר מצביע לזיכרון שהוא חלק מזיכרון הקוד של האפליקציה. זוהי הקצאה סטאטית של הקומפיילר. לעומת הקצאה דינמית, שנעשית עבור מצביעים רגילים, אשר מתייחסת לאיזור זיכרון אחר - ה-HEAP.
 
למעלה