String array Problem -- Segmentation fault



  • allokieren muss nicht sein. aber zumindest solltest du sicherstellen, das arraygrenzen nicht überschritten werden können.

    gehen wir von einem byte pro zeichen aus:
    buffer[400]; <-- hier passen 400 zeichen rein, inklusive 0-terminator.
    char gericht[300][40]; <-- hier passen 300 * 40 zeichen rein. das sind also 300 zeilen, mit maximal 40 zeichen pro zeile(inklusive 0-terminator).

    fgets(buffer,128,fp); <-- hier werden maximal 128 zeichen (inklusive 0-terminator) in buffer reinkopiert, das ist ok.

    text = strtok(buffer, trennzeichen); <-- je nach position des trennzeichens in 'buffer' kann 'text' auf einen speicherbereich mit bis zu 398 zeichen zeigen
    (400 zeichen minus 0-terminator, minus trennzeichen), soweit ok.

    strcpy(gericht[i], text); <-- hier droht u.a. die gefahr eines überlaufs. weil die anzahl der zeichen, auf die 'text' zeigt, größer als 39 zeichen werden kann.



  • char string[2500];
    
    while (fgets(string,25000,fp))
    

    2500 != 25000...



  • Jetzt habe ich gericht auf [300][400] geändert.
    Hat aber leider auch nichts gebracht. Er bricht immmernoch in der zweiten Schleife ab, egal wie gross ich string setze, und immer an der selben Stelle

    So langsam verzweifele ich hier....



  • ist gericht das einzige array, das überlaufen kann?
    wie kommen die daten in die variable dateiname?
    hast du die zeile text=strtok(buffer, trennzeichen);
    aus der schleife rausgeholt und über diese geschrieben?

    char trennzeichen[]= " = ";

    bist du sicher, das du auch an leerzeichen trennen willst?
    hast du fclose(fp2) abgesichert?
    usw...
    du hast noch einiges aufzuarbeiten. vielleicht postest du noch einmal den überarbeiteten code vollständig.



  • hier noch mal der " abgeänderte" code.

    ich kann doch das text = strtok(buffer, trennzeichen); nicht vor die Schleife setzen, da ich es ja für jede Zeile benötige.
    das Schließen von fp2 müsste doch durch das öffnen mit a+ abgesichert seine oder?
    Der erstellt doch eine neue Datei sollte sie nicht vorhanden seien

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main(void) {
    
      FILE *fp;
      FILE *fp2;
      char dateiname[40];
      char trennzeichen[]= " = ";
      char buffer[400];
      char buffer2 [250000];
      char *string;
      char gericht[300][400];
      char subnet[300][400];
      char *text;
      int i=0, j=0;
    
    //Netze-Datei oeffnen und alle felder in ein array fuellen
        if ((fp =fopen("test.txt", "r")) != NULL  )
        { //printf ("alles takko\n");
          while (fgets(buffer,128,fp))
          {
           text=strtok(buffer, trennzeichen);
           //printf (text);
           strcpy(gericht[i], text);      
           text = strtok(NULL, trennzeichen);
           strcpy(subnet[i], text);
           i++; 
          }
          j=i;
          strcpy(subnet[i], "exit"); 
          //printf (gericht[4]);
          //printf (subnet[i-1]);
          //getchar();
          fclose(fp);
        }
        else
        {
            printf ("fehler beim oeffnen der Datei\n");
            printf (dateiname);
            getchar();
        }
    
        if ((fp =fopen("access-2009-06-16.log", "r")) != NULL  )
        {
         while (fgets(buffer2,250000,fp))
         {  
                 string = (char*) malloc(strlen(buffer2));                        
                 strcpy(string, buffer2);  
                 i=0;
                 while (i<j)
                 {
    
                 text=strtok(subnet[i], "\n");
                 //printf (subnet[i], "\n");
                  if( strstr(string, text) != NULL)
                  {
                      if ((fp2 =fopen(gericht[i], "a+")) != NULL  )
                      fprintf(fp2, string, "\n");
                      //printf (subnet[i],"\n");
                      //printf (string,"\n");
                      //printf (gericht[i],"\n");
                      //getchar();
                      fclose(fp2);
    
                  }
                  i++;
                 }
         }
         getchar();
        } 
    
        else
        {
            printf ("fehler beim oeffnen der Datei\n");
            printf (dateiname);
            getchar();
        }
    
    return 0;
    }
    


  • printf (dateiname);

    was hier wohl ausgegeben wird *grübel*

    string = (char*) malloc(strlen(buffer2));
    strcpy(string, buffer2);

    hier gibt es wieder einen netten überlauf, weil ein zeichen für die terminierung fehlt.



  • Sorry wenn ich mich ein bisschen blöd anstelle, aber anscheinend habe ich nun komplett den Überblick verloren...
    Das Problem ist glaube ich das ich C das letzte mal vor 10 Jahren in der Ausbildung gemacht habe und hier nun keinen Faden mehr finde.

    Also was ich damit sagen will, ist das mir ein etwas detailierter Tipp glaube ich weiterhelfen könnte.

    Danke fpr deine Ausdauer

    Ralph



  • hmmm ... okay,
    eine zeichenkette in c schließt mit einer 0 ab.
    angenommen, du willst die zeichenkette "abc" speichern:
    strlen("abc") ist gleich 3, strlen zählt die 0 nicht mit.
    wegen der abschließenden 0 brauchst du aber platz für 4 zeichen, weil die 0
    auch speicherplatz belegt.

    darum ist also
    char* p = malloc(strlen("abc"));
    nicht ausreichend, weil der platz für die 0 fehlt.

    und darum
    gibt es für strcpy(p,"abc");
    einen überlauf, weil strcpy keine arraygrenzen prüft und die 0 in nichtallokierten speicherbereich kopiert.

    korrekt wäre also
    char* p = malloc(strlen("abc") +1);
    nun kannst du auch beruhigt
    strcpy(p,"abc");
    aufrufen, die funktion strcpy sorgt für die terminierung, d.h. die 0 wird von der funktion an die letzte freie stelle kopiert.

    nunja und im übrigen ist die verwendung von strtok ein wenig unglücklich gewählt, hast du dir mal die zwischenergebnisse anzeigen lassen?
    die verwendung von festen arraygrößen ist auch überdenkenswert.

    was wird hier ausgegeben:
    printf (dateiname);
    ?
    was steht in dateiname drin? 😉

    gruß,
    *0r



  • Beim if in Zeile 63 mußt du geschweifte Klammern verwenden. Sonst wird fclose(fp2) selbst dann aufgerufen, wenn das öffnen der Datei fehlgeschlagen ist.

    Du verwendest printf() und fprintf() falsch. ZB in Zeile 64 mußt du

    fprintf(fp2, "%s\n", string);
    

    schreiben.

    Um herauszufinden ob die Stringlängen das Problem sind kannst du auch das Makro assert verwenden. ZB kannst du in Zeile 26

    assert(strlen(text)<400)
    

    schreiben. Assert beendet das Programm mit einer Fehlermeldung, wenn die Bedingung nicht erfüllt ist. Ist das Makro NDEBUG definiert, dann wird assert durch einen leeren Austruck ersetzt und benötigt weder Speicher noch Rechenzeit. Um assert verwenden zu können muß am Anfang des Programms

    #include <assert.h>
    

    stehen.



  • Das in dateiname nichts steh ist mir schon klar, ist nur noch ne Altlast.

    Das feste array größen nicht das Gelbe vom Ei sind ist mir bewusst, ich hab bloss keinen Schimmer wie ich den Speicher dynamisch zuweisen soll, bevor ich den String aus der Datei gelesen habe.

    auf jeden Fall habe ioch glaube ich jetzt alles nochmal nagepasst

    sieht nun wie folgt aus

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <assert.h>
    
    int main(void) {
    
      FILE *fp;
      FILE *fp2;
      FILE *fp3;
      char dateiname[40];
      char trennzeichen[]= " = ";
      char buffer[400];
      char buffer2 [25000];
      char *string;
      char gericht[300][400];
      char subnet[300][400];
      char *text;
      int i=0, j=0, code=0, stringlang=0;
    
    //Netze-Datei oeffnen und alle felder in ein array fuellen
        if ((fp =fopen("test.txt", "r")) != NULL  )
        { //printf ("alles takko\n");
          while (fgets(buffer,128,fp))
          {
           text=strtok(buffer, trennzeichen);
           assert(strlen(text)<400);
           //printf (text);
           strcpy(gericht[i], text);
           printf(gericht[i],"\n");
           printf("\n");     
           text = strtok(NULL, trennzeichen);
           strcpy(subnet[i], text);
           printf(subnet[i],"\n");
           i++; 
          }
          j=i;
          strcpy(subnet[i], "exit"); 
          //printf (gericht[4]);
          //printf (subnet[i-1]);
          //getchar();
          fclose(fp);
          getchar();
        }
        else
        {
            printf ("fehler beim oeffnen der Datei\n");
            printf (dateiname);
            getchar();
        }
    
        if ((fp3 =fopen("access.log", "r")) != NULL  )
        {
         while (fgets(buffer2,25000,fp))
         {  
                 assert(strlen(buffer2)<25000);
                 stringlang = (strlen(buffer2))+1;
                 string = (char*) malloc(stringlang); 
                 //stringlang = strlen(string);                       
                 strncpy(string, buffer2,stringlang);
                 i=0;
                 while ((i<j))
                 {
    
                 text=strtok(subnet[i], "\n");
                 //printf (subnet[i], "\n");
                  if( strstr(string, text) != NULL)
                  {
    
                      if ((fp2 =fopen(gericht[i], "a+")) != NULL  )
                      {
                      fprintf(fp2, "%s\n", string);
                      code = 1;
                      //printf (subnet[i],"\n");
                      printf (string,"%s\n");
                      //free(string);
                      //printf (gericht[i],"\n");
                      //getchar();
                      fclose(fp2);
                      //free(buffer);
                      }
    
                  }
                  i++;
                 }
         }
         fclose(fp3);
         getchar();
        } 
    
        else
        {
            printf ("fehler beim oeffnen der Datei\n");
            printf (dateiname);
            getchar();
        }
    
    return 0;
    }
    

    KLappt aber trotzdem nicht 😞 Un er bricht auch nicht beim Asset ab



  • rja schrieb:

    KLappt aber trotzdem nicht

    guck dir nochmal das mit der strtok funktion an.
    schreib dir ein kleines beispielprogramm, das dir eine zeichenkette zerlegt, z.b.
    char test[] "abc = 123 \n def = 456 \n ghi = 789";

    versuche dich mit einem debugger anzufreunden, damit du dir den inhalt von variablen angucken kannst.


Anmelden zum Antworten