Problem beim Auslesen einer .csv Datei (String,Struct,strtok)
-
Guten Abend,
ich bin noch relativ unerfahren, was ANSI C angeht und muss gestehen, dass ich gerade an einem Punkt angekommen bin, wo ich absolut nicht mehr weiter weiß.
Ich hoffe ihr könnt mir ein wenig auf die Sprünge helfen.Und zwar möchte ich eine .csv Datei auslesen und deren Inhalt in einem Struct speichern.
Der Inhalt der .csv Datei könnte z.B. so aussehene:
Name;Vorname;Anrede;Strasse Meier;Peter;Herr;Juliusleberstrasse Blizzeria GmbH;;Firma;Auguststrasse
Das Problem ist u.a. das doppelte Semikolon bei leeren Zellen in der Tabelle.
Wie man das dann mit strtok auslesen kann, weiß ich nicht.
Deswegen habe ich erstmal alle Zeichen aus der .csv Datei in einem String gespeichert und nach jedem Semikolon manuell ein Leerzeichen eingefügt.
Somit habe ich das Problem mit dem doppeltem Semikolon gelöst und ich kann mit strtok(string,';') die einzelnen Tokens, die später in einem Struct abgelegt werden sollen, zerlegen.for(i=0;(readChar=fgetc(fz))!=EOF;i++) { if(readChar==';' || readChar=='\n') { buf[i]=readChar; buf[i+1]=' '; i++; } else { buf[i]=readChar; } }
Mit printf("%s",buf); wird mir auch der komplette eingelesene String angezeigt.
Nun kommen wir zu dem Problem.
Ich möchte nun mit strtok(buf,del); den String innerhalb einer Schleife zerlegen und die Tokens, wie erwähnt, in einem Struct speichern.So sieht mein Versuch derzeit aus:
while((buf!=NULL) && i<100) { strcpy(daten[i].name, strtok(buf,del)); strcpy(daten[i].vorn, strtok(NULL,del)); strcpy(daten[i].anrede, strtok(NULL,del)); strcpy(daten[i].strasse, strtok(NULL,del)); ++i; }
Das Programm schmiert komplett ab. Scheint vermutlich ein overflow zu sein.
Das ich nach jedem Schleifendurchlauf wieder den kompletten String mit strtok in daten[i].vorn einlese ist mir bewusst und genau da liegt vermutlich auch das Problem. Die Schleifenbedingung ist wohl auch falsch. Ich habe da schon einiges ausprobiert. Die Bedingung hatte ich eben als letztes noch getestet. Aber ich habe gerade irgendwie ein Brett vorm Kopf.Ich hoffe ihr könnt mir behilflich sein.
Edit:
Hier mal der "komplette" code:#include <stdio.h> #include <stdlib.h> #include <string.h> #define LENGTH 21000 struct Daten { char vorn[40]; char name[40]; char anrede[10]; char strasse[20]; }daten[100]; int main(void) { FILE *fz=NULL; int i=0,j; char buf[LENGTH]; char del[]=";\n"; char readChar; fz = fopen ("F:\\test.csv", "r"); for(i=0;i<LENGTH;i++) buf[i]='\0'; for(i=0;(readChar=fgetc(fz))!=EOF;i++) { if(readChar==';' || readChar=='\n') { buf[i]=readChar; buf[i+1]=' '; i++; } else { buf[i]=readChar; } } fclose(fz); while((buf!=NULL) && i<100) { strcpy(daten[i].name, strtok(buf,del)); strcpy(daten[i].vorn, strtok(NULL,del)); strcpy(daten[i].anrede, strtok(NULL,del)); strcpy(daten[i].strasse, strtok(NULL,del)); ++i; } for(j=0;j<20;j++) { printf("%s", daten[j].name); printf("%s", daten[j].vorn); printf("%s", daten[j].anrede); printf("%s", daten[j].strasse); } return 0; }
-
man: strtok gibt NULL zurück, wenn es keine Tokens mehr gibt und NULL ist kein gültiger Parameter für strcpy!
-
Also findet meine Schleifenbedigung kein Ende?
Ich hatte es auch schon mal mit einer for-Schleife probiert und als Bedingung einfach i<5 genommen zum Testen. Nach dem ersten Schleifendurchlauf ist das Programm ebenfalls abgeschmiert.
Das würde dann wohl an dem
strcpy(daten[i].name, strtok(buf,del));
liegen, weil das nach jedem Durchlauf wieder aufgerufen wird.
Wie kann ich das umgehen?Ich könnte die Daten auch alle manuell ohne Schleife einlesen, aber das würde dann bei 100 Datensätzen ziemlich viel Quellcode produzieren und ist auch einfach nur unschön.
Daher halte ich mich die ganze Zeit an der Schleife auf und ich komm echt nicht drauf, wie ich es umsetzen soll, damit es vernünftig läuft.
Für euch ist das evt. etwas banales, aber bitte helft mir. Ich bin echt am verzweifeln grad.
-
Mavinas schrieb:
Das würde dann wohl an dem
strcpy(daten[i].name, strtok(buf,del));
liegen, weil das nach jedem Durchlauf wieder aufgerufen wird.
Wie kann ich das umgehen?Eine Zeiger-Variable anlegen, den Wert von strtok() dort speichern, und nur so lange weiterarbeiten, wie der Zeiger nicht NULL ist.
-
In etwa so?
Char *temp; temp=strtok(buf,del); while(temp!=NULL) { strcpy(daten[i].vorn, temp); strcpy(daten[i].name, temp); strcpy(daten[i].anrede, temp); strcpy(daten[i].strasse, temp); temp=strtok(NULL,del); }
Dann würde doch bestimmt in vorn, name, anrede und strasse nach dem ersten Durchlauf jeweils "Vorname" stehen und nicht wie gewünscht "Name Vorname Anrede Strasse".
Aber ich glaube das funktioniert so weit. Ich kann es grad nicht testen. Jetzt müsst ich nur noch wissen, wie man die Tokens dann vernünftig an die richtigen Arrays übergibt.Vielleicht so?
while(temp!=NULL) { strcpy(daten[i].vorn, temp); temp=strtok(NULL,del); strcpy(daten[i].name, temp); temp=strtok(NULL,del); strcpy(daten[i].anrede, temp); temp=strtok(NULL,del); strcpy(daten[i].strasse, temp); temp=strtok(NULL,del); }
Wobei er ja hier auch vermutlich mit "Vorname" anfangen würde und nicht mit "Name".
-
Du musst nach jedem Aufruf von strtok überprüfen ob NULL zurück gegeben wurde und kannst erst dann kopieren.
-
Moin,
ich habe es hinbekommen.
Vielen Dank euch beide. Ihr habt mir sehr geholfen!