Variablenwerte ausserhalb von Blöcken auslesen?
-
Hallo, ich habe folgenden Code:
Struktur:
struct programm {
int index;
char *name;
char *logdir;
char *logfile;
char *user;
int aktiv;
} pprogramm[10];int i=0; while (fgets(string, 500, fd) != NULL){ if (string[0] != '#'){ len = strlen(string); printf("String1 <%s>\n", string); string[len-1] = '\0'; printf("String2 <%s>\n", string); pprogramm[i].name = strtok(string, " "); pprogramm[i].logdir = strtok(NULL, " "); pprogramm[i].logfile = strtok(NULL, " "); pprogramm[i].user = strtok(NULL, "\n"); pprogramm[i].index = i; pprogramm[i].aktiv = 0; printf("**Programm %d: <%s>\n", i, pprogramm[i].name); getchar(); i++; } } fclose(fd); printf("unten: 1 <%s>\n", pprogramm[0].name); printf("unten: 2 <%s>\n", pprogramm[1].name);
Das printf innerhalb der while-Schleife gibt mir das korrekte Programm aus (ich habe 2 Strings in meiner Datei wo die Programmaufrufe extrahiert werden), das printf jedoch ausserhalb (nach fclose) gibt in beiden Fällen nur den Inhalt des 2. Strings aus.
Irgendwie verzweifel ich hier.
-
strtok() verändert den Originalstring. (Es setzt an die Stelle der Trennzeichen ein '\0') und verweist auch auf Stellen innerhalb des Strings.
Daher zeigt dein programm[i].name auf eine Stelle in string. Und string wird mit jeder Zeile neu eingelesen.Ersetze in deinen printf mal %s durch %p und schau dir die Adressen an.
-
Immer dieses Rumfummeln mit strtok, wo schnappt ihr das bloß immer auf.
Für deinen Anwendungsfall tut es sscanf als Einzeiler:if( 4==sscanf(string,"%s%s%s%s",p[i].name,p[i].logdir,p[i].logfile,p[i].user) ) { }
-
Wutz schrieb:
Immer dieses Rumfummeln mit strtok, wo schnappt ihr das bloß immer auf.
Für deinen Anwendungsfall tut es sscanf als Einzeiler:Er braucht aber auf alle Fälle Speicherplatz für seine Token.
-
Tja, und was steht dann in den p[i-1]-Token beim folgenden fgets-Durchlauf drin?
Sicher nicht das Erwartete. Deshalb braucht auch die strtok Lösung statt char* char[].
-
Wutz schrieb:
... Deshalb braucht auch die strtok Lösung statt char* char[].
Ist wohl bei meiner ersten Erklärung nicht richtig rübergekommen.
Er sollte nur nicht denken, dass sein Problem mit scanf behoben ist.
-
Och, es wäre durchaus vertretbar, die Tokens direkt hintereinander in einem dynamischen Speicherbereich zu halten - man muss halt nur beim Aufräumen hinterher aufpassen, den richtigen Zeiger zu freen.
Eine ähnliche, ganz simple Lösung wäre
char *str_duplicate(char const *src) { char *dest; if(!src) return NULL; dest = malloc(strlen(str + 1)); strcpy(dest, src); return dest; } ... pprogramm[i].name = str_duplicate(strtok(string, " " )); pprogramm[i].logdir = str_duplicate(strtok(NULL , " " )); pprogramm[i].logfile = str_duplicate(strtok(NULL , " " )); pprogramm[i].user = str_duplicate(strtok(NULL , "\n")); /* Speicher später wieder freigeben! */
Wobei ich dagegen jedes Mal wieder die Krätze kriege, ist nacktes %s in *scanf-Aufrufen. Längenbegrenzung! Du handelst dir damit jedes Mal wieder Buffer-Overflows ein, und das ist einfach nicht professionell.
Wenn die Länge legitimer Eingabedaten zuverlässig nach oben abgeschätzt werden kann, kann man etwa Folgendes machen:
struct programm { int index; char name[50]; char logdir[256]; char logfile[256]; char user[50]; int aktiv; } pprogramm[10]; ... /* v-- %s niemals nackt! */ if(4 == fscanf(fd, "%49s%255s%255s%49[^\n]", pprogramm[i].name, pprogramm[i].logdir, pprogramm[i].logfile, pprogramm[i].user)) { }
Wo hast du eigentlich diese fixe Idee aufgeschnappt, *scanf für alles zu benutzen? Man kann damit eine Menge reißen, aber man muss schon vorsichtig sein.
-
Dann kann er auch gleich seine string aus der Datei im Speicher behalten.
struct programm { int index; char *string; // hier mit malloc Platz für den string (aus fgets) machen char *name; char *logdir; char *logfile; char *user; int aktiv; } pprogramm[10];
Dann hat er weniger free().
-
Jupp, das meinte ich mit "die Tokens direkt hintereinander in einem dynamischen Speicherbereich zu halten".
Großer Vorteil: Wenn einem mal ein Herr "Karl Theodor Maria Nikolaus Johann Jacob Philipp Franz Joseph Sylvester Freiherr von und zu Guttenberg" o.ä. über den Weg läuft, hat man mit der Länge des Namensbuffers trotzdem kein Problem.