• Diese Seite verwendet Cookies. Indem du diese Website weiterhin nutzt, erklärst du dich mit der Verwendung von Cookies einverstanden. Erfahre mehr

csv to array

Themenstarter #1
Hallo,
bin gerade mehr oder weniger dabei ein Programm zu basteln, was den Inhalt einer csv in den RAM läd und 3 neue Files erstellt.

Mein Beispiel hat 35000 Zeilen, pro Zeile 13 Zellen mit einem Zelleninhalt von 39 chars

Würds gerne in einen 3D - Array laden, erhalte jedoch immer Segmentation faults

Code:
void
zaehl_function(int *rows, int *cells, int *letters)
{
// Öffnet die csv und zählt Zeilen, Zellen-Maxwert und Zelleninhalt-Maxwert --> schreibts über pointer in die variablen aus main()
}
int
main(void)
{
    int rows, cells, letters;
    zaehl_function(&rows, &cells, &letters);

    // rows ~ 35000 -- cells ~ 13 -- letters ~ 39
    char array[rows + 1][cells + 1][letters + 1];

    return 0;
}
(stark vereinfacht)
Das Ergebnis ist ein Segmentation fault, ich vermute mal aufgrund des zu großen Arrays?

Weiß hierfür jemand eine intelligentere Lösung, würde gern ein allgemeines Programm basteln mit dem ich eine csv via C ähnlich wie mit VBA bearbeiten kann. Dateien vollständig in den RAM laden ist erwünscht, denke so erhalte ich die beste Zugriffszeit.

Bitte fragen, wenn ich etwas unverständlich erläutert habe
 
Themenstarter #3
Man muss schon den konkrekten Code sehen, bei dem es crasht.

Hier mein Code:
Code:
#include <stdio.h>
#include <stdlib.h>

void
read(int *rows, int *cells, int *letters)
{
   FILE *read_file;
  
   if ((read_file = fopen("/cygdrive/c/Users/imj1lo/Desktop/testfilter.csv", "r")) == NULL) {
     printf("Unable to open read_file in function read()\n");
     exit(1);
   } else {
     printf("read_file opened successfully in function read()\n");
   }
  
   int c;
   int c_counter = 0;
   int s_counter = 0;
   int l_counter = 0;

   c = fgetc(read_file);
  
   while(c != EOF) {
     if (c == '\n') {
       c_counter++;
       s_counter = 0;
       l_counter = 0;
     }
     if (c == ';') {
       s_counter++;
       l_counter = 0;
     }
     if (s_counter > *cells) {
       *cells = s_counter;
     }
     if (l_counter > *letters) {
       *letters = l_counter;
     }
    
     l_counter++;    
     c = fgetc(read_file);
   }
   *rows = c_counter;

   fclose(read_file);
}

int
main(void)
{
   FILE *read_file;
   FILE *write_file;
  
   int rows = 0, cells = 0, letters = 0;
  
   read(&rows, &cells, &letters);
  
   if ((read_file = fopen("/cygdrive/c/Users/imj1lo/Desktop/testfilter.csv", "r")) == NULL) {
     printf("Unable to open read_file\n");
     exit(1);
   } else {
     printf("read_file opened successfully\n");
   }
  
   if ((write_file = fopen("/cygdrive/c/Users/imj1lo/Desktop/output.csv", "w")) == NULL) {
     printf("Unable to open write_file\n");
     exit(1);  
   } else {
     printf("write_file opened successfully\n");
   }

   short row = 0, cell = 0, letter = 0;
  
   int c;
   c = fgetc(read_file);
  
   printf("Max-Rows: %i, Max-Cells: %i, Max-Letters: %i\n", rows, cells, letters);
  
   char read_array[rows + 1][cells + 1][letters + 1];

   /*
    * Main-Loop
    */
   while (c != EOF) {  
     fprintf(write_file, "%c", c);
     c = fgetc(read_file);
   }    
  
   fclose(read_file);
   fclose(write_file);
  
   return 0;
}
Ausgabe:
Code:
read_file opened successfully in function read()
read_file opened successfully
write_file opened successfully
Max-Rows: 34060, Max-Cells: 13, Max-Letters: 39
Segmentation fault (core dumped)
Was jedoch geht:
Code:
#include <stdio.h>

