große Datensätze einlesen

HentaiD

Mitglied
Hi,
ich habe ein Problem beim Einlesen großer Datensätze.
Das Programm ist in C geschrieben und funktioniert, warum auch immer, nur auf Windows XP 32, auf Vista 32 und 64 stürzt es direkt ab. Auf XP 32 funktioniert es mit kleineren Datensätzen (so um die 20-30 Zeilen). Funktionieren soll es auf Linux (tut's das so auch?) Ich vermute mal, dass es ein Malloc()-Problem ist, weiß aber nicht, wie ich es lösen kann.

Code:
   FILE* Datensatz = fopen (argv[1], "r");                                      // öffnen(lesen, "r") der Datei (argv[1] = Pfad)
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang beginnen
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl und Brueckenverbindungen einlesen/speichern
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            fscanf(Datensatz, "%d %d", &Bruecken[i-1][0], &Bruecken[i-1][1]);               
         }
         Zeilen = i;                                                            // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
      }
   }                                                                            // Ende einlesen
   
   if (Datensatz != NULL){                                                      // Falls gueltiger Datensatz: Start
      fclose(Datensatz);                                                        // Datei schließen      
      Speicherallozierung();                                                    // Speicher allozieren

Die Speicherallozierung sieht so aus:

Code:
void Speicherallozierung(){                                                  // Speicherallozierung
      passBr[Versuch+1][Zeilen][2] = (int*)malloc(sizeof(int)*(Versuch+1)*Zeilen*2); 
      Blacklist[Versuch+1][Zeilen][2] = (int*)malloc(sizeof(int)*(Versuch+1)*Zeilen*2);                                   
      Bruecken[Zeilen][2] = (int*)malloc(sizeof(int)*Zeilen*2);
      BrueckenK[Zeilen][2] = (int*)malloc(sizeof(int)*Zeilen*2);
      Ergebnis[Zeilen+1] = (int*)malloc(sizeof(int)*(Zeilen+1));
      ManiZs[Zeilen] = (int*)malloc(sizeof(int)*Zeilen);
      if(ManiZs[Zeilen] == NULL || Bruecken[Zeilen][2] == NULL || BrueckenK[Zeilen][2] == NULL || Ergebnis[Zeilen+1] == NULL || Blacklist[Versuch+1][Zeilen][2] == NULL || passBr[Versuch+1][Zeilen][2] == NULL) {
         printf("Kein Virtueller RAM mehr verfügbar ...\n");
         SAV = 1;
      }
      else {
         SAV = 0;   
      }
   }


Die Datensätze sehen z.B: so aus:

5
5 4
4 3
3 2
2 1
.....
0 5

Wäre Euch sehr dankbar für Hilfe. =)

Liebe Grüße, D
 
Zuletzt bearbeitet:
Hi Ihr,
danke für die super Links. =)
Habe das jetzt nochmal versucht mit Alloc und Realloc. Klappt aber trotzdem nicht, d.h.
das Programm stürzt jetzt direkt ab.

Habe die Variable jetzt mal umdefiniert:
Code:
   int **Bruecken;
      Bruecken = (int **)malloc(Zeilen * sizeof(int *));
      Bruecken[2] = (int *)malloc(2 * sizeof(int));

Compiler sagt, dass das ok wäre.
Jetzt dachte ich mir, da ja gleichzeitig die Zeilenanzahl eingelesen wird aber auch in das Array gespeichert wird, muss ich reallozieren. Also sieght der Code jetzt so aus:
(Da Zeilen mit 0 initialisiert ist, muss also pro Schleifendurchlauf mit Zeilen+1 realloziert wird und der Speicher erhöht werden)

Code:
   FILE* Datensatz = fopen (argv[1], "r");                                      // öffnen(lesen, "r") der Datei (argv[1] = Pfad)
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang beginnen
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl und Brueckenverbindungen einlesen/speichern
         Bruecken = (int *)realloc(Bruecken,(Zeilen+1)*sizeof(int));
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            fscanf(Datensatz, "%d %d", &Bruecken[i-1][0], &Bruecken[i-1][1]);               
         }
         Zeilen = i;                                                            // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
      }
   }

