makis89 Δημοσ. 8 Ιανουαρίου 2008 Δημοσ. 8 Ιανουαρίου 2008 Καλημέρα....Θα ήθελα τη βοήθειά σας ... Θέλω να γράψω ένα πρόγραμμα στη c που θα ανοίγει ένα αρχείο txt το οποίο θα είναι στην ακόλουθη μορφή: 12345,fdafaaf,sdfsaf Δηλαδή θα έχουμε int,string,string Εγώ θέλω να διαβάσω κάθε αντικείμενο ανάμεσα στα κόμματα χωριστά. Για παράδειγμα θέλω τον ακέραιο να τον αποθηκεύσω σε μία μεταβλητή, το fdafaaf σε ένα string κλπ Αυτό που ρωτάω είναι πώς μπορώ να πάρω κάθε αντικείμενο που βρίσκεται ανάμεσα σε κόμματα ; Σκέφτηκα να περάσω όλη τη γραμμή σε ένα string, και με ένα for να ξεχωρίσω κάθε τι που είναι ανάμεσα στα κόμματα...αλλά μήπως υπάρχει καμιά πιο εύκολη λύση ; Ευχαριστώ !
bokarinho Δημοσ. 8 Ιανουαρίου 2008 Δημοσ. 8 Ιανουαρίου 2008 Καλημέρα....Θα ήθελα τη βοήθειά σας ... Θέλω να γράψω ένα πρόγραμμα στη c που θα ανοίγει ένα αρχείο txt το οποίο θα είναι στην ακόλουθη μορφή: 12345,fdafaaf,sdfsaf Δηλαδή θα έχουμε int,string,string Εγώ θέλω να διαβάσω κάθε αντικείμενο ανάμεσα στα κόμματα χωριστά. Για παράδειγμα θέλω τον ακέραιο να τον αποθηκεύσω σε μία μεταβλητή, το fdafaaf σε ένα string κλπ Αυτό που ρωτάω είναι πώς μπορώ να πάρω κάθε αντικείμενο που βρίσκεται ανάμεσα σε κόμματα ; Σκέφτηκα να περάσω όλη τη γραμμή σε ένα string, και με ένα for να ξεχωρίσω κάθε τι που είναι ανάμεσα στα κόμματα...αλλά μήπως υπάρχει καμιά πιο εύκολη λύση ; Ευχαριστώ ! Καλημέρα ο παρακάτω κώδικας ανοίγει ένα αρχείο κειμένου το οποίο βρίσκεται στην μορφή που μας έδωσες και τεμαχίζει τα περιεχόμενα κάθε γραμμής με βάση το "," αποθηκεύοντας τα επιμέρους κομμάτια σε ένα πίνακα δομών για ξεχωριστή προσπέλαση κάθε φορά. Έτσι αποθηκεύω αλλού τον αριθμό, αλλού το πρώτο string και αλλού το δεύτερο string. To περιβάλλον υλοποίησης είναι ο C++ Builder 2007 σε Windows XP Pro SP2. > //--------------------------------------------------------------------------- #include <stdio.h> #include <string.h> #include <stdlib.h> #define BUFSZ 256 #define TOKENS 3 /* Seperator. */ const char *seperator = ","; typedef struct _Line { int LineNumber; char *LBuffer; char *NLBuffer; }Line; #pragma hdrstop //--------------------------------------------------------------------------- /* Functions. */ void _perror(const char *Msg) { printf("ERROR:%s\n", Msg ? Msg : "NULL Message."); } int GetLineFromFile(const char *filename, int *Cnt, Line **ptrLine) { if(!filename) { _perror("Invalid File Name."); return -1; } else { FILE *fileptr = NULL; if((fileptr = fopen(filename, "rt")) == NULL) { _perror("Open File."); return -2; } else { /* Basic Variables. */ char *tokenPtr = NULL; char *TBuffer = NULL; Line *Lineptr = NULL; /* Case Status. */ int nCase = 0, jDx = 0; /* Error Checking. */ static int nError = 0; /* Get Memory. */ if((TBuffer = calloc(BUFSZ, sizeof(char))) == NULL) { _perror("Memory Fault."); /* Close File. */ fclose(fileptr); return -3; } if((Lineptr = malloc(sizeof(Line))) == NULL) { _perror("Memory Fault."); /* Free memory. */ free(TBuffer); fclose(fileptr); return -4; } else { while(fgets(TBuffer, BUFSZ, fileptr) != NULL) { if(TBuffer[strlen(TBuffer)-1] == '\n') TBuffer[strlen(TBuffer)-1] = '\0'; tokenPtr = strtok(TBuffer,seperator); if(!tokenPtr) { nError = 1; _perror("Invalid Text Line Type."); break; } else { while(tokenPtr && nCase < TOKENS) { switch(nCase) { case 0: sscanf(tokenPtr, "%d", &Lineptr[jDx].LineNumber); break; case 1: Lineptr[jDx].LBuffer = strdup(tokenPtr); break; case 2: Lineptr[jDx].NLBuffer = strdup(tokenPtr); break; default: break; } tokenPtr = strtok(NULL, seperator); /* Advance Case Status. */ nCase++; } } /* Advance jDx. */ jDx++; /* Zero nCase. */ nCase = 0; /* Clear TBuffer. */ memset(TBuffer, 0 , strlen(TBuffer)); /* Realloc Line. */ Lineptr = realloc(Lineptr, (jDx+1) * sizeof(Line)); } if(nError) { free(TBuffer); free(Lineptr); fclose(fileptr); return -4; } /* EXIT SUCCESS. */ else { /* Return Values. */ *ptrLine = Lineptr; *Cnt = jDx; free(TBuffer); fclose(fileptr); return 0; } } } } } #pragma argsused int main(int argc, char* argv[]) { int i,nCnt = 0; Line *ptrLine = NULL; if(!GetLineFromFile("file.txt", &nCnt, &ptrLine)) { for(i = 0; i < nCnt; i++) printf("NumberRead:%d\nFirstStringRead:\"%s\"\nSecondStringRead:\"%s\"\n\n" , ptrLine[i].LineNumber, ptrLine[i].LBuffer, ptrLine[i].NLBuffer); } printf("Hit Enter to continue..."); getchar(); return 0; } //--------------------------------------------------------------------------- Για να τρέξεις το πρόγραμμα δημιούργησε ένα άδειο project σε C, κάνε copy-paste στο άδειο αρχείο του project και δημιούργησε στο φάκελο Debug του project ένα αρχείο με το όνομα file.txt και δώσε του πληροφορίες. Παράδειγμα Αρχείου file.txt: 3,nikos,androu 12,antwnis,sparoy 345,fddds,ghhhssgfg 1256,kwstas,boka Εκτυπωμένα αποτελέσματα για το παράδειγμα αρχείου: NumberRead:3 FirstStringRead:"nikos" SecondStringRead:"androu" NumberRead:12 FirstStringRead:"antwnis" SecondStringRead:"sparoy" NumberRead:345 FirstStringRead:"fddds" SecondStringRead:"ghhhssgfg" NumberRead:1256 FirstStringRead:"kwstas" SecondStringRead:"boka" Hit Enter to continue... Bokarinho!!!
georgemarios Δημοσ. 8 Ιανουαρίου 2008 Δημοσ. 8 Ιανουαρίου 2008 αν ξέρεις πως κάθε γραμμη ειναι στανταρ της μορφης πχ <int>,<string>,<string> μπορεις να χρησιμοποιησεις την sscanf ως εξης > // μη ξεχάσεις τα κόμματα αναμεσα στα %d,%s etc sscanf( buffer, "%d,%s,%s", &intVar1, stringVar1, stringVar2); όπου buffer ειναι η μεταβλητη που εχει τη σειρα που διαβασες από το αρχειο, intVar1, stringVar1 κτλ ειναι οι μεταβλητες στις οποιες θες να αποθηκευεσεις τις τιμες αναμεσα στα κομματα. επαναλαμβάνεις για οσες γραμμες του αρχειου θες
makis89 Δημοσ. 8 Ιανουαρίου 2008 Μέλος Δημοσ. 8 Ιανουαρίου 2008 Ευχαριστώ πολύ και τους δύο... Τελικά το έκανα έτσι: sscanf( buffer, "%d,%s,%s", &intVar1, stringVar1, stringVar2); Βέβαια χρησιμοποίησα δομές αντί για μεταβλητές αλλά αυτό είναι άλλο
makis89 Δημοσ. 9 Ιανουαρίου 2008 Μέλος Δημοσ. 9 Ιανουαρίου 2008 Τελικά έχω ακόμα πρόβλημα... Στο .txt μου έχω μέσα int,string,string,string,string,int,int Στην sscanf βάζω "%d,%s,%s,%s,%s,%d,%d" αλλά δεν κάνει σωστά τις αντιστοιχίες. Πχ το πρώτο int το βάζει στο αντίστοιχό του αλλά μετά, τα υπόλοιπα string τα βάζει σε ένα. Ενώ όταν αντικαταστήσω τα κόμματα με κενά δουλεύει κανονικότατα Τί μπορεί να φταίει ;
makis89 Δημοσ. 11 Ιανουαρίου 2008 Μέλος Δημοσ. 11 Ιανουαρίου 2008 Κάποια βοήθεια ρε παιδιά κάποιος ;; Κάποιος άλλος τρόπος για να κάνω αυτό που προσπαθώ ; Ευχαριστώ για την οποιαδήποτε βοήθεια...
bokarinho Δημοσ. 11 Ιανουαρίου 2008 Δημοσ. 11 Ιανουαρίου 2008 Η λογική η δική μου με το πρόγραμμα που σου έγραψα δεν σε ικανοποιούσε; Με λίγες μικρές μετατροπές μπορείς να κάνεις εύκολα αυτό που θες χωρίς να χρησιμοποιήσεις την sscanf. Τώρα δική σου υπόθεση είναι το τι θα πράξεις.
georgemarios Δημοσ. 11 Ιανουαρίου 2008 Δημοσ. 11 Ιανουαρίου 2008 λοιπον μια αλλη προσεγγιση παρνεις μια γραμμη απο το αρχειο καθε φορα με την fgets > FILE* fPtr; char linebuffer[100]; // maximum line length 100-1 char* tmp; ... tmp = fgets(lienbuffer,100, fPtr); ... αν το tmp==NULL τοτε εφτασε στο EOF χωρις να διαβαστει χαρακτηρας. Εχεις λοιπον τωρα το linebuffer που περιεχει μια γραμμη. Εσυ ξέρεις ακριβως το format καθε γραμμης, εχεις πχ πεδια που χωριζονται με κομματα. Θα χρησιμοποιησουμε την strtok για αυτη τη δουλεια πχ για <int>,<string>,<int> > while( fgets(linebuffer, 100, fPtr) != NULL) // για καθε γραμμη { char* tmp1 = strtok(linebuffer,","); //take portion of string (token)until first comma intVar1 = atoi(tmp1); // get you 1st integer tmp1 = strtok(NULL,","); // get token until 2nd comma (notice that now NULL is passed as argument, meaning that we continue from where we were) strcpy( yourstring1, tmp1); // copy from tmp1 (until 2nd comma) tmp1 = strtok(NULL,","); // get token until the end // now get the 2nd integer (after the 2nd comma) intVar2 = atoi(tmp1); } ο κωδικας ειναι απο το μυαλο μου οποτε μπορει να εχει λαθη αλλα ειμαι στη δουλεια τωρα. Κοιτα το documentation της strtok, και customarise τον κωδικα για το δικο σου format ps. η λυση ειναι παρομοια με αυτη του bokarinho , απλα στο εκανα πολυ λιανά ωστε να φτιαξεις κατι που καλυπτει τις αναγκες σου
bilco Δημοσ. 11 Ιανουαρίου 2008 Δημοσ. 11 Ιανουαρίου 2008 Τελικά έχω ακόμα πρόβλημα...Στο .txt μου έχω μέσα int,string,string,string,string,int,int Στην sscanf βάζω "%d,%s,%s,%s,%s,%d,%d" αλλά δεν κάνει σωστά τις αντιστοιχίες. Πχ το πρώτο int το βάζει στο αντίστοιχό του αλλά μετά, τα υπόλοιπα string τα βάζει σε ένα. Ενώ όταν αντικαταστήσω τα κόμματα με κενά δουλεύει κανονικότατα Τί μπορεί να φταίει ; H sscanf με %s στο fromat string θα διαβάσει ένα string μέχρι να βρει κενό. Μπορείς να καθορίσεις διαφορετική συμπεριφορά χρησιμοποιόντας τα [] αντί για το s. Για παράδειγμα η %[Α-z] θα διαβάσει μόνο τους χαρακτήρες από το Α μέχρι το z (που σημαίνει ότι αν βρεί διαφορετικό χαρακτήρα θα σταματήσει). Στην περίπτωση σου βολεύει να καθορίσεις ποιόν χαρακτήρα δεν θα διαβάσει (εδώ το ',') βάζοντας %[^,] (το string μπορεί να περιέχει οποιοδήποτε χαρακτήρα, συμπεριλαμβανομένου και του κενού, εκτός από το κόμμα)
georgemarios Δημοσ. 11 Ιανουαρίου 2008 Δημοσ. 11 Ιανουαρίου 2008 H sscanf με %s στο fromat string θα διαβάσει ένα string μέχρι να βρει κενό. Μπορείς να καθορίσεις διαφορετική συμπεριφορά χρησιμοποιόντας τα [] αντί για το s. Για παράδειγμα η %[Α-z] θα διαβάσει μόνο τους χαρακτήρες από το Α μέχρι το z (που σημαίνει ότι αν βρεί διαφορετικό χαρακτήρα θα σταματήσει). Στην περίπτωση σου βολεύει να καθορίσεις ποιόν χαρακτήρα δεν θα διαβάσει (εδώ το ',') βάζοντας %[^,] (το string μπορεί να περιέχει οποιοδήποτε χαρακτήρα, συμπεριλαμβανομένου και του κενού, εκτός από το κόμμα) χαχα αυτο δεν το ηξερα, ωραιος bilco
lockhart Δημοσ. 11 Ιανουαρίου 2008 Δημοσ. 11 Ιανουαρίου 2008 Μπορείς εξίσου απλά να χρησιμοποιήσεις την fscanf για να διαβάσεις τα αλφαριθμητικά και τους ακέραιους και στην συνέχεια με την χρήση της συνάρτησης strtok να αφαιρέσεις το κόμμα(,) από τα αλφαριθμητικά
Επισκέπτης Δημοσ. 11 Ιανουαρίου 2008 Δημοσ. 11 Ιανουαρίου 2008 Χρειάζεται προσοχή όταν γίνετε χρήση της scanf (& family) με το %s specifier καθώς δεν γίνεται έλεγχος των ορίων του string/array προορισμού. Ο σωστός τρόπος χρήσης είναι με length specifier. Λάθος τρόπος: > stest.c -------- #include <stdio.h> int main(void) { char buf[10]; scanf("%s", buf); printf("buf = %s\n", buf); return 0; } Εκτέλεση: > # gcc -Wall -O2 -W stest.c -o stest # ./stest sdsdsd <== input buf = sdsdsd # ./stest askldljkasdklasldkaslkdlkasd <== input = buffer overflow buf = askldljkasdklasldkaslkdlkasd Segmentation fault Σωστός τρόπος > stest2.c ---------- #include <stdio.h> int main(void) { char buf[10]; scanf("%9s", buf); printf("buf = %s\n", buf); return 0; } Εκτέλεση: > # gcc -Wall -O2 -W stest2.c -o stest2 # ./stest2 asdasdasd <== input buf = asdasdasd # ./stest2 asjkdjasdasjkdaskdkasdsadjas <== input, no buffer overflow buf = asjkdjasd Το ίδιο ισχύει και για το specifier %[..] Links: http://securityficus.org/blog/2007/08/11/scanf-is-an-underrated-source-of-security-bugs/ http://en.wikipedia.org/wiki/Scanf
makis89 Δημοσ. 16 Ιανουαρίου 2008 Μέλος Δημοσ. 16 Ιανουαρίου 2008 Σας ευχαριστώ όλους... Τα παραπάνω δεδομένα τα παίρνω από ένα αρχείο. Το αρχείο αυτό πρέπει να το ανοίγω για ανάγνωση-εγγραφή αλλά και όταν δεν υπάρχει πρέπει να το δημιουργώ. Μπορεί να γίνονται αυτά ταυτόχρονα ; Έστω ότι για το read-write βάζω mode "r+" ... Άν βάλω "w+" ώστε να δημιουργείται το αρχείο αν δεν υπάρχει, σβήνει όλα τα περιεχόμενά του. Τί κάνουμε σε αυτήν την περίπτωση ; Μία σκέψη είναι ότι άν το fopen("arxeio.txt","r+") είναι NULL να κάνω ένα fopen("arxeio.txt","w+"). Είναι σωστή η λογική μου ;
RubiksCube Δημοσ. 16 Ιανουαρίου 2008 Δημοσ. 16 Ιανουαρίου 2008 Μια απλή λύση είναι να ανοίξεις το αρχείο .txt με to notepad και να πας edit->replace. Αντικαθιστάς όλα τα κόμματα με κενό κάνοντας μόνο ένα click!!! Στη συνέχεια χρησιμοποιείς την fscanf(file,"%s %s %d",....klp). Ελπίζω να βοηθήει αυτό.
bokarinho Δημοσ. 16 Ιανουαρίου 2008 Δημοσ. 16 Ιανουαρίου 2008 Σας ευχαριστώ όλους... Τα παραπάνω δεδομένα τα παίρνω από ένα αρχείο. Το αρχείο αυτό πρέπει να το ανοίγω για ανάγνωση-εγγραφή αλλά και όταν δεν υπάρχει πρέπει να το δημιουργώ. Μπορεί να γίνονται αυτά ταυτόχρονα ; Έστω ότι για το read-write βάζω mode "r+" ... Άν βάλω "w+" ώστε να δημιουργείται το αρχείο αν δεν υπάρχει, σβήνει όλα τα περιεχόμενά του. Τί κάνουμε σε αυτήν την περίπτωση ; Μία σκέψη είναι ότι άν το fopen("arxeio.txt","r+") είναι NULL να κάνω ένα fopen("arxeio.txt","w+"). Είναι σωστή η λογική μου ; Απλά άνοιξε το να το διαβάσεις να δεις αν υπάρχει, μία ωραία συναρτησούλα να κάνει την δουλειά είναι αυτή: > int FileExists(const char *_filename) { FILE *ptrFile = NULL; if(ptrFile = fopen(_filename, "r")) != NULL) { fclose(ptrFile); return 1; } return 0; } Επιστρέφει True (διάφορο του μηδέν) αν όντως υπάρχει και False (μηδέν) αν δεν υπάρχει.
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.