Giorgos3924 Δημοσ. 24 Ιουλίου 2010 Μέλος Δημοσ. 24 Ιουλίου 2010 Για την δυναμική διαχείρισή μνήμης βρήκα ένα πρόγραμμα. Το παρακάτω πρόγραμμα δεσμεύει 10bytes μνήμης. Μετά ζητάει να πληκτρολογηθεί ένα σύνολο χαρακτήρων. Τέλος, εμφανίζει στην οθόνη το σύνολο χαρακτήρων και μετά απελευθερώνει τις θέσεις που δέσμευσε. >#include <stdio.h> #include <stdlib.h> main() { char *k; k=(char *)malloc(10); if(k==NULL) { puts("Den yparxei arketi mnimi gia desmeysi"); exit(2); } gets(k); puts(k); free(k); system("pause"); } Απ' ότι ξέρω, ένας χαρακτήρας καταλαμβάνει 1 byte στη μνήμη. Άρα εδώ μπορούμε να καταχωρήσουμε στον δείκτη k μέχρι 10 χαρακτήρες. Το πρόγραμμα όμως μπορεί να δεχτεί και να τυπώσει περισσότερους από 10 χαρακτήρες. Γιατί συμβαίνει αυτό; Μήπως κατάλαβα κάτι λάθος; Εγώ χρησιμοποιώ το Dev-C++ Πώς μπορώ να δώ πόσα byte δεσμεύει το πρόγραμμά μου για τις λειτουργίες που εκτελεί;
parsifal Δημοσ. 24 Ιουλίου 2010 Δημοσ. 24 Ιουλίου 2010 Ο παραπάνω κώδικας είναι λανθασμένος, από την άποψη ότι δεν ελέγχει αν η είσοδος που θα δοθεί από τον χρήστη χωρά στο δυναμικό k array. Η σωστή προσέγγιση θα ήταν η χρήση της fgets, η οποία παίρνει όρισμα για το πόσους χαρακτήρες το πολύ θα διαβάσει από την είσοδο.
Giorgos3924 Δημοσ. 24 Ιουλίου 2010 Μέλος Δημοσ. 24 Ιουλίου 2010 Σε βιβλίο τον βρήκα τον κώδικα. Η fgets κανονικά δεν διαβάζει από αρχείο;
parsifal Δημοσ. 24 Ιουλίου 2010 Δημοσ. 24 Ιουλίου 2010 Διαβάζει γενικά από εκεί που θα της υποδείξεις μέσω του τρίτου ορίσματός της (τύπου FILE*). Το οποίο μπορεί κάλλιστα να είναι και το standard input (stdin), δηλαδή το πληκτρολόγιο στις περισσότερες των περιπτώσεων. Ρίξε μια ματιά στο documentation της, π.χ.: http://www.cplusplus.com/reference/clibrary/cstdio/fgets/
Giorgos3924 Δημοσ. 24 Ιουλίου 2010 Μέλος Δημοσ. 24 Ιουλίου 2010 Ναι η fgets όμως ζητάει όρισμα για το πλήθος των χαρακτήρων που θα διαβάσει. Είναι λογικό έτσι να μην εμφανίζει περισσότερα απ όσα της λες να διαβάσει μετά. Απλά προσπαθώ να καταλάβω την προηγούμενη λογική. Εφόσον δεσμέυω πχ 10 θέσεις για έναν πίνακα. και στη συνέχεια διαβάζω 20. Όταν εκτυπώνω τον πίνακα πως γίνεται να εκτυπώνει 20 χαρακτήρες; Μήπως κοιτάει το πλήθος των χαρακτήρων και στη συνέχεια δεσμεύει τόσες θέσεις το πρόγραμμα; Αλλά στη malloc λέει ξεκάθαρα ότι δεσμεύουμε 10 bytes.
Evgenios1 Δημοσ. 24 Ιουλίου 2010 Δημοσ. 24 Ιουλίου 2010 Για την δυναμική διαχείρισή μνήμης βρήκα ένα πρόγραμμα.Το παρακάτω πρόγραμμα δεσμεύει 10bytes μνήμης. Μετά ζητάει να πληκτρολογηθεί ένα σύνολο χαρακτήρων. Τέλος, εμφανίζει στην οθόνη το σύνολο χαρακτήρων και μετά απελευθερώνει τις θέσεις που δέσμευσε. >#include <stdio.h> #include <stdlib.h> main() { char *k; k=(char *)malloc(10); if(k==NULL) { puts("Den yparxei arketi mnimi gia desmeysi"); exit(2); } gets(k); puts(k); free(k); system("pause"); } Απ' ότι ξέρω, ένας χαρακτήρας καταλαμβάνει 1 byte στη μνήμη. Άρα εδώ μπορούμε να καταχωρήσουμε στον δείκτη k μέχρι 10 χαρακτήρες. Το πρόγραμμα όμως μπορεί να δεχτεί και να τυπώσει περισσότερους από 10 χαρακτήρες. Γιατί συμβαίνει αυτό; Μήπως κατάλαβα κάτι λάθος; Εγώ χρησιμοποιώ το Dev-C++ Πώς μπορώ να δώ πόσα byte δεσμεύει το πρόγραμμά μου για τις λειτουργίες που εκτελεί; Καλο ειναι εφοσον εχεις δεσμευση μνημη για 10 να μην χρησιμοποιεις παραπανω. Το προγραμμα δε σκαει επειδη στη πραγματικοτητα δεν εχεις δεσμευσει 10 byte, αλλα ζητας απο το tlb να σου δεσμευσει 10 byte η οποια δεσμευει την φυσικη μνημη σε blocks. Ενα οχι και τοσο πετυχημενο παραδειγμα για να παρεις το μεγεθος του μπλοκ ειναι το παρακατω >#include <stdlib.h> typedef unsigned int ptr; int main(int argc, char** argv) { ptr f = (ptr)malloc(1); ptr s = (ptr)malloc(1); printf("Block size:%d",s-f); return 0; } Αλλα καλυτερα να μην προκαλεις overflow γιατι θα εχεις περιεργα προβληματα πχ >#include <stdlib.h> typedef unsigned int ptr; int main(int argc, char** argv) { char* f = (char*)malloc(124); char* s = (char*)malloc(124); memcpy(f+124+60,"lol",4); printf(s); getchar(); return 0; } Και το χειροτερο απ'ολα, μπορεις να σπασει τον heapstruct(ο οποιος βρισκετε πισω απο τον δεικτη) του επομενου δεικτη. Αν το κανεις αυτο θα κρασαρει το προγραμμα στο καλεσμα της free πχ >#include <stdlib.h> typedef unsigned int ptr; int main(int argc, char** argv) { char* f = (char*)malloc(124); char* s = (char*)malloc(124); memcpy(f+124+50,"Paei o heap struct huhuhu 100% tha faw crash",30); free(s); getchar(); return 0; }
imitheos Δημοσ. 24 Ιουλίου 2010 Δημοσ. 24 Ιουλίου 2010 > k=(char *)malloc(10); Αν το πρόγραμμα γίνει compile με έναν C compiler (και όχι με C++ compiler) τότε δεν χρειάζεται το cast (char *) και καλό είναι να αποφεύγεται. > gets(k); Ό,τι είπε ο parsifal. Χρησιμοποίησε fgets αντί για gets. > system("pause"); } Η system("pause") συναντιέται πάρα πολύ συχνά σε προγράμματα που έχουν γραφτεί για Windows ώστε να βλέπεις την έξοδο των προγραμμάτων. Αντί αυτής μπορεί να χρησιμοποιεί η getchar ώστε το πρόγραμμα να παίζει παντού. Απ' ότι ξέρω, ένας χαρακτήρας καταλαμβάνει 1 byte στη μνήμη. Αν μιλάμε για μια μεταβλητή τύπου char, τότε έχεις δίκιο. Καταλαμβάνει 1 byte. Θεωρητικά καταλαμβάνει ένα C byte. Στην C, byte θεωρείται ο χώρος που χρειάζεται για να αποθηκεύσουμε ένα χαρακτήρα. Αυτό το C byte μπορεί να μην έχει 8 bits μέγεθος. Πρακτικά όμως όταν μιλάμε για τους x86/x86_64 επεξεργαστές που έχουμε όλοι, τότε byte == C Byte == 8 bits Ένας σταθερός χαρακτήρας (char literal) π.χ '5', καταλαμβάνει όσο ένα int στην C και όσο ένα char στην C++. Τέλος μια μεταβλητή τύπου wchar_t συνήθως καταλαμβάνει 4 bytes.
parsifal Δημοσ. 24 Ιουλίου 2010 Δημοσ. 24 Ιουλίου 2010 Ναι η fgets όμως ζητάει όρισμα για το πλήθος των χαρακτήρων που θα διαβάσει.Είναι λογικό έτσι να μην εμφανίζει περισσότερα απ όσα της λες να διαβάσει μετά. Απλά προσπαθώ να καταλάβω την προηγούμενη λογική. Εφόσον δεσμέυω πχ 10 θέσεις για έναν πίνακα. και στη συνέχεια διαβάζω 20. Όταν εκτυπώνω τον πίνακα πως γίνεται να εκτυπώνει 20 χαρακτήρες; Μήπως κοιτάει το πλήθος των χαρακτήρων και στη συνέχεια δεσμεύει τόσες θέσεις το πρόγραμμα; Αλλά στη malloc λέει ξεκάθαρα ότι δεσμεύουμε 10 bytes. Όπως είπε και ο Evgenios1, ο κώδικάς σου δεσμεύει μεν 10 bytes για τον k, αλλά τα επιπλέον bytes γράφονται σε χώρο μνήμης που δεν ξέρεις τί, γιατί και πώς μπορεί να χρησιμοποιούνται. Αναλόγως του compiler και του περιβάλλοντος εκτέλεσης, μπορεί να έχεις από φαινομενικά φυσιολογική συμπεριφορά χωρίς crashes (όπως στην περίπτωσή σου) μέχρι segmentation faults και, το χειρότερο (ναι, χειρότερο και από segfaults): σιωπηρή αλλοίωση των τιμών άλλων μεταβλητών και structs που χρησιμοποιείς στο πρόγραμμά σου και άντε βρες μετά γιατί το πρόγραμμα κάνει τα δικά του. Bottom line: Don't do it! Η C δε σε προστατεύει από τέτοια πράγματα και μία μικρή απροσεξία στον κώδικα μπορείς άνετα να σημαίνει ότι μόλις πυροβόλησες τον εαυτό στο στο πόδι. Κώδικας σχετικός με χειροκίνητο memory allocation και deallocation πρέπει να γράφεται με φειδώ και σούπερ προσοχή.
Giorgos3924 Δημοσ. 16 Αυγούστου 2010 Μέλος Δημοσ. 16 Αυγούστου 2010 Καλημέρα! Έχω ένα πρόβλημα στην εγγραφή και ανάγνωση binary αρχείων. Στο παρακάτω πρόγραμμα: >int main() { FILE *fp1,*fp2; char grammata[200]; fp1=fopen("paradeigma.txt","rb"); fseek(fp1,50,0); [color="RoyalBlue"]//Ξεκινώντας από το 50ο byte του αρχείου paradeigma.txt[/color] fread(grammata,10,1,fp1); [color="RoyalBlue"]//Διαβάζουμε τα επόμενα 10 byte[/color] fclose(fp1); fp2=fopen("test.txt","wb"); fseek(fp2,50,0); [color="RoyalBlue"]//Από το 50ο byte του αρχείου test.txt[/color] fwrite(grammata,1,10,fp2); [color="RoyalBlue"]//Ξεκινάμε και γράφουμε τα πρώτα 10 byte του πίνακα grammata[/color] fclose(fp2); system("PAUSE"); } Έστω ότι έχω διάφορους τυχαίους χαρακτήρες και στα 2 αρχεία. Από το ένα αρχείο διαβάζω κάποια byte χωρίς κανένα πρόβλημα. Κατά την εγγραφή των byte που διαβάστηκαν, στο αρχείο test.txt γράφονται οι 10 χαρακτήρες αντικαθιστώντας όμως όλους τους προηγούμενους με κενό. Δηλαδή υπάρχει κενό 50 bytes και 10 χαρακτήρες στο τέλος. Δεν έπρεπε να κρατάει αυτούς τους χαρακτήρες; Γιατί σβήνονται;
parsifal Δημοσ. 16 Αυγούστου 2010 Δημοσ. 16 Αυγούστου 2010 Δεν έπρεπε να κρατάει αυτούς τους χαρακτήρες; Γιατί σβήνονται; Το ανοίγεις σε w(rite) mode: >fp2=fopen("test.txt","wb"); ...αλλά σύμφωνα με τα υπόλοιπα που γράφεις στο μήνυμά σου, θα έπρεπε να το ανοίγεις σε a(ppend) mode για να έχεις τη συμπεριφορά που ζητάς (χμμμ, κι αυτό κανονικά υπό συζήτηση είναι, εξαρτάται από το τί μέγεθος έχει το αρχείο που ανοίγεις σε σχέση με το offset από το οποίο θέλεις να αρχίσεις να γράφεις). fopen [email protected]: "w": Create an empty file for writing. If a file with the same name already exists its content is erased and the file is treated as a new empty file."a": Append to a file. Writing operations append data at the end of the file. The file is created if it does not exist.
imitheos Δημοσ. 16 Αυγούστου 2010 Δημοσ. 16 Αυγούστου 2010 Όπως είπε ο Parsifal επειδή το ανοίγεις σε write κατάσταση, το αρχείο γίνεται truncate ό,τι είχε δηλαδή χάνεται. Για να μην χάνονται τα δεδομένα έχεις δύο μεθόδους: 1) Η κατάσταση append που ανέφερε ο parsifal. > fp2=fopen("test.txt","ab"); Στις περισσότερες libc (τουλάχιστον σε Linux,Free/Net/OpenBSD) οι εγγραφές θα γίνονται στο τέλος ανεξαρτήτως αν έχεις εκτελέσει κάποια fseek πρώτα. Δηλαδή δεν θα γράφει στο byte 50 που θέλεις αλλά στο εκάστοτε τέλος του αρχείου. 2) > fp2=fopen("test.txt","r+b"); Έτσι επιλέγεις ανάγνωση αλλά και εγγραφή. Η θέση εγγραφής αρχικά βρίσκεται στην αρχή του αρχείου. Σε αυτή την κατάσταση μπορείς να γράψεις σε όποιο σημείο θέλεις και όχι μόνο στο τέλος. Υπάρχει όμως ένα πρόβλημα. Το πρότυπο ANSI της C ορίζει πριν από κάθε εναλλαγή μεταξύ ανάγνωσης και εγγραφής πρέπει να υπάρχει μια εντολή αλλαγή θέσης. Δηλαδή δεν μπορείς να κάνεις μια fwrite και αμέσως μετά μια fread. Η υλοποίηση της glibc του Linux και της libc του FreeBSD έχουν σπάσει το πρότυπο και επιτρέπουν την εναλλαγή. Τα Net/OpenBSD τηρούν το πρότυπο οπότε πρέπει να υπάρχει μια fseek έστω και αν δεν κάνει τίποτα, π.χ: > fseek(fp2, 0, SEEK_CUR); Ανάλογα τι λειτουργικό χρησιμοποιείς και κατά πόσο θέλεις να είναι portable το πρόγραμμά σου ή όχι, ακολούθησε την αντίστοιχη πρακτική. Επίσης το "b" είχε νόημα στις εποχές της turbo c σε DOS. Σε όλα τα UNIXοειδή λειτουργικά, είτε το βάλεις είτε όχι δεν παίζει ρόλο. Edit: Αν κρίνω από το system(PAUSE) χρησιμοποιείς Windows. Βρήκα αυτό το url της MS http://msdn.microsoft.com/en-us/library/yeby3zcb%28VS.80%29.aspx που αναφέρει τα εξής: When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. The file pointer can be repositioned using fseek or rewind, but is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. Οπότε και σε Windows ισχύουν όλα όσα είπα πριν εκτός από το θέμα του "b". Για binary κατάσταση χρειάζεται το "b".
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.