void
test(int *eins, int *zwei, int *drei)
{
   *eins = 20;
   *zwei = 20;
   *drei = 20;
  
   printf("%i, %i, %i\n", *eins, *zwei, *drei);
}

int
main(void)
{
   int eins, zwei, drei;
  
   test(&eins, &zwei, &drei);
  
   char array[20][20][20];
   printf("success 1\n");
  
   char array_2[eins + 1][zwei + 1][drei + 1];
   printf("success 2\n");
  
   return 0;
}
Ausgabe:
Code:
20, 20, 20
success 1
success 2

Fehler jedoch in:
Code:
#include <stdio.h>

void
test(int *eins, int *zwei, int *drei)
{
   *eins = 34062;
   *zwei = 13;
   *drei = 39;
  
   printf("%i, %i, %i\n", *eins, *zwei, *drei);
}

int
main(void)
{
   int eins, zwei, drei;
  
   test(&eins, &zwei, &drei);
  
   char array[34062][13][39];
   printf("success 1\n");
  
   char array_2[eins + 1][zwei + 1][drei + 1];
   printf("success 2\n");
  
   return 0;
}
Ausgabe:
Code:
Segmentation fault (core dumped)
Ich mach den ganzen Unsinn momentan in Cygwin, nicht das es hieran liegt :)
 
#5
Ab besten machst Du dich mal mit dem debugger ``gdb'' vertraut.

Gib dem compiler beim Kompilieren die Option ``-g'' mit an. Beispiel: ``cc -g foo.c''

Dann den debugger mit ``gdb a.out'' starten.

Dann ``run'' eingeben.

Dann mit ``backtrace'' oder ``bt'' einen backtrace erstellen. Daraus ist schon sehr viel ersichtlich.

Hier im debugger kannst Du auch z.B. breakpoints setzen und das Programm Zeile fuer Zeile ablaufen lassen und gucken, ab wann es crashed, was die Variablen zu diesem Zeitpunkt fuer einen Inhalt haben usw...

Ein paar shortcuts findest Du hier:

l = list (l command)
p = print
c = continue
s = step
bt = backtrack
help = help
quit = quit
...
 

serie300

Well-Known Member
#8
C kommt nicht mit einem 18MB großen Array zurecht wegen Stackoverflow?
Die Sache mit malloc und selber verwalten würde ich erstmal lassen. Das macht der Compiler in Zusammenarbeit mit dem OS normalerweise besser als was selbst geschriebenes.
Probier mal ob du mit structs weiterkommst. Im Normalfall zahlt sich der geschickte Einsatz von Datenstrukturen immer aus. Falls du doch selber Zeiger schieben willst, kannst du auch mit Index aus dem File lesen. Das BS cached das im Normalfall eh, sodaß die Plattengeschwindigkeit nicht ins Gewicht fällt.

Serie300
 
Themenstarter #9
Die Sache mit malloc und selber verwalten würde ich erstmal lassen. Das macht der Compiler in Zusammenarbeit mit dem OS normalerweise besser als was selbst geschriebenes.
Ich bekomms gerade eh nicht auf die Reihe malloc mit einem 3D-Array zu füttern, tat mir mit 2D-Arrays schon schwer

Probier mal ob du mit structs weiterkommst. Im Normalfall zahlt sich der geschickte Einsatz von Datenstrukturen immer aus. Falls du doch selber Zeiger schieben willst, kannst du auch mit Index aus dem File lesen.
Danke für die Tipps, werd ich morgen mal angehen
 

Vril

Well-Known Member
#10
Code:
Segmentation fault (core dumped)
Ich mach den ganzen Unsinn momentan in Cygwin, nicht das es hieran liegt :)
Naja, wer unter Windows in C programmiert muss halt bestraft werden :D

Nein, das ist hier ne klare Sache!