Tja, stürzt aber leider wie gesagt ab. Irgendwas mache ich falsch. Wo ist denn der Hund begraben? :(

Liebe Grüße, D
 
Hi.
Hi Ihr,
danke für die super Links. =)
Habe das jetzt nochmal versucht mit Alloc und Realloc. Klappt aber trotzdem nicht, d.h.
das Programm stürzt jetzt direkt ab.

Habe die Variable jetzt mal umdefiniert:
Code:
   int **Bruecken;
      Bruecken = (int **)malloc(Zeilen * sizeof(int *));
      Bruecken[2] = (int *)malloc(2 * sizeof(int));

Compiler sagt, dass das ok wäre.
Ist es aber nicht. Für ein mehrdimensionales Array brauchst du eine Schleife zur Initialisierung der Unterarrays wie in dem Beispiel aus dem Buch.

Und poste mal ein komplettes Beispiel was man auch kompilieren kann und schreibe dazu welche Fehlermeldung kommt und an welcher Stelle das Programm abstürzt (Debugger benutzen!).

Gruß
 
Also bisher sah der Code so aus: Ob jetzt mit Malloc oder nicht, ist egal, da es bis jetzt eh nicht funktioniert. Bei kleinen Datensätzen passiert aber durchaus etwas und er gibt fein die Paare an:

Code:
#include <stdlib.h>                                                             // KOMMENTARE
#include <stdio.h>


int main(int argc, char* argv[]){ 
    
   int i;                                                                       // Zaehlervariable                                
   int Zeilen;                                                                  // Zeilenanzahl
   int Sockelanzahl;                                                            // Anzahl verschiedener Sockel
   int Bruecken[Zeilen][2];                                                     // Brueckenverbindungen

//..............................................................................// PROGRAMMSTART
   FILE* Datensatz = fopen (argv[1], "r");                                      // öffnen(lesen, "r") der Datei (argv[1] = Pfad)
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang beginnen
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl und Brueckenverbindungen einlesen/speichern
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            fscanf(Datensatz, "%d %d", &Bruecken[i-1][0], &Bruecken[i-1][1]);               
         }
         Zeilen = i;                                                            // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
         printf("Bruecke: %d,%d\n", Bruecken[i-1][0], Bruecken[i-1][1]);
      }
   }                                                                            // Ende einlesen                                                                                   
}

Da der Debugger, warum auch immer, nicht funktioniert (vll. ist Dev CPP einfach die falsche IDE :( ) muss ich oftmals leider raten.

Umgeschrieben sieht es bisher so aus:

Code:
#include <stdlib.h>                                                             // KOMMENTARE
#include <stdio.h>


int main(int argc, char* argv[]){ 
    
   int i;                                                                       // Zaehlervariable                                
   int Zeilen = 0;                                                              // Zeilenanzahl
   int Sockelanzahl;                                                            // Anzahl verschiedener Sockel
   int **Bruecken;                                                              // Brueckenverbindungen

//..............................................................................// PROGRAMMSTART

   Bruecken = (int **)malloc((Zeilen+1) * sizeof(int *));
   
   void Alloz(){
      Bruecken = (int **)realloc(Bruecken,(Zeilen+1)*sizeof(int));                    
      Bruecken[0] = (int *)malloc(sizeof(int));
      Bruecken[1] = (int *)malloc(sizeof(int));
   }


   FILE* Datensatz = fopen (argv[1], "r");                                      // öffnen(lesen, "r") der Datei (argv[1] = Pfad)
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang beginnen
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl und Brueckenverbindungen einlesen/speichern
      Alloz();
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            fscanf(Datensatz, "%d %d", &Bruecken[i-1][0], &Bruecken[i-1][1]);               
         }
         Zeilen = i;                                                            // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
         printf("Bruecke: %d,%d\n", Bruecken[i-1][0], Bruecken[i-1][1]);
      }
   }                                                                            // Ende einlesen                                                                                   
}


