Directx Δημοσ. 11 Οκτωβρίου 2011 Δημοσ. 11 Οκτωβρίου 2011 Ναι, αυτή την συνάρτηση ψυλλιάζομαι κι εγώ, αλλά στην linetokens_free() έχω βάλει επί τούτου έλεγχο ώστε να κοιτάει αν το linetokens[ i ] δεν είναι NULL πριν επιχειρήσει να το κάνει free(). Από τον debugger μου, πριν την εκτέλεση του: > tokens[0] = strtok(s, delimiters); Η διεύθυνση μνήμης του [0][0] ισούται με 00D03360 όπως έχει αποδοθεί κατά την δέσμευση της από την ρουτίνα linetokens_create. Μετά την εκτέλεση της εντολής tokens[0] = strtok(s, delimiters); η διεύθυνση μνήμης του [0][0] ισούται με 0013FE48 με περιεχόμενο το πρώτο token ("0"). Συνεπώς η strtok έχει αλλάξει το Address του πίνακα, από εδώ αρχίζει το πρόβλημα με την free και έχει συνέχεια διότι ο αρχικά δεσμευμένος πίνακας στην διεύθυνση 00D03360 δεν απελευθερώνεται ποτέ κατά την έξοδο από το πρόγραμμα αφού η free δοκιμάζει να αποδεσμεύσει την 0013FE48 η οποία έχει αποδεσμευτεί από την strtok αφήνοντας την 00D03360 ως ορφανό memory block πλέον. Η strtok δηλαδή δεσμεύει εκ νέου ένα νέο δικό της buffer (σύμφωνα με τον debugger μου) και παίζει σε αυτό κάνοντας overwrite το δικό μας αυθεντικό buffer οπότε μετά ..προβλήματα. Γενικά, προσωπικά χρησιμοποιώ την strtok (λόγο του καταστροφικού της χαρακτήρα) απομονωμένη σε τοπικές μεταβλητές αποφεύγοντας την άμεση απόδοση της σε δυναμικά δεσμευμένη μνήμη (καθώς έχω δει αρκετά bugs με' δαύτη). Υ.Γ. Όλα αυτά σε C++ Builder πάντα.
migf1 Δημοσ. 11 Οκτωβρίου 2011 Δημοσ. 11 Οκτωβρίου 2011 Από τον debugger μου, πριν την εκτέλεση του: > tokens[0] = strtok(s, delimiters); Η διεύθυνση μνήμης του [0][0] ισούται με 00D03360 όπως έχει αποδοθεί κατά την δέσμευση της από την ρουτίνα linetokens_create. Μετά την εκτέλεση της εντολής tokens[0] = strtok(s, delimiters); η διεύθυνση μνήμης του [0][0] ισούται με 0013FE48 με περιεχόμενο το πρώτο token ("0"). Συνεπώς η strtok έχει αλλάξει το Address του πίνακα, από εδώ αρχίζει το πρόβλημα με την free και έχει συνέχεια διότι ο αρχικά δεσμευμένος πίνακας στην διεύθυνση 00D03360 δεν απελευθερώνεται ποτέ κατά την έξοδο από το πρόγραμμα αφού η free δοκιμάζει να αποδεσμεύσει την 0013FE48 η οποία έχει αποδεσμευτεί από την strtok αφήνοντας την 00D03360 ως ορφανό memory block πλέον. Υ.Γ. Όλα αυτά σε C++ Builder πάντα. Μύλος! Οπότε το πρόβλημα λύνεται χρησιμοποιώντας strncpy() αντί για ανάθεση... > strncpy( tokens[0], strtok(s, delimiters), MAXLEN_TOKEN ); και ομοίως και για τα υπόλοιπα tokens (και προφανώς χρειάζονται έξτρα έλεγχοι)... θα το κοιτάξω και θα ενημερώσω. Σε ευχαριστώ EDIT1: Μπα ούτε η strncpy() θα δουλέψει γιατί η strtok δεν τερματίζει με '\0' το token... θέλει παραπάνω δουλειά EDIT2: Ευτυχώς τελικά βάζει null-character η strok() στο τέλος του κάθε token
migf1 Δημοσ. 11 Οκτωβρίου 2011 Δημοσ. 11 Οκτωβρίου 2011 Τελικά χρειάστηκε να φτιάξω και δικιά μου strncpy() γιατί στην αυθεντική όταν το token είναι μεγαλύτερο του MAXLEN_TOKEN δεν το τερματίζει με '\0'. Οπότε ολοκληρωμένη η ANSI έκδοση του κώδικα, που φαίνεται πλέον να δουλεύει απροβλημάτιστα είναι αυτή... > #include <stdio.h> #include <stdlib.h> /* για calloc(), free(), atoi(), atof(), exit() */ #include <string.h> /* για strtok() ... */ #define MAXLEN_LINE 255+1 #define MAXLEN_LINETOKEN 10+1 #define pressENTER() \ do { \ printf("\npress ENTER..."); \ while ( getchar() != '\n' ) \ ; \ } while (0) typedef enum Bool {FALSE=0, TRUE} Bool; // ------------------------------------------------------------------------------------ char *s_ncopy( char *dst, char *src, const size_t n ) { if ( !src ) // early exit conditions return NULL; // ... if ( !dst ) // ... return src; // ... char *save = dst; // save start of dst while ( (dst-save) < n-1 && (*dst++ = *src++) ) // do the copying ; // ... until n-1 or *src == '\0' if ( *dst ) // null-terminate dst *dst = 0; return save; // return saved start of dst } /* ------------------------------------------------------------------------------------- * Count how many tokens are contained in the c-string s, using as separators the chars * found inside delimiters. * * IMPORTANT: * since strtok() breaks the original c-string s, it is advised to pass a copy of * it in this function (otherwise you will loose your original c-string). * ------------------------------------------------------------------------------------- */ int s_tokenscount( char *s, const char *delimiters ) { register int i=0; if ( !s || !delimiters ) return 0; if ( strtok(s, delimiters) == NULL) return 0; for (i=1; strtok(NULL, delimiters) != NULL; i++) ; return i; } /* ------------------------------------------------------------------------------------- */ int s_tokenize( char *s, char *tokens[], const int maxtokens, const int maxtokenlen, const char *delimiters ) { register char *cp = NULL; register int i=0; if ( !s || !tokens || !delimiters ) return 0; cp = strtok(s, delimiters); if (cp == NULL) return 0; s_ncopy( tokens[0], cp, maxtokenlen ); for (i=1; i < maxtokens && (cp=strtok(NULL, delimiters)) != NULL; i++) s_ncopy( tokens[i], cp, maxtokenlen ); return i; } /* ------------------------------------------------------------------------------------- */ float **dis_create( const int ncustomers ) { float **dis = NULL; register int i=0, j=0; dis = (float **) calloc(ncustomers, sizeof(float *) ); if ( !dis ) return NULL; for (i=0; i < ncustomers; i++) { dis[i] = (float *) calloc(ncustomers, sizeof(float) ); if ( !dis[i] ) { for (j=i-1; j > -1; j--) { free( dis[j] ); dis[j] = NULL; } free( dis ); return NULL; } } return dis; } /* ------------------------------------------------------------------------------------- */ void dis_free( float **dis, const int ncustomers ) { register int i = 0; if ( !dis ) return; for (i=0; i < ncustomers; i++) { if ( dis[i] ) { free( dis[i] ); dis[i] = NULL; } } if ( dis ) free( dis ); dis = NULL; return; } /* ------------------------------------------------------------------------------------- */ char **linetokens_create( const int ncustomers, const int maxtokenlen ) { char **linetokens = NULL; register int i=0, j=0; linetokens = (char **) calloc( ncustomers, sizeof(char *) ); if ( !linetokens ) return NULL; for (i=0; i < ncustomers; i++) { linetokens[i] = (char *) calloc(maxtokenlen, sizeof(char) ); if ( !linetokens[i] ) { for (j=i-1; j > -1; j--) { free( linetokens[j] ); linetokens[j] = NULL; } free( linetokens ); return NULL; } } return linetokens; } /* ------------------------------------------------------------------------------------- */ void linetokens_free( char **linetokens, const int ncustomers ) { register int i = 0; if ( !linetokens ) return; for (i=0; i < ncustomers; i++) { if ( linetokens[i] ) { free( linetokens[i] ); linetokens[i] = NULL; } } if ( linetokens ) free( linetokens ); linetokens = NULL; return; } /* ------------------------------------------------------------------------------------- */ Bool memory_reserve( float **prof, float ***dis, char ***linetokens, const int ncustomers, const int maxtokenlen ) { *prof = calloc(ncustomers, sizeof(float) ); if ( !*prof ) return FALSE; *dis = dis_create( ncustomers ); if ( !*dis ) { free( *prof ); *prof = NULL; return FALSE; } *linetokens = linetokens_create( ncustomers, maxtokenlen ); if ( !*linetokens ) { free( *prof ); *prof = NULL; dis_free( *dis, ncustomers ); return FALSE; } return TRUE; } /* ------------------------------------------------------------------------------------- */ void memory_cleanup( float *prof, float **dis, char **linetokens, const int ncustomers ) { if ( prof ) free( prof ); prof = NULL; dis_free( dis, ncustomers ); linetokens_free( linetokens, ncustomers ); return; } /* ------------------------------------------------------------------------------------- */ void print_profits( const int ncustomers, const float *prof ) { register int i = 0; if ( !prof ) return; for (i=0; i < ncustomers; i++) printf("%.2f ", prof[i] ); putchar('\n'); return; } /* ------------------------------------------------------------------------------------- */ void print_distances( const int ncustomers, float **dis ) { register int i = 0, j = 0; if ( !dis || !*dis ) return; for (i=0; i < ncustomers; i++) { for (j=0; j < ncustomers; j++) printf("%.2f ", dis[i][j] ); putchar('\n'); } return; } /* ------------------------------------------------------------------------------------- */ int main( void ) { int ncustomers = 0; /* πλήθος πελατών (1η γραμμή στο αρχείο) */ char line[ MAXLEN_LINE ] = {'\0'}; /* για διάβασμα μιας γραμμής από αρχείο */ float *prof = NULL; /* πίνακας κερδών (2η γραμμή στο αρχείο) */ float **dis = NULL; /* αποστάσεις (υπόλοιπες γραμμές αρχείου)*/ char **linetokens = NULL; /* πίνακας από strings (tokens γραμμής) */ register int i=0, j=0; /* απλοί μετρητές */ /* άνοιγμα αρχείου για διάβασμα */ FILE *infile = fopen("dataRouting.txt", "r"); if ( !infile ) { puts("*** file read error: aborting program..."); pressENTER(); exit( EXIT_FAILURE ); } /* διάβασμα 1ης γραμμής & ανάθεση τιμής στο: ncustomers */ if ( !fgets(line, MAXLEN_LINE, infile ) ) { puts("*** file read error: (line #1), aborting program..."); fclose( infile ); pressENTER(); exit( EXIT_FAILURE ); } ncustomers = atoi( line ); /* δέσμευση δυναμικής μνήμης για τους πίνακές μας */ if ( !memory_reserve( &prof, &dis, &linetokens, ncustomers, MAXLEN_LINETOKEN ) ) { puts("*** out of memory: aborting program..."); fclose( infile ); pressENTER(); exit( EXIT_FAILURE ); } /* διάβασμα αρχείου από την αρχή ανά γραμμή & ανάθεση τιμών στους prof & dis */ rewind( infile ); /* τοποθέτηση στην αρχή του αρχείου */ for (i=0; fgets(line, MAXLEN_LINE, infile); i++ ) { /* αγνόηση 1ης γραμμής */ if ( i == 0 ) continue; /* σπάσιμο γραμμής σε tokens */ s_tokenize(line, linetokens, ncustomers, MAXLEN_LINETOKEN, " \n" ); /* η 2η γραμμή περιέχει τις τιμές για τον πίνακα prof[] */ if ( i == 1 ) for (j=0; j < ncustomers; j++) prof[j] = atof( linetokens[j] ); /* οι υπόλοιπες γραμμές περιέχουν τιμές για τον πίνακα dis[][] */ else for (j=0; j < ncustomers; j++) dis[i-2][j] = atof( linetokens[j] ); } fclose( infile ); /* κλείσιμο του αρχείου */ printf("ncustomers = %d\n", ncustomers ); print_profits( ncustomers, prof ); print_distances( ncustomers, dis ); /* απελευθέρωση της δυναμικά δεσμευμένης μνήμης */ memory_cleanup( prof, dis, linetokens, ncustomers ); pressENTER(); exit( EXIT_SUCCESS ); }
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.