Entweder den gcc via switch anweisen, einen grösseren Stack bereitzustellen
(oftmals schlechte Methode):
Code:
gcc -Wl,--stack,500000 -o dein_prog
( 50000 ist Groesse in Bytes -aber ist Beispiel - ich habe jetzt nicht deine Arraygroesse ausgerechnet )

oder eben dynamisch den Speicher deinen arrays zuweisen.
Das ist die Methode, die Du Dir direkt angewöhnen solltest - und immer benutzen solltest.
Deine Freunde heissen:
malloc, calloc usw.
schau mal hier:
http://www.c-howto.de/tutorial/arrays-felder/speicherverwaltung/
 

Vril

Well-Known Member
#11
Nachtrag:
ich hatte eben nur den thread flüchtig überflogen -
jetzt hab ich das hier gesehen:

...
Code:
void
zaehl_function(int *rows, int *cells, int *letters)
{
// Öffnet die csv und zählt Zeilen, Zellen-Maxwert und Zelleninhalt-Maxwert --> schreibts über pointer in die variablen aus main()
}
int
main(void)
{
    int rows, cells, letters;
    zaehl_function(&rows, &cells, &letters);

    // rows ~ 35000 -- cells ~ 13 -- letters ~ 39
    char array[rows + 1][cells + 1][letters + 1];

    return 0;
}
(stark vereinfacht)
in C ist ein Array entweder statisch oder eben nicht!

statisch heisst: dass die Anzahl der Elemente fix ist!

Das ist hier aber genau nicht der Fall - sondern Du willst im Programmlauf mit der zaehl_function
die Größe des Arrays bestimmen --- dann musst Du auf jeden Fall den Speicher (dynamisch) alloziieren!

Dies dann gleich zum erstenmal in einem dreidimensionalen Array zu machen,
finde ich etwas unglücklich, denn schon ein 2dimensionales array ist vom Verständnis
gar nicht so trivial, wie es erstmal scheint

Warum? Das merkst Du spätestens wenn Du damit arbeitest:

ich skizziere hier mal die Verhältnisse bei nur 2 Dimensionen:

char array[3][5] -> ist ein Array von 3 Arrays von 5 char: also sizeof(array) = 3* 5* sizeof(char)
array -> ist hier ein Array von 5 char: sizeof(array) = 5* sizeof(char)

in char array[x][y] gelten folgende Dinge:

array liefert einen Zeiger vom Typ Zeiger auf ein Array von 3 Arrays von 5 char

*array liefert einen Pointer auf ein Array von 5 char

&array liefert einen Pointer vom Typ Pointer auf ein Array von 5 char

&array[j] liefert einen Zeiger auf char
usw.
 

Vril

Well-Known Member
#13
Geht es hier um den Lerneffekt in C oder um die Aufgabe? Falls Letzteres, würde ich dringend zu Perl und Konsorten raten.
Der Ansatz, eine zu bearbeitendes csv-File komplett in ein mehrdimensionales Array zu laden, wird auch mit Perl nicht besser.
Ausserdem warne ich jeden C Anfänger (der C wirklich lernen will) davor :belehren:- parallel dazu mit Perl zu murxen;)
 
Themenstarter #14
Geht es hier um den Lerneffekt in C oder um die Aufgabe? Falls Letzteres, würde ich dringend zu Perl und Konsorten raten.
Die Aufgabe ist bereits in VBA gelöst, jedoch viel zu langsam. Ich habe einzelne Teile bereits in C nachgebaut und bin von 20 Sekunden Aufwand, auf < 0,01 Sekunden gewandert.


Dies dann gleich zum erstenmal in einem dreidimensionalen Array zu machen,
finde ich etwas unglücklich,
Naja, eine csv-Datei/Excel-Tabelle ist nach Definition ein 3D-Array:
Erste Dimension: Zelleninhalt
Zweite Dimension: Zellen
Dritte Dimension: Zeilen