Programm stürzt direkt ab, keine Ausgabe. =((

Liebe Grüße, D
 
Code:
   void Alloz(){
      Bruecken = (int **)realloc(Bruecken,(Zeilen+1)*sizeof(int));                    
      Bruecken[0] = (int *)malloc(sizeof(int));
      Bruecken[1] = (int *)malloc(sizeof(int));
   }
Beim realloc sollte es sizeof(int *) heißen. Und die nächsten zwei Zeilen verstehe ich nicht. Du reservierst dir Speicher für Zeilen+1 Zeiger und initialisiert dann davon die ersten beiden. Das geht schon beim allerersten Aufruf schief, weil dort Bruechen[1] nicht reserviert wurde. Ich denke du wolltest viel eher das hier machen:
Code:
   void Alloz(){
      Bruecken = (int **)realloc(Bruecken,(Zeilen+1)*sizeof(int *));
      Bruecken[Zeilen] = (int *)malloc(2*sizeof(int));
   }

Code:
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl und Brueckenverbindungen einlesen/speichern
      Alloz();
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            fscanf(Datensatz, "%d %d", &Bruecken[i-1][0], &Bruecken[i-1][1]);               
         }
         Zeilen = i;                                                            // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
         printf("Bruecke: %d,%d\n", Bruecken[i-1][0], Bruecken[i-1][1]);
      }
Die Ausgabe sollte nur erfolgen, wenn du auch etwas eingelesen hast (also nicht bei i==0), da du sonst wieder auf unreservierten Speicher zugreifst. Du könntest aber auch das Einlesen der Sockelanzahl schon vor der Schleife erledigen, dann sparst du dir die Fallunterscheidung.

Als abschließende Bemerkung möchte ich noch erwähnen, dass für diesen Zweck ein Array möglicherweise nicht die richtige Datenstruktur ist. Zumindest beim Einlesen wäre eine verkettete Liste viel handlicher.

Grüße, Matthias
 
Hi,
danke habe das jetzt geändert. Leider funktioniert das immer noch nicht. Programm stürzt nach wie vor ab, obwohl es ansich ja funktionieren müsste. Habe mich jetzt entschlossen tatsächlich zuerst die Zeilen auszulesen, damit die Allozierung nicht mehr so aufwendig ist, da noch mehrere Arrays benutzt werden. Leider bin ich wohl sogar dazu zu doof.
Habe jetzt den Einlesen-Teil komplett rausgelassen. Habe das vorher schonmal probiert, aber irgendwie möchte das Programm dann nicht aufhören einzulesen, da er wohl das EOF nicht mehr ganz versteht.

Code:
   Bruecken = (int **)malloc((Zeilen+1) *sizeof(int *));
   
   void Alloz(){
      Bruecken = (int **)realloc(Bruecken,(Zeilen+1)*sizeof(int *));
      Bruecken[Zeilen] = (int *)malloc(2*sizeof(int));
   }


   FILE* Datensatz = fopen (argv[1], "r");                                      // öffnen(lesen, "r") der Datei (argv[1] = Pfad)
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang beginnen
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl und Brueckenverbindungen einlesen/speichern
         Alloz();
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            Zeilen = i;                                                         // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
            printf("Zeilen: %d\n", Zeilen);
         }
      }
   }                                                                            // Ende einlesen                                                                                   
}

Die Schleife läuft also bis unendlich. Das gibt's doch gar nicht *verzweifel*. =(

Liebe Grüße, D


Edit:
So, es funktioniert. =)
Das allerdings auch nur mit völlig falschen astronomischen Zahlen: (Und das Programm stürzt nach dem vorletzten Brückenpaar ab)

