Messdaten auswerten
-
Process terminated with status -1073741510 (0 minutes, 2 seconds)
#include <stdio.h> #include <stdlib.h> #define MAX 15 int main(void) { FILE *f=fopen("C:\\programme12\\daten\\daten","r+"); float werte[MAX][MAX]; int i=0,j=0; while(!feof(f) &&i<MAX) { char c=0; while(i<MAX && !feof(f) && fscanf(f,"%f",&werte[i][j++]) && fscanf(f,"%c",&c) && c!='\n'); i++; j=0; } printf("%f", werte[0][0]);//Zum testen was im Array steht printf("\n%.2f", werte[1][0]);//Zum testen was im Array steht return(0); }
Habs mal getestet und das Programm stürzt ab. Arbeite mit Code::Blocks 8.02 und dem GNU GCC Compiler.
-
Hm, bei mir klappt's, mit einer Datei, die genau die von dir geposteten Werte enthält. Erstell mal die Debug-Version (du testest scheinbar direkt mit der Release-Version), dann kriegst du auch die Zeile, in der es kracht, vom Debugger angezeigt (und eine vernünftige Fehlermeldung).
Es fehlt natürlich noch die Abfrage, ob j<MAX ist:
while(i<MAX && j<MAX && !feof(f) && fscanf(f,"%f",&werte[i][j++]) && fscanf(f,"%c",&c) && c!='\n');
Und zum Testen, was im Array landet, solltest du keine printf-Ausgaben verwenden, sondern direkt den Debugger benutze. Der liefert dir schließlich zur Laufzeit alle Variableninhalte.
Und eine Frage wäre natürlich auch noch, wie du erkennen willst, wieviele Werte in einer Zeile sind. Wenn du 5 Werte liest, ist das 6. Element in dieser Zeile in deinem Array natürlich nicht leer, sondern es steht 0 (wenn nullinitialisiert) oder irgendein Müll drin. Daher solltest du j festhalten, z.B. könnte man das Array dreidimensional aufbauen.
-
Program received signal SIGSEGV, Segmentation fault.
In der Zeile 11 liegt der Fehler.
-
martinANSIC schrieb:
Program received signal SIGSEGV, Segmentation fault.
In der Zeile 11 liegt der Fehler.in der schleife von z.13 wird j erhöht aber nicht getestet, i<MAX kann da eigentlich raus da es eh nie false wird, kpl. ob das zu nem fehler führt, sollte aber schon so sein, irgendwann haben wir sie schon die bug's
lg lolo
-
noobLolo schrieb:
in der schleife von z.13 wird j erhöht aber nicht getestet
Hatte ich ja schon ergänzt...
-
%c in *scanf überspringt whitespaces, du wirst damit also nie ein Newline-Zeichen einlesen.
Wie dem auch sei, das ganze geht natürlich bedeutend einfacher - mit fgets bist du im Grunde schon auf dem richtigen Weg. getline im folgenden Beispiel ist GNU-spezifisch (es fordert Speicher für die Zeile nach Bedarf an), aber da du mit dem GNU-Compiler arbeitest, sollte das kein Problem sein. Ansonsten tut's fgets auch, wenn du vorher weißt, wie lang eine Zeile in der Datei maximal sein kann.
#define _GNU_SOURCE #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> double line_avg(char *line) { char *token; double sum = 0.0; unsigned count = 0; for(token = strtok(line, " "); token != NULL; token = strtok(NULL, " ")) { double x; if(sscanf(token, "%lf", &x) == 1) { sum += x; ++count; } } return sum / count; } int main(void) { FILE *fd = fopen("daten.txt", "r"); char *line = NULL; size_t n = 0; while(-1 != getline(&line, &n, fd)) { printf("%g\n", line_avg(line)); } free(line); fclose(fd); }
-
seldon schrieb:
%c in *scanf überspringt whitespaces, du wirst damit also nie ein Newline-Zeichen einlesen.
Da haben wir das Problem. Zumindest bei der MS-Implementation werden Newlines nämlich (nur bei %c) gelesen:
MSDN schrieb:
White-space characters that are ordinarily skipped are read when c is specified.
-
Hmm...Tatsache, das hab ich in der Manpage auch so stehen. Ich hatte das wohl falsch im Kopf.
Was den Absturz angeht, wenn der in Zeile 11 stattfindet, hab ich feof(f) im Verdacht; das könnte dann passieren, wenn das Öffnen der Datei fehlschlägt und f == NULL ist.
Im Übrigen läufst du mit deiner Schleife in Probleme, wenn etwa am Ende einer Zeile ein oder mehrere Leerzeichen stehen. Ich halte prinzipiell nicht viel von solchen "cleveren" Hacks; sie sind kaum wartbar, und man läuft leicht in Situationen, in denen der Code leise und auf subtile Weise das Falsche macht. In den allermeisten Fällen ist es sicherer, geradlinig auf das Problem loszugehen - in diesem Fall, wo die Daten in Zeilen strukturiert sind, ist "hol eine Zeile, verarbeite sie, wiederhole, solange notwendig" ein robusterer Ansatz als "Hol dir die Daten zahlenweise und finde auf clevere Weise zwischendrin raus, wo die Zeilen enden." Man kann dabei weniger falsch machen.
Das ist zumindest meine Meinung.
-
Danke erstmal, der Code von seldon funktioniert.NUR getline ist kein ANSI C oder irre ich mich da?!
-
Nein, das ist ursprünglich eine GNU-Erweiterung und neuerdings in POSIX.1-2008 enthalten (was bedeutet, dass innerhalb einiger Jahre jedes System außer Windows sie beherrschen wird). Sie funktioniert im Grunde ähnlich wie fgets, fordert aber selbst ausreichend Speicher an, um die ganze Zeile darin zu verstauen.
Wenn du weißt, wie lang eine Zeile in der Datei maximal werden kann, tut's auch fgets mit ausreichend großem Buffer. Ist das nicht der Fall und bist du an ANSI-C gebunden, lässt sich getline relativ leicht mit fgets und realloc nachschreiben. Beispielsweise:
char *get_line(FILE *stream) { size_t const CHUNKSIZE = 128; size_t n = 0; char *buf = NULL; if(feof(stream)) return NULL; do { char *p; /* Buffer vergrößern */ n += CHUNKSIZE; p = realloc(buf, n + 1); if(p == NULL) { free(buf); return NULL; } buf = p; /* Nächsten Block anfordern */ if(fgets(buf + n - CHUNKSIZE, CHUNKSIZE + 1, stream) == NULL) { /* Für den Fall, dass die Datei nicht mit einem Newline-Zeichen endet */ if(feof(stream)) { return buf; } else { free(buf); return NULL; } } /* Solange, bis die Zeile vollständig ist. */ } while(buf[strlen(buf) - 1] != '\n'); return buf; }
In der Benutzung dann etwa
char *line; while(line = get_line(fd)) { printf("%g\n", line_avg(line)); free(p); }
Das ist jetzt nicht so performant wie getline, weil der Heap stärker bemüht wird und ich das nicht besonders optimiert habe, aber es sollte die Grundidee verdeutlichen.