zahlen einlesen
-
Hallo,
ich möchte aus einer Textdatei Zahlen einlesen. In der Datei stehen jeweils untereinander 10, 20, 30. So sieht mein Code aus:int main(){ FILE *datei; int c; datei =fopen("D:\\zahlen.txt","r"); if (datei != NULL){ while((c=fgetc(datei))!= EOF) {printf("%d\n",c); }} else printf("Konnte nicht geoeffnet werden!"); fclose(datei); system("Pause"); return 0; }
Bei ausgeben bekomme ich jetzt aber die Zahlen 49, 48, 10, 50, 48, 10, 51, 48.
Was mache ich falsch?
-
Du liest Zeichen ein.
Schau dir mal mit deinen Werten eine ASCII Tabelle.
-
fgetc steht für file get character. Du liest die Zahlen als ihren Buchstabenwert ein. Du suchst fscanf. Verwendung ist wie scanf (welches du kennen solltest), außer dass das erste Argument der Dateizeiger ist.
-
Wenn du wirklich die Zahlen auswerten willst, die in der Datei stehen, solltest du dir mal fscanf() ansehen.
-
Zudem solltest du meiner Meinung nach deinen Codestil überdenken.
-
Ist das irgendwie in Mode? Sieht man immer öfter:
}}}
Schrecklich!
-
Zum Einlesen aus einer text-basierten Datei - egal ob Zahlen, Buchstaben oder Hackschnitzel - eignet sich stets eine Kombination aus fgets und sscanf (bei bekanntem Format der eingelesenen Zeichen!) oder eben fscanf.
Wenn wir gerade schon beim Thema sind und sich hier die Kompetenzen bündeln, helft mir doch bitte mal auf die Sprünge.
Folgendermaßen sehen Zeilen in einer csv-Datei aus:
Hirsch;Harry;Putzfrau;rosa;251; Musterfrau;Renate;Gouverneur;rot;1292; Klum;Heidi;Kopfrechenkönigin;;111111;
In der 3. Zeile fehlt ein Element und - sollte man als Formatstring bei sscanf etwas wie "%[;];%[;];%[;];%[;];%[^;];" verwenden, wird man das letzte Element der 3. Zeile nicht auslesen können - so zumindest meine bisherig Praxiserfahrung damit.
Wenn also die Länge der eingelesenen Strings unterschiedlich sind und auch "", also Länge 0 möglich ist - wie kann ich den Formatstring für sscanf aussehen lassen?
FILE * fp; int minl = 0, maxl = 99; char liste[3][5][100] = { { { 0 } } }; ... fopen ... fgets (zeile, sizeof (zeile), fp); sscanf (zeile, "%*.*s;%*.*s;%*.*s;%*.*s;%*.*s;", liste[0][0], liste[0][1], liste[0][2], liste[0][3], liste[0][4]); fgets (zeile, sizeof (zeile), fp); sscanf (zeile, "%*.*s;%*.*s;%*.*s;%*.*s;%*.*s;", liste[1][0], liste[1][1], liste[1][2], liste[1][3], liste[1][4]); fgets (zeile, sizeof (zeile), fp); sscanf (zeile, "%*.*s;%*.*s;%*.*s;%*.*s;%*.*s;", liste[2][0], liste[2][1], liste[2][2], liste[2][3], liste[2][4]); ...
Kann mir nicht vorstellen, dass das zum gewünschten Ergebnis führt (dass liste[2][4] befüllt ist).
Any hints?
-
char liste[3][5][100] = { { { 0 } } };
Den gleichen Zweck erfüllt
char liste[3][5][100] = { 0 };
fgets (zeile, sizeof (zeile), fp);
Führt zu unerwünschten Effekten, falls zeile ein Zeiger ist.
Für sich ändernde Feldbreiten sollte man auch dynamisch reagieren, auch mit sscanf möglich:
int split(const char *s,char c,char***a) { char f[9]={'%','*','[','^',c,']','%','n'}; int r=0,i; while( sscanf(s,f,&i), *s ) { *s==c?i=0:1; *a=realloc(*a,++r*sizeof**a); memcpy((*a)[r-1]=calloc(1,i+1),s,i); s+=i+(!!s[i]); } return r; } ... while( fgets(zeile,zeilegroesse,f) ) { char **a=0; int r=split(zeile,';',&a); while( r-- ) printf("%s;",a[r]),free(a[r]); free(a); puts(""); }
-
1000 Dank, lieber Wutz - das hebe ich mir für nach dem Wochenende auf
-
@Wutz
Zeile 10 WTF
-
Wutz schrieb:
*a=realloc(*a,++r*sizeof**a); memcpy((*a)[r-1]=calloc(1,i+1),s,i);
Jupp, wer braucht schon Fehlerbehandlung.
Ich schlage vor, hier etwas tiefer in die Trickkiste zu greifen. Der Ansatz ist etwas komplexer, dafür ist er schneller und die Umsetzung einfacher. Der Plan ist, den Array-Kopf, den Index und die Daten direkt hintereinander in einen großen Speicherblock zu legen, d.h.
| size | data | i1 | i2 | i3 | ... | "foo" | "bar" | "baz" | ... | +------+------+----+----+----+-----+-------+-------+-------+-----+ |___^ | | | ^ ^ ^ |____|____|_________| | | |____|_________________| | |_________________________|
Dadurch, dass nur einmal Speicher angefordert wird, entfällt die Fehlerbehandlung bei Speichermangel praktisch vollständig. Das sieht dann etwa so aus:
#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct string_array { size_t size; char **data; }; size_t count_tokens(char const *input, size_t n, char delim) { size_t result = 1; char const *p; for(p = input; (p = memchr(p, delim, n - (p - input))); ++p) { ++result; } return result; } struct string_array *split_string(char const *input, char delim) { size_t len = strlen(input) + 1; size_t token_count = count_tokens(input, len, delim); struct string_array *result = malloc(sizeof(struct string_array) + /* Array-Kopf*/ sizeof(char*) * (token_count) + /* Index */ len); /* Daten */ if(result != NULL) { char *p; size_t i; /* Hier: Der Index liegt direkt hinter dem Kopf im Speicher, die Strings * direkt hinter dem Index. */ result->size = token_count; result->data = (char**)(result + 1); result->data[0] = (char*)(result->data + token_count); /* Also legen wir die Daten in den gewünschten Bereich */ p = result->data[0]; memcpy(p, input, len); /* Und ersetzen alle Trenner durch Null-Terminatoren, so dass aus den * Token einzelne C-Strings werden. Das Vorgehen ist vergleichbar mit * strtok, allerdings mit nur einem Trennerzeichen und ohne * aufeinanderfolgende Trenner zu überspringen. */ for(i = 1; i < token_count; ++i) { p = memchr(p, delim, len - (p - result->data[0])); *p++ = '\0'; /* Der Index wird hier gebaut. */ result->data[i] = p; } } return result; } int main(void) { size_t i; struct string_array *a = split_string("foo;bar;baz;qux;;quux;xyzzy", ';'); if(a == NULL) { return -1; } for(i = 0; i < a->size; ++i) { puts(a->data[i]); } free(a); return 0; }