Code:
   void Alloz(){
      for(i=0; i<Zeilen; i++){
         Bruecken = (int **)malloc(Zeilen*sizeof(int *));
      }
      for(i=0;i<Zeilen;i++){
         Bruecken[i] = (int *)malloc(2*sizeof(int));
      }
   }


   FILE* Datensatz = fopen (argv[1], "r");                                      // öffnen(lesen, "r") der Datei (argv[1] = Pfad)
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang (Zeilen beginnen
      for(i=0; !feof (Datensatz); i++){                                         // Bis zum Dateiende Zeilenanzahl einlesen/speichern
         if (i==0){                                                    
            fscanf(Datensatz, "%d", &Sockelanzahl);
         }
         else{
            fscanf(Datensatz,"%d %d", &Zeilen,&Zeilen);                         
            Zeilen = i;                                                         // Anzahl der Bruecken (Anzahl der Dateizeilen - 1)
            printf("Zeilen: %d\n", Zeilen);
         }
      }
   }  
   
   Alloz();
   
   if ( Datensatz == NULL )                                                     // Wenn Datei nicht vorhanden ist:
      printf("Ungueltiges Eingabeformat.\n");                                   // Ausgabe, Abbruch
   else{                                                                        // Andernfalls: Einlesevorgang beginnen
      for(i=1; Zeilen; i++){                                                    // Bis zum Dateiende Brueckenverbindungen einlesen/speichern
         fscanf(Datensatz, "%d %d", &Bruecken[i][0], &Bruecken[i][1]);               
         printf("Bruecke: %d,%d\n", Bruecken[i][0], Bruecken[i][1]);
      }

   }

Edit2: OK Absturzproblem behoben, dämlicher Fehler, die astronomischen Zahlen bleiben aber weiterhin ein Problem. *ratlos*
 
Zuletzt bearbeitet:
Code:
   void Alloz(){
      for(i=0; i<Zeilen; i++){
         Bruecken = (int **)malloc(Zeilen*sizeof(int *));
      }
      for(i=0;i<Zeilen;i++){
         Bruecken[i] = (int *)malloc(2*sizeof(int));
      }
   }
Die erste Schleife erzeugt ein schönes Speicherleck. Wieso alloziierst du den Speicherplatz für deine Zeiger mehrmals? Überleg dir bei solchen Sachen doch einfach mal in Ruhe (am besten auf einem Blatt Papier), was passieren soll, anstatt drauflos zu programmieren.

Code:
      for(i=1; Zeilen; i++){                                                    // Bis zum Dateiende Brueckenverbindungen einlesen/speichern
         fscanf(Datensatz, "%d %d", &Bruecken[i][0], &Bruecken[i][1]);               
         printf("Bruecke: %d,%d\n", Bruecken[i][0], Bruecken[i][1]);
      }
Wenn die Programmausführung bei diesem Codestück ist, bist du bereits am Ende der Datei angekommen. Was erwartest du, dass fscanf dann weiter einlesen soll? Du musst erst mit fseek wieder an den Anfang der Datei zurückkehren, um die Werte erneut einlesen zu können. Außerdem solltest du die Abbruchbedingung der Schleife nochmal genau anschauen.

Ich würde dir nachwievor empfehlen, das ganze mit einer verlinkten Liste zu lösen.

Grüße, Matthias
 
Super, vielen vielen Dank!! =))

Es funktioniert jetzt alles wie es sollte. Auch mit Riesendatensätzen.
Das Speicherleck ist jetzt behoben und auch große Datensätze werden ohne Probleme ausgegeben. Ich muss leider zugeben, dass ich wenig Ahnung von den verketteten Listen habe. Da ich aber noch zusätzliche Arrays benutze, schien mir die Handhabung recht einfach. Vll. mache ich einen Fehler, aber hauptsache es funktioniert. >.<

Liebe Grüße, D
 
Hi.

Wenn deine Objekte immer eine feste Anzahl von Werten haben (also die zweite Dimension immer 2 ist), würde es sich anbieten eine Struktur zu verwenden:
C:
typedef struct { 
  int x, y;
} Bruecke;

Bruecke *bruecken = calloc(n, sizeof(Bruecke));
Dann mußt du nicht mit einem mehrdimensionalen Array rumhantieren.

Gruß
 
Zurück