Giorgos3924 Δημοσ. 12 Ιουλίου 2010 Μέλος Δημοσ. 12 Ιουλίου 2010 Πρεπει οπωσδηποτε να κανεις parse απο αυτο το format; Δεν σε κατάλαβα. Θέλω απλως να πάρω πίσω τα δεδομένα. Κάθε γραμμή ξεχωρίζεται από # και τα επιμέρους δεδομένα θα μπούνε στους αντίστοιχους πίνακες. Η μεταβλητή της δομής (πίνακας) struct θα αλλάζει για κάθε γραμμή. ---------- Προσθήκη στις 02:57 ---------- Προηγούμενο μήνυμα στις 02:25 ---------- Με τον παραπάνω κώδικα, (ποστ #14) κρεμάει το πρόγραμμα. Δεν ξέρω γιατί.
3c0r1z Δημοσ. 12 Ιουλίου 2010 Δημοσ. 12 Ιουλίου 2010 Εγώ το σκεφτόμουν αλλιώς.Στο αρχείο: >electronica # thesaloniki # 342415134 # 6900000000 # 12.33 # 12/02/2003 # 150E Ξεκινάμε με: >[color="blue"]do {[/color] [color="Green"]ch=fgetc(fp);[/color] [color="Red"]if (ch!='#') metabliti[0].eteria[i]=ch;[/color] [color="blue"] i++;}[/color] [color="Blue"]while (ch!='#');[/color] Μετά από εδώ θα πρέπει να αλλάζει το 2ο μέλος του strutct. Το πρόβλημα είναι πως θα αλλάζει για να πάμε στη δεύτερη λέξη και να τη καταχωρήσουμε στο 2ο πίνακα. Sorry αν δεν κατάλαβα σωστά, αλλά το πρόβλημα σου είναι πως απο την λέξη electronica πας στην thesaloniki; Αν ναι έχεις δοκιμάσει να χρησιμοποιήσεις την strtok; Tο παρακάτω πρόγραμμα δείχνει πως μπορείς να χρησιμοποιήσεις την strtok. Βέβαια δεν είναι η εφαρμογή σου αλλά μπορείς να το πάρεις σαν σκελετό και να το τροποποιήσεις για τις ανάγκες σου: > #include <stdio.h> #include <stdlib.h> #include <string.h> struct books { char eteria[256]; char address[256]; char afm[256]; }; int main() { static const char filename[] = "file.txt"; FILE* file = NULL; struct books* book; book = malloc(sizeof(struct books)); file = fopen(filename, "r"); if(file != NULL) { char line [1024]; int i = 0; while(fgets(line, sizeof line, file) != NULL) { char* pToken = strtok(line, "#"); if(pToken) { strcpy(book->eteria, pToken); i++; while((pToken = strtok(NULL, "#"))) { switch(i) { case 1: strcpy(book->address, pToken); i++; break; case 2: strcpy(book->afm, pToken); i++; break; } } } } fclose(file); printf("company:%s\naddress:%s\nafm:%s\n", book->eteria, book->address, book->afm); } else perror(filename); return 0; } To file.txt περιέχει μόνο την ακόλουθει γραμμή: >nike#ermou#99989899 και η έξοδος είναι η παρακάτω: > company:nike address:ermou afm:99989899 Αν όχι απλά αγνόησε την απάντηση αυτή.
Giorgos3924 Δημοσ. 12 Ιουλίου 2010 Μέλος Δημοσ. 12 Ιουλίου 2010 Τώρα που είδα την switch σκέφτηκα να το κάνω όπως και πριν. Σε έναν ξεχωριστό πίνακα τύπου char να αποθηκεύω γα γράμματα ένα ένα για όσο δεν διαβάζει #. Μετά πάμε στην case 0 και αποθηκεύει τα γράμματα ένα ένα στον πρώτο πίνακα του struct. Αυξάνει το δείκτη της switch κατά 1 (για την επόμενη case) και διαβάζει τα επόμενα γράμματα μετά το # και ξανα κάνει την ίδια διαδικασία. Όλο αυτό μέχρι να ολοκληρωθεί η struct (υπάρχει συνθήκη while στο τέλος) Το πρόβλημα είναι ότι πάλι κρεμάει το πρόγραμμα. Υπάρχει όμως και ένα θέμα. Όταν βρει το # και σταματήσει να διαβάζει, μετά θα ξεκινήσει από το ίδιο σημείο ή θα αρχίσει πάλι από την αρχή της γραμμής;
thanos713 Δημοσ. 12 Ιουλίου 2010 Δημοσ. 12 Ιουλίου 2010 Αφού είναι γνωστό το μέγεθος, γιατί δεν ανοίγεις το αρχείο με rb και να διαβάζεις με fread()?
Giorgos3924 Δημοσ. 12 Ιουλίου 2010 Μέλος Δημοσ. 12 Ιουλίου 2010 Αφού είναι γνωστό το μέγεθος, γιατί δεν ανοίγεις το αρχείο με rb και να διαβάζεις με fread()? Δυαδικό αρχείο; Πολύ καλή σκέψη, όμως, ο πρώτος πίνακας (δηλαδή η πρώτη λέξη του αρχείου) έχει μέγιστο όριο χαρακτήρων 30(χωρίς το /0) η λέξη που θα αποθηκεύσουμε μπορεί να έχει λιγότερα γράμματα. Πώς θα ξέρω μέχρι ποιο byte φτάνει η λέξη; Μπορούμε να μετρήσουμε τα γράμματα με τη fgetc και τη συνθήκη της if όπως πριν. Μετά όμως πως θα βάλουμε την fgetc να ξεκινήσει από το byte που βρήκε #;
thanos713 Δημοσ. 12 Ιουλίου 2010 Δημοσ. 12 Ιουλίου 2010 Θα γράφεις επιτόπου όλη την δομή, απλώς θα γράφονται και σκουπίδια, όταν όμως θα την διαβάζεις, θα διαβάζεις με την fread() πάλι όλη την δομή και θα αποθηκεύονται μόνο όσα σε ενδιαφέρουν...
Giorgos3924 Δημοσ. 12 Ιουλίου 2010 Μέλος Δημοσ. 12 Ιουλίου 2010 Το δυαδικό αρχείο λαμβάνεται ως ένας μονοδιάστατος πίνακας χαρακτήρων; Δηλαδή αν έχω ένα αρχείο txt με 10 γραμμές και 50 χαρακτήρες ανά γραμμή Μπορώ με την fread να διαβάζω μια-μια κάθε γραμμή και να την αποθηκεύω σε έναν πίνακα μιας διάστασης στο πρόγραμμα; Δηλαδή παίρνω την 1η γραμμή, την βάζω στον πίνακα που θέλω κάνω την επεξεργασία και μετά συνεχίζω στην 2η γραμμή κλπ μέχρι το τέλος. Όπως είπα και πριν δεν ξέρω το ακριβές μήκος της γραμμής. Ξέρω το μέγιστο. Απλά θέλω να ξέρω άμα έχω 50 χαρακτήρες ανά γραμμή, 10 γραμμές, και βάλω την fread να διαβάσει 80, θα συνεχίσει στην επόμενη γραμμή ή θα σταματήσει στο 50;
thanos713 Δημοσ. 12 Ιουλίου 2010 Δημοσ. 12 Ιουλίου 2010 Δες εδώ ένα παράδειγμα. Κώδικας για εγγραφή σε αρχείο: >#include <stdio.h> int main() { struct stoixeia { char onoma[20]; char epitheto[30]; }mathites[10]; FILE *fp = fopen("data.txt", "wb"); int i; for (i=0;i<=9;i++) { printf("Dose onoma %dou mathiti: ",i+1); gets(mathites[i].onoma); printf("Dose epitheto %dou mathiti: ",i+1); gets(mathites[i].epitheto); } fwrite(mathites, 1, sizeof(struct stoixeia)*10, fp); fclose(fp); } Κώδικας για ανάγνωση από το ίδιο αρχείο: >#include <stdio.h> int main() { struct stoixeia { char onoma[20]; char epitheto[30]; }mathites[10]; FILE *fp = fopen("data.txt", "rb"); int i; fread(mathites, sizeof(struct stoixeia)*10, 1, fp); for (i=0;i<=9;i++) { puts(mathites[i].onoma); puts(mathites[i].epitheto); } system("pause"); fclose(fp); }
Evgenios1 Δημοσ. 12 Ιουλίου 2010 Δημοσ. 12 Ιουλίου 2010 Δυαδικό αρχείο;Πολύ καλή σκέψη, όμως, ο πρώτος πίνακας (δηλαδή η πρώτη λέξη του αρχείου) έχει μέγιστο όριο χαρακτήρων 30(χωρίς το /0) η λέξη που θα αποθηκεύσουμε μπορεί να έχει λιγότερα γράμματα. Πώς θα ξέρω μέχρι ποιο byte φτάνει η λέξη; Μπορούμε να μετρήσουμε τα γράμματα με τη fgetc και τη συνθήκη της if όπως πριν. Μετά όμως πως θα βάλουμε την fgetc να ξεκινήσει από το byte που βρήκε #; Μαλιστα, εχεις προβλημα με τους Pointers (δε το λεω υποτιμητικα). Λοιπον. το >struct foo{ char a[10]; char b[10]; }; Πιανει 20 byte στην μνημη, και ξερεις οτι το πρωτο γραμμα απο το a βρισκετε στη πρωτη θεση της μνημης. Δλδ εαν το foo βρισκετε στη θεση μνημης 10 το πρωτο γραμμα απο το a θα ειναι στη θεση 10 (το ν στη θεση 10+ν) Με αντιθεση με το >struct foo{ char *a; char *b; }; που πιανει 8 byte (+εξωτερικη data ) και το πρωτο γραμμα δεν αρχηζει απο τη πρωτη θεση της μνημης αλλα αρχηζει απο τη θεση που σου δειχνει το η πρωτη θεση μνημης. δλδ αν το foo ειναι στη θεση 10 τοτε στη θεση 10 θα διαβασεις τη θεση χ στην οποια βρισκετε το πρωτο γραμμα απο το a. Εφοσον το πρωτο παραδειγμα κραταει τα δεδομενα (σε αντιθεση με το δευτερο που κραταει τις θεσεις) μπορεις να τα γραψεις οπος ειναι στη μνημη , μεσα στο αρχειο. Εαν σε μπερδευει το αρχειο δες ενα παραδειγμα που θα γραψω το struct στη μνημη >struct foo { char a[30]; char b[30]; char c[30]; }; void print_b(void *ptr) { printf("%s", ((char*)ptr)+30 ); } int _tmain(int argc, _TCHAR* argv[]) { void* mem = malloc(sizeof(foo)); foo f; strcpy(f.a,"value of a"); strcpy(f.b,"value of b"); strcpy(f.c,"value of c"); memcpy(mem,&f,sizeof(foo)); print_b(mem); free(mem); getchar(); return 0; } Μπορεις να εκτυποσεις ολη την μνημη να δεις ακριβος πως "εφαρμοζει" το struct στη μνημη. Τσεκαρε >void print_mem(void* mem,int size) { char *pr =(char*) mem; for(int i=0;i<size;i++) if(pr[i]=='\0') printf("{Null terminal}"); else printf("%c",pr[i]); } ΥΓ: ΕΙναι σε c++, δε ξερω c, το πως δηλωνονται η struct
V.I.Smirnov Δημοσ. 12 Ιουλίου 2010 Δημοσ. 12 Ιουλίου 2010 Αν πρόκειται για κλάσεις και C++ μπορούν να χρησιμοποιηθούν οι κλάσσεις outstream/ifstream και τα παρελκόμενά τους που γράφουν και διαβάζουν αυτόματα ότι και όπως χρειάζεται χωρίς να απαιτείται μέριμνα από τον προγραμματιστή για τα επιμέρους δεδομένα της κλάσης (serialization).
Giorgos3924 Δημοσ. 13 Ιουλίου 2010 Μέλος Δημοσ. 13 Ιουλίου 2010 Δείτε λίγο αυτό. > do { y=0; do { if (arxeio[x]!='#') word[y]=arxeio[x]; else finder++; y++; x++; } while (arxeio[x]!='#'); [color="Blue"] puts(word);[/color] if (finder==7) { B++; } switch(S) { case 0: { for (i=0;i<31;i++) book[b].eteria[i]=word[i]; S++; break; } case 1: { for (i=0;i<31;i++) book[b].address[i]=word[i]; S++; break; } case 2: { for (i=0;i<31;i++) book[b].afm[i]=word[i]; S++; break; } case 3: { for (i=0;i<31;i++) book[b].thl[i]=word[i]; S++; break; } case 4: { for (i=0;i<31;i++) book[b].time[i]=word[i]; S++; break; } case 5: { for (i=0;i<31;i++) book[b].hmerominia[i]=word[i]; S++; break; } case 6: { for (i=0;i<31;i++) book[b].timi[i]=word[i]; S++; break; } } } while(S>=6); Στον πίνακα χαρακτήρων αποθηκεύω όλους τους χαρακτήρες του αρχείου. Έχω ορίσει μήκος πίνακα arxeio[1200]. Μετά ξεκινάω και παίρνω τις λέξεις σύμφωνα με τα διαχωριστικά #. Ανά 1 # αλλάζει λέξη. Ανά 7 # αλλάζει γραμμή. Η puts(word); που έχω κάτω από τη 1η while βάλει είναι για να δω αν όντως έχω τη ροή που περιμένω κι όμως δεν τρέχει σωστά. Αντί να πάρω όλες τις λέξεις του αρχείου τη μια μετά την άλλη χωρίς # παίρνω απλά μόνο την πρώτη. ---------- Προσθήκη 13-07-2010 στις 00:23 ---------- Προηγούμενο μήνυμα 12-07-2010 στις 20:13 ---------- Προσπάθησα να το κάνω και με τυχαία προσπέλαση του αρχείου. Με αυτή τη μέθοδο θα πρέπει να ξέρω την θέση των # μέσα στο αρχείο. Το παρακάτω πρόγραμμα μου δίνει τη θέση των #. > while (!feof(fp)) { ch=fgetc(fp); read++; if (ch=='#') { point[x]=read; x++; } } Το πρόβλημα είναι ότι παίρνω και αρνητικές τιμές στα ενδιάμεσα του πίνακα. Γιατί το κάνει αυτό; ΑΚΥΡΟ: Είχα βάλει τον πίνακα τύπου char
Giorgos3924 Δημοσ. 23 Ιουλίου 2010 Μέλος Δημοσ. 23 Ιουλίου 2010 Τελικά τελείωσα το πρόγραμμα πριν μια βδομάδα περίπου. Όλα είναι εντάξει αλλά έχω κάποια μικροπροβλήματα. Έχω βάλει κάποια μενού για να κάνω εισαγωγή ανάγνωση διαγραφή και επεξεργασία δεδομένων στο αρχείο. Και το πρόβλημα είναι ότι επειδή ζητάω ακέραιο int αν δώσω χαρακτήρα το πρόγραμμα κολάσει! Αυτό σαν πρώτη φάση το διόρθωσα όταν έβαλα να διαβάζω αριθμούς τύπου χαρακτήρα. Μετά όμως έχω ένα άλλο μενού. Παράδειγμα στη συνάρτηση διαγραφή λέει το πρόγραμμα, επέλεξε την καταχώρηση που θέλεις να διαγράψεις. Και εκεί χρειάζομαι οπωσδήποτε αριθμό τύπου int. Αν έχω 10 καταχωρήσεις απλά επιλέγω πχ την 4η καταχώρηση. Και μετά ξαναγράφω όλα τα δεδομένα και παρακάμπτω την 4η. Αυτό με for και if για έλεγχο. Υπάρχει κάποιος τρόπος για να αντικαταστήσω τους χαρακτήρες σε ακέραιους τύπου int; Όχι όμως αντιστοίχιση με βάση τον ASCII. πχ ο χαρακτήρας 1 να να γίνεται ακέραιος 1 τυπου int και όχι ο αντίστοιχος αριθμός του ASCII. Εκτός αν υπάρχει άλλος τρόπος να αποτρέψω τους χαρακτήρες από το πληκτρολόγιο για να μην κολλάει το πρόγραμμα. Επίσης σκέφτομαι ότι μπορούμε να χειριστούμε τη δομή struct χωρίς πίνακα. Δεν χρειάζεται να δεσμεύουμε απευθείας x θέσεις στον πίνακα της δομής από τη στιγμή που θα χρησιμοποιήσουμε τις 4 ή τις 7. Ή μπορεί να χρησιμοποιήσουμε και περισσότερες. Δεν μπορούμε να λαμβάνουμε τη χειρότερη περίπτωση και να δεσμεύουμε έναν πίνακα με πολλές θέσεις. Το ίδιο και στη δομή. Στο όνομα δεν μπορούμε να δώσουμε μεγάλο περιθώριο για καλύψουμε κάποιον που έχει πολύ μεγάλο όνομα. Σε αυτή την περίπτωση τί μπορούμε να κάνουμε; Σκέφτομαι ότι μπορούμε να χειριστούμε το αρχείο γνωρίζοντας την θέση των διαχωριστικών χαρακτήρων #. Όπως το έκανα και προηγουμένως. Και στη συνέχεια να εκτελούμε την ανάλογη ενέργεια με χρήση τυχαίας προσπέλασης. Στην εισαγωγή μπορούμε να αρχίσουμε από το τέλος για να γράψουμε καινούργια δεδομένα. Στην ανάγνωση διαβάζουμε και εμφανίζουμε στην οθόνη διαδοχικά όλα τα δεδομένα. Στην επεξεργασία όμως το πρόβλημα θα ήταν αν τα καινούργια δεδομένα που αντικαθηστάνε τα παλιά ήταν μεγαλύτερα σε bytes ή και μικρότερα. Αυτό τί θα προκαλούσε; Το ίδιο και στη διαγραφή. πώς θα ξαναγράψω τα παλιά από τη στιγμή που δεν δεσμεύω τα δεδομένα μου στο στη μνήμη του προγράμματός μου τώρα που δεν έχω πίνακα. Ευχαριστώ για τη βοήθεια!
_tasos Δημοσ. 23 Ιουλίου 2010 Δημοσ. 23 Ιουλίου 2010 Για τον έλεγχο της εισόδου από το χρήστη θα πρέπει να κάνεις εσύ τον σχετικό έλεγχο ότι είναι ακέραιος κ όχι κάτι άλλο. Έτσι αφού ξέρεις ότι είναι ακέραιος προχωράς για να κάνεις update και delete. Για το σχετικό έλεγχο θα σου χρειαστεί η isdigit(), ή κάτι αντίστοιχο. Αν θέλεις να αποφύγεις τα προβλήματα χώρου που αναφέρεις στο τέλος, θα σου πρότεινα σε κάθε update ή delete να ξαναγράφεις το αρχείο από την αρχή. Το αποθηκεύεις σε κάποιο temp και μετά το κάνεις rename, διαβάζεις το temp και το γράφεις στο αρχικό. Να σε ρωτήσω γιατί δεν χρησιμοποίησες κάποια database για να κάνεις τη δουλειά σου;
Giorgos3924 Δημοσ. 23 Ιουλίου 2010 Μέλος Δημοσ. 23 Ιουλίου 2010 Δοκίμασα να κάνω επανάληψη με την isdigit. > do { agn=0; fflush(stdin); scanf ("%d",&sedt); if (!isdigit(sedt)) { agn=1; printf("Lathos pliktrologisi!\n"); } } while (agn>=1); Αλλά και όταν πατάω αριθμό πάλι μου τυπώνει το μήνυμα λάθους. Όπως το έχω τώρα, με κάθε update και delete ξαναγράφω το αρχείο. Έχω 10 θέσεις σε ένα πίνακα. σε κάθε θέση πίνακα υπάρχει μια δομή struct με κάποια στοιχεία. Έτσι μπορώ ανά πάσα στιγμή να επεξεργαστώ τα δεδομένα. Απλά θέλω να καταργήσω τον πίνακα για το χειρισμό της δομής struct αφού έχω το αρχείο μπορώ να κάνω ανάγνωση όποια ώρα θέλω, το ίδιο και στη διαγραφή και στην επεξεργασία. Θέλω να επεμβαίνω στο αρχείο για οποιαδήποτε λειτουργία και όχι στον πίνακά μου. Στη διαγραφή σκέφτηκα ότι ίσως μπορώ να διαβάζω όλα δα δεδομένα εκτός αυτά που θέλω να διαγράψω και τα περνάω σε ένα καινούργιο αρχείο. Αλλά θα έχει διαφορετικό όνομα. Στην επεξεργασία αν τα bytes είναι λιγότερα ή περισσότερα θα υπάρξει πρόβλημα;
_tasos Δημοσ. 23 Ιουλίου 2010 Δημοσ. 23 Ιουλίου 2010 Είσαι σίγουρος για την isdigit(); Σου έφτιαξα την isnumber() η οποία κοιτάει αν μία συμβολοσειρά είναι αριθμός. Βασίζεται στην isdigit() και παίζει μια χαρά. > #include <stdio.h> int main(void) { char *s; s = (char *)malloc(sizeof(int)*32); printf("Give character:"); scanf("%s", s); int flag=isnumber(s); if(flag) printf("No number"); else printf("Number"); return; } int isnumber(char *s) { int flag=0; int position=0; while(s[position] != '\0' && flag==0) { if(!isdigit(s[position])) flag=1; position+=1; } return flag; } Τώρα για αυτό που λες για το ότι το 2ο αρχείο θα έχει άλλο όνομα, ναι είναι αλήθεια. Αλλά μπορείς να σβήσεις το 1ο κ να κάνεις rename το 2ο, ή να διαβάσεις το 2ο και να γράψεις στο 1ο όλα τα περιεχόμενα. Μετά σβήνεις το 2ο αρχείο.
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.