bestimmte Spalte einer CSV Datei einlesen
-
Hallo und vielen Dank für die Vorschläge. Bekomme leider beim Kompilieren vom Code folgenden Fehler:
cc -c changeChannel.c In function 'main': 23:5: error: 'for' loop initial declarations are only allowed in C99 mode 23:5: note: use option -std=c99 or -std=gnu99 to compile your code make: *** [changeChannel.o] Error 1
-
...habe das Problem selbst lösen können:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { int* arr = NULL; int count=0; int i; const char filename[] = "1.txt"; FILE *file = fopen(filename, "r"); if ( file ) { char line [ BUFSIZ ]; while ( fgets(line, sizeof line, file) ) { char* p = strchr(line,','); if (p == NULL) continue; // Zeile ohne 2. Spalte (z.B. Leerzeile) ++p; int i = atoi (p); if (i == 0) continue; // Wert ist kein Integer arr = (int*) realloc (arr,(count+1)*4); arr[count] = i; ++count; } } fclose (filename); for (i=0; i<count; ++i) { printf ("arr[%i]: %i\n",i,arr[i]); } if (arr) free (arr); return 0; }
-
Silvi21 schrieb:
Hallo und vielen Dank für die Vorschläge. Bekomme leider beim Kompilieren vom Code folgenden Fehler:
cc -c changeChannel.c In function 'main': 23:5: error: 'for' loop initial declarations are only allowed in C99 mode 23:5: note: use option -std=c99 or -std=gnu99 to compile your code make: *** [changeChannel.o] Error 1
for(int i = 0; i < irgendwas; i++)
ist nicht erlaubt.
int i; for(i = 0; ...)
so!
edit: zu spaet gesehen. Schön, dass es dir selbst aufgefallen ist!
-
Vielen Dank @rkhb,
dein Code funktioniert super. Wie kann man es jetzt noch hinbekommen, das alle Dateien mit der Endung *.txt aus einem Verzeichnis eingelesen werden? Die Dateien, die in diesem Verzeichnis liegen, haben alle den gleichen Aufbau wie die "1.txt".
Gruß,
Silvi
-
Silvi21 schrieb:
Wie kann man es jetzt noch hinbekommen, das alle Dateien mit der Endung *.txt aus einem Verzeichnis eingelesen werden? Die Dateien, die in diesem Verzeichnis liegen, haben alle den gleichen Aufbau wie die "1.txt".
Es sieht so aus, als arbeitest Du an einem POSIX-konformistischem System (Linux) mit einem POSIX-konformistischem Compiler (GCC). Also:
#include <stdio.h> #include <string.h> #include <dirent.h> int main () { struct dirent* dp; char* dir_path = "."; DIR* dir = opendir (dir_path); if (dir == NULL) { perror("OPENDIR fehlgeschlagen"); return 1; } while ( (dp=readdir(dir)) != NULL ) { char* p = strrchr (dp->d_name,'.'); if (p && strcmp(p,".txt") == 0) { printf ("%s\n",dp->d_name); } } closedir (dir); return 0; }
viele grüße
ralph
-
Hallo ralph,
vielen Dank für Deine Antwort. Dein Code listet mir alle Dateien im Verzeichnis auf, welche auf *.txt enden. Wie schafft man es, dass all diese Dateien so verarbeitet werden, dass von nur die INT-Werte der zweite Spalte von ihnen in ein Array geschrieben werden. Sozusagen eine Erweiterung des Deines ersten Codes.
Gruß,
Silvi
-
In Zeile 22 werden die Dateinamen ausgegeben.
An der Stelle kannst du dein bisheriges Einleseprogramm einpflegen.
Nicht einfach einfügen.Besser ist es, wenn du dein Einleseprogramm als Funktion schreibst und in Zeile 22 aufrufst.
-
Silvi21 schrieb:
Wie schafft man es, dass all diese Dateien so verarbeitet werden, dass von nur die INT-Werte der zweite Spalte von ihnen in ein Array geschrieben werden.
Ich bekomme langsam schwer den Eindruck, dass es sich um eine Semesterhausaufgabe handelt. Was will der Professor denn noch? Mittelwert? Summe? Umrechnung aus der Unixtime? Eintrag in eine relationale Datenbank?
Den Königsweg hat DirkB beschrieben. Das PRINTF dient als Platzhalter, um anzuzeigen, was zu diesem Zeitpunkt bekannt ist. Das kann man natürlich auch als Argument an eine Funktion übergeben.
Ich selbst bevorzuge immer schnelles Schließen (close, closedir) und unverzügliche Freigabe (free). Das bedeutet, dass bei offenen Dateien und offenen Verzeichnisse nur das Nötigste abgearbeitet bzw. erst einmal gespeichert wird. Weitere Aktionen erfolgen auf dem Speicher. Das sähe dann etwa so aus:
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <dirent.h> int main () { int i,j; // für kurzfristige Zwecke, z.B. Laufvariablen struct dirent *dp; const char *dir_path = "."; DIR *dir = opendir (dir_path); if (dir == NULL) { perror("OPENDIR fehlgeschlagen"); return 1; } puts ("Dateien:"); char* dirs = NULL; int files_size = 0; int files_count = 0; while ( (dp=readdir(dir)) != NULL ) { char* p = strrchr (dp->d_name,'.'); if (p && strcmp(p,".txt") == 0) { int index = files_size; files_size += strlen(dp->d_name) + 1; char* d = realloc (dirs,files_size); if (d == NULL) { if (dirs) free (dirs); perror ("REALLOC fehlgeschlagen"); return 2; } dirs = d; strcpy (dirs+index,dp->d_name); ++files_count; } } closedir(dir); for (i=0, j=0; i<files_count; ++i) { printf ("%i %s\n",i,dirs+j); j += strlen (dirs+j) + 1; } puts(""); puts ("Integerwerte in der zweiten Spalte:"); int* integers = NULL; int integers_count = 0; for (i=0, j=0; i<files_count; ++i) { char* filename = dirs+j; FILE *file = fopen(filename, "r"); if ( file ) { char line [ BUFSIZ ]; while ( fgets(line, sizeof line, file) ) { char* p = strchr(line,','); if (p == NULL) continue; // Zeile ohne 2. Spalte (z.B. Leerzeile) ++p; int integer = atoi (p); if (integer == 0 && *p != '0') continue; // Wert ist kein gültiges Integer int* a = (int*) realloc (integers,(integers_count+1)*4); if (a == NULL) { if (dirs) free (dirs); perror ("REALLOC fehlgeschlagen"); return 2; } integers = a; integers[integers_count] = integer; ++integers_count; } fclose (file); j += strlen (dirs+j) + 1; } } if (dirs) free (dirs); for (i=0; i<integers_count; ++i) { printf ("integers[%i]:\t%i\n",i,integers[i]); } if (integers) free (integers); return 0; }
Das Auseinanderpfriemeln in Funktionen überlasse ich Dir.
viele grüße
ralph
-
Hallo ralph,
vielen Dank für Deine Hilfe. Dein Code funktioniert super. Bei der Aufgabe handelt es sich nicht um eine Hausaufgabe. Es ist ein kleines privates Projekt und ich versuche ein wenig C zu verstehen. Habe jedoch damit so meine Problemchen.
Wenn ich beispielsweise 8 Dateien mit je 10 Werten (in der zweiten Spalte) einlese, bekomme ich als Ausgabe 80 Arrays untereinander. Wie kann man jetzt mit diesen Werten weiter rechnen? An welcher Stelle vom Code muss man hierfür ansetzen? Würde gern zu jedem Wert die Häufigkeit des Auftretens anzeigen lassen. Weiterhin sollte jeder Wert nur einmal ausgegeben werden.Viele Grüße,
Silvi
-
Du hast ein Array* mit 80 Werten. Dieses Array heißt
integers
Und wie in Zeile 89 zu sehen ist kannst du darauf z.B mit integers[i] zugreifen.
Wenn du jetzt weitermachen willst, musst du deinen neuen Code in Zeile 91 einfügen. Nimm Dazu die Schleife von Zeile 87-90 als Vorbild.
Spätestens jetzt solltest du aber eigene Funktion nutzen, sonst wird das Ganze zu unübersichtlich.
Welchen Wertebereich haben denn deine Zahlen aus Spalte 2?
Wie/womit lernst du denn C?
*integers ist eigentlich kein Array sondern ein Zeiger auf einen Speicherbereich (der mitmalloc/realloc beschafft wurde) Der Unterschied spielt hier erstmal keine Rolle.
-
Hallo DirkB,
vielen Dank für Deine Anmerkungen. Versuche mich in C hiermit http://home.fhtw-berlin.de/~junghans/cref/index.html einzuarbeiten. Der Wertebereich der 2.Spalte liegt im Interval [1;14].
Viele Grüße,
Silvi
-
... wie müsste man die Zeile
printf ("integers[%i]:\t%i\n",i,integers[i]);
ändern, wenn nur die Integerwerte der 2.Spalte angezeigt werden sollten?
Derzeit wird folgendes angezeigt:integers[0]: 2 usw.
printf ("%i\n",i,integers[i]);
funktioniert leider nicht. Hierbei wird lediglich die aktuelle Zeilennr. ausgegeben.
Viele Grüße,
Silvi
-
Silvi21 schrieb:
Versuche mich in C hiermit http://home.fhtw-berlin.de/~junghans/cref/index.html einzuarbeiten.
Außer einer C-Referenz kann ich da nicht viel sehen.
Kauf/leih dir lieber ein Buch.Als Online-Referenz ist http://www.cplusplus.com/reference/clibrary/ besser geeignet.
Wenn du bei
printf ("integers[%i]:\t%i\n",i,integers[i]);
den Index (Zeilennummer) und den Wert siehst, und beiprintf ("%i\n",i,integers[i]);
nur den Index siehst, könnte das etwas mit den weitern Parametern zu tun haben.Deine Werte stehen in dem Feld integeres. Daraus kannst du folgern, dass das i, zuviel ist.
Silvi21 schrieb:
Der Wertebereich der 2.Spalte liegt im Interval [1;14].
Dann brauchst du ein Feld von 15 Elementen (die 0 zählt mit, das macht es einfacher). z.B.
int statistik[15];
Alle Elemente des Feldes setzt du auf 0 (mit einer Schleife).
Dann gehst du das Feld integers durch (wie bei beim print) und wenn du eine 1 findest, erhöhst du das Feld statistik[1] um 1. Wenn du eine 14 findest, erhöhst du das Feld statistik[14] um 1.int statistik[15] = {0}; for (i=0; i<integers_count; ++i) { if ((integers[i] >= 0) && (integers[i] < 15)) ++statistik[integers[i]] ; } for (i=0; i<15; ++i) { printf ("%2i gibt es %3i mal \n", i, statistik[i]); }
Ohne vernünftiges Buch Tutorial hilft dir das aber nicht weiter.
C lernt man nicht durch Versuch und Irrtum.
-
Vielen Dank für Eure Hilfe!
Grüße,
Silvi
-
Silvi21 schrieb:
Hallo ralph,
vielen Dank für Deine Hilfe. Dein Code funktioniert super. Bei der Aufgabe handelt es sich nicht um eine Hausaufgabe. Es ist ein kleines privates Projekt und ich versuche ein wenig C zu verstehen. Habe jedoch damit so meine Problemchen.
Wenn ich beispielsweise 8 Dateien mit je 10 Werten (in der zweiten Spalte) einlese, bekomme ich als Ausgabe 80 Arrays untereinander. Wie kann man jetzt mit diesen Werten weiter rechnen? An welcher Stelle vom Code muss man hierfür ansetzen? Würde gern zu jedem Wert die Häufigkeit des Auftretens anzeigen lassen. Weiterhin sollte jeder Wert nur einmal ausgegeben werden.Viele Grüße,
SilviDirkB ist mir zuvorkommen, so behalte ich meinen fast identischen Codeschnippsel für mich.
Als ich mal blitzartig von Turbo Pascal auf C umsteigen musste, hat mir folgendes Tutorial am meisten genutzt:
http://www2.hs-augsburg.de/informatik/vorlesungen/XX/c_cplus/tutorial/cyris/ckmain.htm
Ich kann es auch heute noch empfehlen. Ein schneller, schnörkelloser Einstieg in C. Danach hat man einen sehr guten Überblick über die Möglichkeiten der Sprache.
Mit den Codeschnippsel in diesem Thread hast Du eine gute Vorlage zum Selbststudium für folgende zwei Aufgaben:
-
Gehe den Code Zeile für Zeile durch und versuche einem imaginären Zuhörer zu erklären, was hier passiert und warum. Übergehe keine Zeile, halte Dich lieber länger daran auf.
-
Teile den Code in Funktionen auf. Ich weiß, das ist nervig, aber Du bekommst ein gutes Gefühl, welcher Block welche Informationen braucht und welche neuen Informationen Du am Ende des Blocks hast (EVA-Prinzip).
viele grüße
ralph
-
-
Silvi21 schrieb:
Schrott.
int func1(void); /* Define a few functions. */ int func2(void); main() {
Der Mann beherrscht die Grundbegriffe nicht und außerdem viel von irgendwoher zusammengeklaubtes Zeug.
-
Silvi21 schrieb:
Als ich mal blitzartig von Turbo Pascal auf C umsteigen musste, hat mir folgendes Tutorial am meisten genutzt:
http://www2.hs-augsburg.de/informatik/vorlesungen/XX/c_cplus/tutorial/cyris/ckmain.htm
Schrott.
Wer im ersten Beispielvoid main(void)
vorführt, sollte selbst nochmal in die Lehre gehen.