לוגו אתר Fresh          
 
 
  אפשרות תפריט  ראשי     אפשרות תפריט  צ'אט     אפשרות תפריט  מבזקים     אפשרות תפריט  צור קשר     חץ שמאלה ‎print ‎"Hello World!"; if‎ ‎not rules.‎know ‎then rules.‎read(); חץ ימינה  

לך אחורה   לובי הפורומים > מחשבים > תכנות ובניית אתרים
שמור לעצמך קישור לדף זה באתרי שמירת קישורים חברתיים
תגובה
 
כלי אשכול חפש באשכול זה



  #1  
ישן 02-04-2012, 21:35
  CM0S CM0S אינו מחובר  
 
חבר מתאריך: 17.03.02
הודעות: 2,354
שאלה לגבי הקצאות זיכרון ושיחרור ב-C

שלום,

כתבתי את התוכנית הבאה ב-C:

קוד PHP:
 char *strsqz(char *strchar *letters) {
    static 
char *newStr;
    
unsigned int inewLengthwriteIndex;
    
unsigned int bucket[ASCII_LENGTH];

    
/* if NULL is passed as an argument, continue from last result */
    
if(!str) {
        return 
strsqz(newStrletters);
    }

    
/* initialize bucket */
    
for(0ASCII_LENGTHi++)
        
bucket[i] = 0;

    
/* fill */    
    
for(0letters[i] != '\0'i++)
        
bucket[(int)letters[i]]++;

    
/* count length of returned string */
    
for(0newLength 0ASCII_LENGTHi++)
        if(!
bucket[i])
            
newLength++;
    
    
/* allocate memory for new string */
    
newStr = (char *) malloc((newLength) * sizeof(char));
    if(!
newStr) {
        
printf("Memory allocation error. exiting...\n");
        exit (
1);
    }
    
    
/* put characters in place */
    
for(0writeIndex 0str[i] != '\0'i++)
        if(!
bucket[(int)str[i]])
            
newStr[writeIndex++] = str[i];

    
newStr[writeIndex] = '\0';
    
    return 
newStr;



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

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

אשמח לכל עצה,
תודה.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #2  
ישן 02-04-2012, 21:53
צלמית המשתמש של פסטן
  פסטן פסטן אינו מחובר  
 
חבר מתאריך: 14.12.09
הודעות: 9,751
בתגובה להודעה מספר 1 שנכתבה על ידי CM0S שמתחילה ב "שאלה לגבי הקצאות זיכרון ושיחרור ב-C"

מספר נקודות:
  • קודם כל, הלולאה השלישית שלך סופרת כמה תווים שונים יכולים להיות מוצגים. אף אחד לא אמר לך שיש רק אחד מכל תו ב-str. זה אומר שהגודל שאתה מקצה ל-newStr כנראה לא יספיק, וזה אומר שהלולאה האחרונה תגרום ל-buffer overflow...
  • מי שאחראי לעשות free הוא מי שיצרן הספריה מגדיר שצריך לעשות free - שזה אתה, וא המרצה שלך, או הבוס שלך... (אישית, אני לא מבין למה העיצוב הזה טוב בכלל.)
_____________________________________
תמונה שהועלתה על ידי גולש באתר ולכן אין אנו יכולים לדעת מה היא מכילה(קרדיט למרשי)
אמר לה ינאי מלכא לדביתיה אל תתיראי מן הפרושין ולא ממי שאינן פרושין אלא מן הצבועין שדומין לפרושין שמעשיהן כמעשה זמרי ומבקשין שכר כפנחס

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


נערך לאחרונה ע"י פסטן בתאריך 02-04-2012 בשעה 22:10.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #3  
ישן 02-04-2012, 22:35
  CM0S CM0S אינו מחובר  
 
חבר מתאריך: 17.03.02
הודעות: 2,354
בתגובה להודעה מספר 2 שנכתבה על ידי פסטן שמתחילה ב "מספר נקודות: [list] [*]קודם..."

אוי ואבוי, איזו טעות מפגרת
תודה, תיקנתי (פשוט קבעתי את ה-newLength לגודל של המחרוזת המקורית וכל פעם הורדתי ממנה את מספר הפעמים שכל אות מופיעה ב-letters, על פי המידע שיש לי ב-bucket):

קוד PHP:
 #include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define ASCII_LENGTH    255
#define TRUE            1
#define FALSE            0

char *strsqz(char *strchar *letters);


int main() {
    
printf(strsqz("hey, my name is muli and i'm like the wind, i don't know why i just said it but anyways...""xyz"));
    return 
0;
}

char *strsqz(char *strchar *letters) {
    static 
char *newStr;
    
unsigned int inewLengthwriteIndex;
    
unsigned int bucket[ASCII_LENGTH];

    
/* if NULL is passed as an argument, continue from last result */
    
if(!str) {
        return 
strsqz(newStrletters);
    }

    
/* initialize bucket */
    
for(0ASCII_LENGTHi++)
        
bucket[i] = 0;

    
/* fill */    
    
for(0letters[i] != '\0'i++)
        
bucket[(int)letters[i]]++;

    
/* count length of returned string */
    
for(0newLength strlen(str); ASCII_LENGTHi++)
        if(!
bucket[i])
            
newLength -= bucket[i];
    
    
/* allocate memory for new string */
    
newStr = (char *) malloc((newLength) * sizeof(char));
    if(!
newStr) {
        
printf("Memory allocation error. exiting...\n");
        exit (
1);
    }
    
    
/* put characters in place */
    
for(0writeIndex 0str[i] != '\0'i++)
        if(!
bucket[(int)str[i]])
            
newStr[writeIndex++] = str[i];

    
newStr[writeIndex] = '\0';
    
    return 
newStr;



באשר לנקודה השניה, לא הבנתי למה אתה מתכוון ב"אני לא מבין למה העיצוב הזה טוב בכלל" - על מה אתה מדבר, על איך שמיממשתי את הפונקציה?
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
  #4  
ישן 02-04-2012, 22:47
צלמית המשתמש של פסטן
  פסטן פסטן אינו מחובר  
 
חבר מתאריך: 14.12.09
הודעות: 9,751
בתגובה להודעה מספר 3 שנכתבה על ידי CM0S שמתחילה ב "אוי ואבוי, איזו טעות מפגרת..."

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

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

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

אני לא מבין למה כל הסיפור של המשתנה הסטטי וכל הבלאגן מסביב בכלל במקום לבחור באחת הגישות המקובלות.






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

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

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


נערך לאחרונה ע"י פסטן בתאריך 02-04-2012 בשעה 22:50.
תגובה ללא ציטוט תגובה עם ציטוט חזרה לפורום
תגובה

כלי אשכול חפש באשכול זה
חפש באשכול זה:

חיפוש מתקדם
מצבי תצוגה דרג אשכול זה
דרג אשכול זה:

מזער את תיבת המידע אפשרויות משלוח הודעות
אתה לא יכול לפתוח אשכולות חדשים
אתה לא יכול להגיב לאשכולות
אתה לא יכול לצרף קבצים
אתה לא יכול לערוך את ההודעות שלך

קוד vB פעיל
קוד [IMG] פעיל
קוד HTML כבוי
מעבר לפורום



כל הזמנים המוצגים בדף זה הם לפי איזור זמן GMT +2. השעה כעת היא 15:53

הדף נוצר ב 0.09 שניות עם 10 שאילתות

הפורום מבוסס על vBulletin, גירסא 3.0.6
כל הזכויות לתוכנת הפורומים שמורות © 2024 - 2000 לחברת Jelsoft Enterprises.
כל הזכויות שמורות ל Fresh.co.il ©

צור קשר | תקנון האתר