Würde der Array stehen, wäre der Unterschied meiner Aufgabe zu VBA sehr maginal, da die Ausgangslage mehr oder weniger die gleiche ist. Ich werds aber erstmal mit ein paar anderen hier im Thread genannten Tricks probieren.

Naja, wer unter Windows in C programmiert muss halt bestraft werden :D
vServer sind bei uns in der Firma zum Testen zu teuer (1GB RAM, 20GB Platte mit Redhat kosten um die 88 €) - ich vermute mal die sind aus Massivgold
Einen Brocken Hardware ohne Windows laufen zu lassen ist ein Papierkrieg
Virtualbox ist erst seit gestern installiert :)
 

Rakor

Administrator
Mitarbeiter
#15
Eine Excel Tabelle ist 2D. Du hast Zeilen und Spalten zur Adressierung deines Wertes.
Als Array schreibst du ja auch in Array[x][y] deinen Wert.
Im übrigen ist wohl so ziemlich alles schneller als VBA.
 

CrimsonKing

Systemzerstörer
#16
C-Programmieren unter Windows ist eigentlich gar nicht so übel, so lange man einen vernünftigen Compiler hat. Der von Microsoft ist für normales C ziemlich scheiße (mangelnde Standardunterstützung u.a.). Cygwin halte ich persönlich für eine deutlich schlechtere Lösung als zum Beispiel einen nativen clang.
 
Themenstarter #17
Als Array schreibst du ja auch in Array[x][y] deinen Wert.
Dann sind weder einzelne Zeichen eines Zellwertes, noch andere Tabellen vorhanden oder verstehe ich Arrays mit mehreren Dimensionen so falsch?

EDIT: Hast recht, habs mir unnötig kompliziert gemacht

Meine Tabellen enthalten hauptsächlich Text, Zahlen sind nur ein kleiner Teil der Auswertung

EDIT: Hast mich damit auf eine Gute Idee gebracht, Danke :)
 
Zuletzt bearbeitet:

Vril

Well-Known Member
#18
Du wolltest die 3. Dimension nutzen um den Inhalt einer Zelle zu speichern?
Also wenn in 5.zeile und 3. Zelle dann ‚Murx‘ stehen würde
[5-1][3-1][0] ist „M“
[5-1][3-1][1]ist „u“
[5-1][3-1][2] ist „r“
[5-1][3-1][3] ist „x“

???

Nein - du denkst zu kompliziert - schaue was
@Rakor geschrieben hat
 

-Nuke-

Well-Known Member
#19
Eine Excel Tabelle ist 2D. Du hast Zeilen und Spalten zur Adressierung deines Wertes.
Es resultiert am Ende dann trotzdem in einem 3D Array, da ein String in C ein char-Array ist. Hier in dem Fall wäre es dann auch nicht char [x][y] sondern char* [x][y] und * und [] ergeben in dem Kontext so ziemlich ein und dasselbe.
 

-Nuke-

Well-Known Member
#24
Das, auf was ein char* zeigt, ist in dem Kontext ein char.
Es zeigt auf "irgendwas char"... C kennt im Speicher so direkt keine Arrays, darum muss man char-Arrays auch mit \0 terminieren, damit die ganzen String-Routinen überhaupt funktioneiren. Erst du machst mittels des []-Operators daraus ein Array in der Hoffnung, dass du im Vorfeld genug Speicher dafür reserviert hast. Als Beispiel mal: char *test = "Hallo Welt".

[] sagt auch nur Anfangs-Adresse von der Variable + Offset mit der Zahl in der Klammer. Ob "printf("%c\n",test[1])" klappt oder nicht sagt dir dann das OS hinterher.
 

Vril

Well-Known Member
#25
Nö, aber das auf was es zeigt ist eines in dem Kontext. Klar es kann auch auf irgendwas x-beliebiges anderes zeigen, da C keinerlei Typsicherheit hat, aber in dem Kontext ist ein char-Array aka String gewünscht. Der einzige Unterschied liegt in der Initialisierung.
Dieser Text erscheint mir jetzt auch nicht typischer :D

Nullterminierung?
Nein - auch ein paar chars sind nicht automatisch ein String in C