While Schleifen, Riesen Problem



  • hi, habe ein problem mit einem programm in dem 2 while-schleifen vorkommen. mein programm soll eine datei auslesen (z.b. Test.tst), diese datei von datenmüll entfernen und in out.txt speichern. In out.txt stehen jetzt Sachen wie z.B:

    <test>   345     Programmer
                peter  = 123 
                hans   = 234
                 ...
    

    Weiterhin soll während des Programmes eine zweite datei (z.b. bat.txt) eingelesen werden, die z.B. so aussieht:

    222    tester
             karl = 334
    345    Programmer
             hans = 000
    555    regisseur
             frauke = 7
    ...
    

    das ganze sieht jetzt vielleicht etwas verwirrend aus, ist aber im prinzip einfach zu verstehen.
    Das Programm solll wie gesagt anfangs den Datenmüll aus test.tst entfernen und in out.txt speichern (nicht den Datenmüll, sondern den Rest)
    Anschließend wird überprüft ob out.txt datendätze besitzt, wenn ja, dann sollen die einzelnen Zeilen von out.txt überprüft und gespalten werden. dafür habe ich zwei funktionen, eine zum splitten, und eine um die führenden whitespaces zu entfernen. das klappt auch soweit perfekt. So: jetzt mein Problem: Also nachdem die test.txt eingelesen wurde (zeilenweise, und gruppenname, gruppennummer,... gespeichert wurden) wird die bat.txt zeilenweise überprüft ob sich da z.b. eine Gruppennummer 345 mit dem Namen Programmer befindet. Wenn ja, dann soll die nächste Zeile überprüft werden, wieder gesplittet und die quasi veränderten werte sollen in die bat.txt eingetragen werden.
    Bsp. wenn vorher da stand hans = 000 (in bat.txt unter Gruppennummer 345 und Gruppenname Programmer) soll danach in der Zeile Hans = 234 stehen, da hans ja der Gruppennummer und der gruppe angehört.
    Bisher habe ich da etwa so gelöst: Habe es kommentiert um nicht den ganzen Code zu posten, ist nämlich ganz schön long

    batfile = fopen("bat.txt","w");  //sieht wie oben aus
    testfile = fopen("test.tst","r"); //sieht wie oben aus
    out = fopen("out.txt","w"); // hier ist alles ohne datenmüll drin
    
    //dann fange ich an:
    while ( fgets (in, MAX_LEN, test) != NULL) 
    {
        //datenmüllbeseitigung
        //alles bei dem int read =0 ist, fliegt jetzt raus 
    
        if(read!=0)
        {
            if (strstr (in,"<test>") != NULL)
            {
               //um sich die gruppe zu merken und die Zeile <test>   345   Programmer zu splitten und die einzelteile zu merken 
            }
            else
            {
                 // wenn nicht <test> drin ist, dann splitte die Zeile und speichere die Werte in par und wer.(Bsp.: par = Hans
                                               wer = 234)
            }
    
            /*jetzt kommt glaube mein problem: Nachdem ich nun parameter und wert und gruppe habe, will ich die bat.txt zeilenweise überprüfen ob dort die werte vorkommen und zwar so:*/
            while(fgets(buffer, MAX_LEN, batfile) != NULL)
            {
                if (( strstr (buffer,groupname) != NULL)  &&  ( strstr (buffer,grnumber) !=NULL))
                {
                    /*Quasi wenn der gruppenname, der zuvor gespeichert wurde und die gruppennummer übereinstimmen und in der bat-datei gefunden wurden, sollen jetzt ab da die werte geändert werden. */
                     printf(buffer);
                       .......... //hier stehen jetzt alle zeilen, die den gruppennamen und die gruppennummer beinhalten.
                }
    

    So, aber wie kann ich jetzt weiter machen? Oder bin ich schon auf dem falschen dampfer??? bei mir wird bis hierher die zweite while-schleife nur einmal durchlaufen. Im prinzip müsste die ja mindestens so oft durchlaufen werden, wie die test.tst Zeilen hat oder nicht? Ach ich weiß nicht mehr weiter, hoffe jemand kann mir weiter helfen insofern mein problem überhaupt verstanden wurde. *SCHNIEF* 😕



  • Du machst das ganze etwas kompliziert.

    Wenn es nicht zuviel Aufwand ist oder nur etwas zur Übung, dann solltest du es etwas umändern.

    Am einfachsten solltest du dich tun, wenn du erstmal die test.tst einliest und nur die wichtigen Daten in einem Array speicherst (vorzugsweise eine struct als Arrayelement). Danach verkehrst du genauso mit deiner bat.txt und speicherst es in einem zweiten solchen Array (der Aufbau scheint ja der selbe zu sein, also kannst du die gleiche struct verwenden). Nun hast du erstmal alles was du brauchst im Arbeitsspeicher. Und jetzt erledigst du die Änderungen vom 1. Array im 2. Array. Wenn alle Änderungen gemacht wurden im 2. Array, dann schreibst du das 2. Array wieder mit den ungeänderten und geänderten Daten (also vollständig) in die bat.txt.



  • Kannst du mir evtl. mal ein zeigen, wie ich das array fülle. Ich weiß gar nicht recht, wie ich da ran gehen sollte. Ich wäre aber gern bereit das so noch zu ändern. Ein Beispiel für test.tst würde mir genügen...



  • Ich mach mal ein einfaches Beispiel:

    #define MAXSPALTEN 256
    
    typedef struct
    {
       char text[MAXSPALTEN];
    }zeile;
    
    ...
    
    //Einlesen der Datei
    zeile *textzeilen;
    unsigned int anzzeilen = 0;
    FILE *textdatei;
    
    textdatei = fopen("test.txt", "r");
    
    if(textdatei)
    {
       textzeilen = malloc(sizeof(zeile)); //Speicher für eine Zeile reservieren
    
       while(fgets(textzeilen[anzzeilen].text, MAXSPALTEN, textdatei))
       {      
          ++anzzeilen;
          //zusätzlichen Speicher reservieren
          textzeilen = realloc(textzeilen, (anzzeilen + 1)*sizeof(zeile));
       }
    
       fclose(textdatei);
    }
    


  • Hoi AJ,
    hab gerade gesehen das der Thread auch in dem Forum in dem ich mich meistens trolle läuft... da er ja vermutlich noch ein wenig länger dauert und damit nicht jede antwort zweimal gegeben wird...

    schlage vor das aber in diesem forum hier weiterzudiskutieren... heir sind meistens mehr leute online...
    http://www.fun-soft.de/showtopic.php?threadid=7636



  • aber an welcher stelle fülle ich denn das array? Oder wo wird denn das array eingelesen? Welche werte habe ich dann an welcher Stelle und wie kann ich dann auf diese einzelnen Elemente zugreifen?

    Wie gesagt, die test.tst sieht so aus:

    <TEST> 255  Programmer
    	Rudi = "1-200-491718710000"
             Lutz = "491718710000"
             Lars = "200"
    

    wenn ich diese datei einlese (mit deinem geposteten code), wie ist das dann im Array verteilt. Weiterhin muss ja die Gruppennummer sowohl bei Rudi, Lutz und bei Lars eingetragen werden, obwohl sie nur einmal da steht. Am liebsten wäre mir ja so ein Array, dass Zeilenweise speichert und zwar so:

    /*Gruppe:*/ 255   /*GrName:*/ Programmer
                  /*Name:*/Rudi     /*Wert:*/ "1-200-491718710000"
    ...
    

    Ich weiß auch nicht, ob ich das jetzt verstanden habe, aber ich muss doch dieDatensätze dann irgendwie ansprechen können wie z.B. Wenn Zeile 7 Gruppe=255, GrName=Programmer ist, dann soll Zeile 8 (quasi Rudi) in der anderen Datei gesucht werden und dort ersetzt werden... Ach, so richtig klar ist mir das noch nicht wie ich das mache.



  • Wie du es genau machen musst, hängt stark vom Aufbau deiner Datei ab. Du musst also erstmal festlegen, wie ein "Datensatz" in deiner Datei aussieht und damit eine struct deklarieren. Beim Einlesen der Datei füllst du dann die struct (pro Schleifendurchlauf also einen Datensatz). Wenn du alles eingelesen hast in den Arbeitsspeicher (struct-Arrays), dann kannst du dich um die Änderungen kümmern.

    Wie man struct-Array anlegt, hab ich dir ja schon mit meinem Beispiel gezeigt. In diesem wird jede Zeile der Datei als "Datensatz" im struct-Array textzeilen gespeichert.



  • wie die datei aussehen soll, darüber brauche ich mir keine Gedanken machen, denn die Datei (test.txt) wird mir zur verfügung gestellt. und die sieht auf jeden Fall immer so aus:

    <test>     455     producer
               gerd = "3456654"
               peter = "5586854"
               Heinz = "585854"
    <test>     123     tester
               lutz = "993"
    <test>     999     writer
               wilma = "3345"
    
          ...   ...   ...
    

    was soll ich da nur für eine struktur schaffen? Jeweils die erste Zeile von einem solchen eintrag beginnt mit <test>, gefolgt von whitespaces, dann kommt die GrNummer, dann der Gruppenname. Alle Zeilen darunter haben die Form: whitespaces am anfang, dann der parameter (gerd bzw. Name), dann der wert (Bsp: "3456654").
    ... bis halt wieder eine Zeile mit test kommt.
    ich habe mir ja überlegt, irgendwie den Datensatz anders aufzubauen. Und zwar, sobald <test> im string erscheint wird sich die gruppennummer und der gruppenname gemerkt. Anschließend wird in die nächste zeile gegangen, und dort an den namen (z.B. gerd) der gruppenname und die GrNummer angehängt werden und letztendlich 4 Datensätze in einer Zeile stehen.
    Bsp.:

    455    producer      gerd   =    "3456654"
    455    producer      peter  =    "5586854"
    455    producer      Heinz  =    "585854"
    123    tester        lutz   =    "993"
    

    ... und wenn ich dann so eine Form habe, dann lässt sich leichter ein struct bilden oder???
    z.B.

    typedef struct
    {
       int GrNumber[MAXSPALTEN];
       char GrName[MAXSPALTEN];
       char name[MAXSPALTEN];
       char number[MAXSPALTEN];
    }zeile;
    

    Könnte das so klappen? Weiß echt nicht wie ich das sonst anstellen sollte. Die Dateien sehen im Original exakt so aus, wie ich sie hier gepostet habe. Hoffe auf positive antworten.



  • Ruuuuudi schrieb:

    ich habe mir ja überlegt, irgendwie den Datensatz anders aufzubauen. Und zwar, sobald <test> im string erscheint wird sich die gruppennummer und der gruppenname gemerkt. Anschließend wird in die nächste zeile gegangen, und dort an den namen (z.B. gerd) der gruppenname und die GrNummer angehängt werden und letztendlich 4 Datensätze in einer Zeile stehen.
    Bsp.:

    455    producer      gerd   =    "3456654"
    455    producer      peter  =    "5586854"
    455    producer      Heinz  =    "585854"
    123    tester        lutz   =    "993"
    

    ... und wenn ich dann so eine Form habe, dann lässt sich leichter ein struct bilden oder?

    So kannst Du das schon machen, es kommt jetzt eher darauf an, für was die Daten später gebraucht werden (und wie das Format genau aussieht).

    ZB könnte ich mir vorstellen, eine Art Map zu basteln, und die in der Datenstruktur zu hinterlegen.



  • habe es jetzt zumindest soweit, dass ich die test.txt auslese, alles wichtige entferne und in out.txt speichere. anschließend öffne ich die out.txt, lese diese zeilenweise ein und füge Gruppenname und-nummer mit hinzu, sprich ich habe jetzt pro durchlauf der whileschleife folgende Daten in variablen gespeichert:(überschriften sind die Variablennamen)

    (GrNumber)     (GrName)      (Param)      (Wert)
    
    233             programmer     gerd      "3456654"
    233             programmer     peter     "5586854"
    442             tester         ryu       "85855"
    

    so, diese werte habe ich also in jedem schleifendurchgang gespeichert. Wie kriege ich nun diese werte in ein struct? habe so begonnen:

    typedef struct 
    	{ 
    		char numb; 
    		char name;
    		char par;
    		char wert; 
    	} LINE;
    
    	LINE l1 = {numb,name,par,wert};
    

    so habe ich das struct vorbereitet.
    Und wie kann ich das jetzt mit den gespeicherten werten füllen?
    Kann mir jemand ein bsp. dafür geben, wie ich z.B.
    die Zeile

    "233             programmer     gerd      "3456654""
    

    in das struct einlese (an die bestimmten Stellen) und wie ich dann damit arbeiten kann. 😕



  • Erstmal sorry, dass ich mich so lange nicht gemeldet hab :(.

    Der Aufbau deiner Struktur ist schon mal ganz gut. Nur die Datentypen passen noch nicht ganz:

    /*
    MAX_GRPNAME: Steht für die maximalen Zeichen für den Gruppennamen + Stringendezeichen
    Beispiel: Der Gruppenname darf maximal 20 Zeichen haben, dann sollte
    MAX_GRPNAME den Wert 21 haben.
    #define MAX_GRPNAME 21
    
    MAX_USERNAME: Wie MAX_GRPNAME, aber für den Benutzernamen
    Beispiel:
    #define MAX_USERNAME 11
    */
    
    typedef struct
    {
       int grpnr;
       char grpname[MAX_GRPNAME];
       char username[MAX_USERNAME];
       long wert;
    } LINE;
    

    Das Einlesen an sich geht recht einfach (fp_out_txt ist dein Stream zu out.txt):

    fscanf(fp_out_txt, "%d %s %s %ld", &LINE.grpnr, LINE.grpname, LINE.username, &LINE.wert);
    

    Das Schwierigste bei der ganzen Sache ist das dynamische Reservieren des Speicherplatz für dein struct-Array. Am besten wärs, wenn du vorher unabhängig von dieser Aufgabe dich etwas mit malloc() und realloc() auseinandersetzt und da auch erstmal mit einfachen Sachen. Versuch z. B. erstmal, dass der Benutzer eine beliebige Anzahl an Zahlen eingeben kann (z. B. in ein dynamisches int-Array) und dass am Ende dann die Zahlen in umgekehrter Reihenfolge ausgegeben werden und z. B. noch die Summe ausgegeben wird (aber nicht gleich jeden eingegebenen Wert summieren, sonst verfehlt es den Sinn der Sache ;)).



  • Thanx AJ,

    hab mal noch ne kurze frage. Wie kann ich denn so ein struct in einer datei speichern?

    fputs(LINE, file);
    

    ...das funzt nicht



  • Das kommt drauf an, wie diese Datei weiterverwendet werden soll.

    Wenn du eine Textdatei brauchst (die Daten soll man sich also auch mit einem Texteditor ansehen können), dann solltest du das, in etwa so machen:

    //Daten werden durch Komma getrennt als Text in die Datei geschrieben
    //Datei mit der Option "wt" o. ä. geöffnet (im Textmodus)
    fprintf(datei, "%d,%s,%s,%ld\n", LINE.grpnr, LINE.gprname, LINE.username, LINE.wert);
    

    Eine andere Möglichkeit wäre diese (kann man sich nicht so einfach in einem Texteditor ansehen)

    //Daten werden als Binärdaten abgespeichert
    //Datei mit der Option "wb" o. ä. geöffnet (im Binärmodus)
    fwrite(&LINE, sizeof(LINE), 1, datei);
    

    Mit der letzten Variante könntest du sogar gleich das ganze struct-Array speichern:

    LINE datensaetze[20]; //der Einfachheit halber mal ein statisches Array
    ...
    //hier werden die datensaetze gefüllt
    ...
    //Datensätze schreiben
    fwrite(datensaetze, sizeof(LINE), 20, datei);
    ...
    


  • so, soweit funzt es. Und wenn jetzt beide Structs gefüllt sind, wie kann ich diese noch vergleichen und notfalls umschreiben?
    mein 1.struct sieht so aus:(überschriften sind spaltennamen)

    //test.txt
    GrNumber[10]   GrName[80]   Parameter[80]    Wert[80]
    
    112              Pros          Karl            345
    112              Pros          Peter           1111-111
    55               Tests         Werni           232
    

    ... so sieht die erste struct aus.

    die zweite struct sieht dann so aus:

    //bat.txt
    GrNumber      GrName           Para          Wer
    001            heros           knut          3456767
    044            other           kai           223
    044            other           kia           232
    112            Pros            ---           ---
    114            news            gerd          444
    

    ... wie kann ich jetzt diese beiden structs vergleichen.
    die bat.txt soll so lange durchgegangen werden, bis GrNumber und GrName (1.Eintrag aus test.txt) in bat.txt gefunden wurde. Wenn die gefunden wurden, dann sollen Parameter und wert ("---") in der bat.txt ersetzt werden... Aber wie?
    (Bitte mit Beispiel...)



  • Das sollte eigentlich nicht das große Problem sein, oder??

    Du musst deine 1. Struktur mit den Daten der test.txt einzeln durchgehen (also pro Datensatz) und dann bei jedem einzelnen Satz die 2. Struktur durchgehen, bis zu dem gewünschten Satz in der 2. Struktur. Also zwei verschachtelte Schleifen. Wenn du den Satz in der zweiten Struktur gefunden hast ersetzt du den Wert zum passenden Parameter mit dem Wert aus der ersten Struktur oder legst einen neuen Satz in der 2. Struktur an (wenn das gewünscht ist 😕 ).

    Ist eigentlich nicht mehr als z. B. in einem String einen Teilstring zu suchen und diesen zu ersetzen bzw. in deinem Fall mehrere Teilstrings zu suchen und zu ersetzen ;).



  • kannst du mir dafür ein Codebeispiel geben?



  • Ok, weil du es bist ;):

    typedef struct
    {
       int nr;
       char wert[20];
    } record;
    ...
    record anders[2] = {{2, "zwei"}, {3, "drei"}};
    int anzanders = 2;
    record daten[5] = {{1, "eins"}, {2, "two"}, {3, "three"}, {4, "vier"}, {5, "fünf"}};
    int anzdaten = 5;
    int i, j;
    ...
    for(i = 0; i < anzanders; ++i)
    {
       for(j = 0; j < anzdaten; ++j)
       {
          if(anders[i].nr == daten[j].nr)
          {
             strcpy(anders[i].wert, daten[j].wert);
          }
       }
    }
    ...
    

    Mehr ist nicht dabei. (In deinem Fall musst du die Bedingung hald noch etwas umstellen.)



  • danke, ist jetzt alles (eigentlich) klar... nur noch ne kurze frage: wie bekomme ich denn am besten die anzahl der datensätze des structs raus? Oder soll ich am besten gleich wenn ich das struct fülle einen zähler mitzählen lassen???



  • ruuuuudi schrieb:

    Oder soll ich am besten gleich wenn ich das struct fülle einen zähler mitzählen lassen???

    Ohne kommst du eh nicht aus, da du ohne einen Zähler der Funktion realloc() nicht den richtigen Wert übergeben kannst. Schließlich musst du den zu reservierenden Speicher aus der Anzahl der Datensätze mal dem Speicherbedarf der Struktur berechnen.


Anmelden zum Antworten