Speicherverwaltung - Laufzeitfehler - malloc()/free()/etc.



  • Hallo Freunde 😉

    Ich habe mal wieder ein Problem bei dem ich allein nicht weiterkomme.
    In meinem Programm arbeite ich mit verketteten Listen, die ich in C ja per struct{} definiere.
    1. Diese Listen können länger werden (ca. 150 Einträge)
    2. Die Daten der einzelnen Listenelemente sind unterschiedlich lang:
    - Es wird aus einer Pipe ein Stream zeilenweise gelesen
    - Die Zeile wird in einen charbuffer kopiert, der im gleichen Prozess als Speicher die Stringlänge der eingelesenen Zeile bekommt. ( = malloc(strlen()))
    - die jeweilige Zeile im char
    buffer wird auf Schlüssel-Teil-Strings untersucht(geparst)
    - wenn einer dieser Schlüssel-Strings in der eingelesenen Zeile vorhanden ist, so wird der Zeileninhalt des buffers per strtok() auf den gewünschten Inhalt heruntergebrochen
    - Nun wird der Token(Teilstring) auf den heruntergebrochen wurde in eine Variable des Dateninhalts des Listenelements kopiert.

    Ich habe versucht, den Speicherplatz so gut wie möglich zu schonen und deshalb folgenden Code zusammengehackt:

    Definition des Structs für die Liste in der Header.h:

    struct struct_host
    {
      char *name;
      char *ipadr;
      char *macadr;
      char *vendor;
      char *os;
    
      struct struct_host *next;
      struct struct_port *ports;
    };
    

    Im Programm main.c:

    FILE *ptpipe = popen(cmd_output, "r");
      char *ptline_in = (char *) malloc(1000);
      size_t istorage = 1000;
    
      char *line_buffer;
    
      do
      {
          getline(&ptline_in, &istorage, ptpipe);
    
          if(strstr(ptline_in, "<host ") || strstr(ptline_in, "<host>"))
          {
    	found_hosts++;
    
    	ptnewHost		= (_host) malloc(sizeof(struct struct_host));
    	ptnewHost->name		= "<Unbekannt>";
    	ptnewHost->ipadr	= "<Unbekannt>";
    	ptnewHost->macadr	= "<Unbekannt>";
    	ptnewHost->vendor	= "<Unbekannt>";
    	ptnewHost->next		= NULL;
    	ptnewHost->ports	= NULL;
    
            // Host in Host-Liste aufnehmen:
    	// Wenn Host-Liste leer	...
    	if(ptstartHost == NULL)
    	{
    	  ptstartHost = ptnewHost;
    	  ptlastHost = ptnewHost;
    	}
    	else // Wenn schon Hosts in Liste ...
    	{
    	  ptlastHost->next = ptnewHost;
    	  ptlastHost = ptnewHost;
    	}
          }
    
          // Hostname
          if(strstr(ptline_in, "<hostname "))
          {
    	strcpy(line_buffer = (char*) malloc(strlen(ptline_in)), ptline_in);
    
    	line_buffer = strtok(line_buffer, "\"");
    	line_buffer = strtok(NULL, "\"");
    
    	strcpy(ptnewHost->name = malloc(strlen(line_buffer)), line_buffer);
          }
    
          //Adresse (IP/MAC)
          if(strstr(ptline_in, "<address "))
          {
            // Adresse -> IP
            if(strstr(ptline_in, "ipv4"))
            {
              strcpy(line_buffer = (char*) malloc(strlen(ptline_in)), ptline_in);
              line_buffer = strtok(line_buffer, "\"");
              line_buffer = strtok(NULL, "\"");
              strcpy(ptnewHost->ipadr = (char*) malloc(strlen(line_buffer)), line_buffer);
            }
          }
    
          free(line_buffer);
    
      }while(strstr(ptline_in, "</nmaprun>") == NULL);
    

    Nun bekomme ich beim Programmaufruf folgenden Fehler-Code-Block:

    *** Error in `./iNmapTool': double free or corruption (out): 0x00007fffa6e4e060 ***
    ======= Backtrace: =========
    /lib64/libc.so.6(+0x7afc6)[0x7f4fd8b91fc6]
    /lib64/libc.so.6(+0x7bd43)[0x7f4fd8b92d43]
    ./iNmapTool[0x4015fa]
    ./iNmapTool[0x400ef1]
    /lib64/libc.so.6(__libc_start_main+0xf5)[0x7f4fd8b38a15]
    ./iNmapTool[0x400b49]
    ======= Memory map: ========
    00400000-00403000 r-xp 00000000 08:02 6425638                            /home/praktikant/Dokumente/iNmapTool/iNmapTool
    00602000-00603000 r--p 00002000 08:02 6425638                            /home/praktikant/Dokumente/iNmapTool/iNmapTool
    00603000-00604000 rw-p 00003000 08:02 6425638                            /home/praktikant/Dokumente/iNmapTool/iNmapTool
    01ea4000-01ec5000 rw-p 00000000 00:00 0                                  [heap]
    7f4fd84ca000-7f4fd84df000 r-xp 00000000 08:02 7602188                    /lib64/libgcc_s.so.1
    7f4fd84df000-7f4fd86de000 ---p 00015000 08:02 7602188                    /lib64/libgcc_s.so.1
    7f4fd86de000-7f4fd86df000 r--p 00014000 08:02 7602188                    /lib64/libgcc_s.so.1
    7f4fd86df000-7f4fd86e0000 rw-p 00015000 08:02 7602188                    /lib64/libgcc_s.so.1
    7f4fd86e0000-7f4fd8709000 r-xp 00000000 08:02 7602181                    /lib64/libtinfo.so.5.9
    7f4fd8709000-7f4fd8909000 ---p 00029000 08:02 7602181                    /lib64/libtinfo.so.5.9
    7f4fd8909000-7f4fd890d000 r--p 00029000 08:02 7602181                    /lib64/libtinfo.so.5.9
    7f4fd890d000-7f4fd8912000 rw-p 0002d000 08:02 7602181                    /lib64/libtinfo.so.5.9
    7f4fd8912000-7f4fd8913000 rw-p 00000000 00:00 0 
    7f4fd8913000-7f4fd8916000 r-xp 00000000 08:02 7602335                    /lib64/libdl-2.17.so
    7f4fd8916000-7f4fd8b15000 ---p 00003000 08:02 7602335                    /lib64/libdl-2.17.so
    7f4fd8b15000-7f4fd8b16000 r--p 00002000 08:02 7602335                    /lib64/libdl-2.17.so
    7f4fd8b16000-7f4fd8b17000 rw-p 00003000 08:02 7602335                    /lib64/libdl-2.17.so
    7f4fd8b17000-7f4fd8cbb000 r-xp 00000000 08:02 7602310                    /lib64/libc-2.17.so
    7f4fd8cbb000-7f4fd8ebb000 ---p 001a4000 08:02 7602310                    /lib64/libc-2.17.so
    7f4fd8ebb000-7f4fd8ebf000 r--p 001a4000 08:02 7602310                    /lib64/libc-2.17.so
    7f4fd8ebf000-7f4fd8ec1000 rw-p 001a8000 08:02 7602310                    /lib64/libc-2.17.so
    7f4fd8ec1000-7f4fd8ec5000 rw-p 00000000 00:00 0 
    7f4fd8ec5000-7f4fd8eea000 r-xp 00000000 08:02 7602276                    /lib64/libncurses.so.5.9
    7f4fd8eea000-7f4fd90e9000 ---p 00025000 08:02 7602276                    /lib64/libncurses.so.5.9
    7f4fd90e9000-7f4fd90ea000 r--p 00024000 08:02 7602276                    /lib64/libncurses.so.5.9
    7f4fd90ea000-7f4fd90eb000 rw-p 00025000 08:02 7602276                    /lib64/libncurses.so.5.9
    7f4fd90eb000-7f4fd910c000 r-xp 00000000 08:02 7613489                    /lib64/ld-2.17.so
    7f4fd92e2000-7f4fd92e6000 rw-p 00000000 00:00 0 
    7f4fd9309000-7f4fd930c000 rw-p 00000000 00:00 0 
    7f4fd930c000-7f4fd930d000 r--p 00021000 08:02 7613489                    /lib64/ld-2.17.so
    7f4fd930d000-7f4fd930e000 rw-p 00022000 08:02 7613489                    /lib64/ld-2.17.so
    7f4fd930e000-7f4fd930f000 rw-p 00000000 00:00 0 
    7fffa6e2e000-7fffa6e50000 rw-p 00000000 00:00 0                          [stack]
    7fffa6f1f000-7fffa6f20000 r-xp 00000000 00:00 0                          [vdso]
    ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
    Abgebrochen
    

    Was habe ich falsch gemacht?
    Wo habe ich zu viel allokiert?
    Wo zu wenig?
    Wo vergessen zu free()-en?

    Liebe Grüße und Danke an diejenigen, die hier durchsteigen und mir helfen können! 🙂
    Felix



  • 1. Mit malloc(strlen())) besorgst du zuwenig Speicher.
    2. malloc kann auch NULL zurück liefern.
    3. strtok verändert den Quellstring (hier nicht dein Problem)
    4. Du weist line_buffer nach dem malloc mehrmals neue Werte zu. Dann bekommt free eine falsche Adresse mit gegeben.
    5. der cast beim malloc ist überflüssig.



  • Der Code ist ziemlich konfus,
    - pclose vergessen
    - free zu wenig und auf falsche (weil zwischenzeitlich geänderte) Zeiger angewendet
    - zuwenig Speicher bei malloc ( strlen()+1 )
    - Cast bei malloc ( redundantes C++ Zeugs )
    - verkettete Liste ist prinzipiell zu vermeiden weil fehleranfällig und inperformant
    - getline-Schleife ist bei dir prinzipiell falsch ( Abbruchbedingung falsch )
    - strtok ist nicht reentrant ( und ist deshalb prinzipiell zu vermeiden insbesondere im Multithread-Umfeld ), besser sscanf
    - fehlendes free für Elemente der verk.Liste
    - ...



  • DirkB schrieb:

    1. Mit malloc(strlen())) besorgst du zuwenig Speicher.
    2. malloc kann auch NULL zurück liefern.
    3. strtok verändert den Quellstring (hier nicht dein Problem)
    4. Du weist line_buffer nach dem malloc mehrmals neue Werte zu. Dann bekommt free eine falsche Adresse mit gegeben.
    5. der cast beim malloc ist überflüssig.

    Wutz schrieb:

    Der Code ist ziemlich konfus,
    - pclose vergessen
    - free zu wenig und auf falsche (weil zwischenzeitlich geänderte) Zeiger angewendet
    - zuwenig Speicher bei malloc ( strlen()+1 )
    - Cast bei malloc ( redundantes C++ Zeugs )
    - verkettete Liste ist prinzipiell zu vermeiden weil fehleranfällig und inperformant
    - getline-Schleife ist bei dir prinzipiell falsch ( Abbruchbedingung falsch )
    - strtok ist nicht reentrant ( und ist deshalb prinzipiell zu vermeiden insbesondere im Multithread-Umfeld ), besser sscanf
    - fehlendes free für Elemente der verk.Liste
    - ...

    Okay und dann bitte verbesserungsvorschläge .. Ich komm mir gerade etwas überrannt vor. Okay ich weis, ich habe gefragt, aber das ist doch jetzt zeimlich viel ..
    Kurz zum Background: Ich habe alles was ich in C kann in den letzten 1,5 Monaten mit Google/Openbooks.Galileo Computing gelernt ..
    Bzw. also die einfachsten Grundkenntnisse der Programmierung mit Datentypen und so kannte ich schon aber diese ganzen Standart-C-Funktionen wie str... und malloc etc. hatte ich erst mühe mir das rauszusuchen was passte ..
    Bei manchen der Antworten wusste ich gar nicht was gemeint ist ..

    - strtok ist nicht reentrant ( und ist deshalb prinzipiell zu vermeiden insbesondere im Multithread-Umfeld ), besser sscanf

    ?

    Danke für die Antworten .. 😉

    Kurz zu den einzelnen Punkten:

    DirkB
    - warum zu wenig Speicher? Wegen dem \0 ??
    - in welchem fall hat malloc denn 0? Die Länge des Strings ist doch immer mindestens ein paar Zeichen lang (strlen()) ..?
    - weil strtok den Quellstring verändert habe ich ja extra den buffer genommen den string dort reinkopiert und danach den buffer mit strtok bearbeitet und nicht die ursprüngliche LINE_IN Variable (ptline_in)
    - also müsste ich nach jedem strcpy( Variable_eines_elemnts, line_buffer) free(line_buffer); aufrufen?
    - cast .. okay .. hab ich aus diesem C von A bis Z von Jürgen Wolf oder so .. bei Galileo Open Books.

    Ich hab jetzt schon gehört bei meiner letzten Frage hier im Forum dass das kakke ist das material von dem Verlag, aber ich habe nichts vergleichbar großes gesehn auf deutsch und zum online komplett free lesen.

    Wutz:

    - pclose hab ich vergessen, ändere ich! - Danke 😉
    - free(): ich will doch nur den buffer wieder freigeben, der zum "runterrechen" des langen Line_IN streams war .. Wenn ich anderen Speicher freigebe, dann sind doch auch die eingetragenen Daten der Elemente der Liste weg ..?
    - verkettete Liste zu vermeiden .. wie? Was soll man sonst nehmen? Also ich speichere in dem Struct, wie oben ja zu sehen die Daten zu den einzelnen Rechnern im Netzwerk. Was eignet sich besser als eine linked List?
    - die abbruchbedingung der do - while schleife, in der getline() jeweils als erstes einmal aufgerufen wird ist doch so, wie ich es bracuhe .. , da bei der xml ausgabe von Nmap, wie ich sie parse das </nmaprun> tag in der letzten zeile der asugabe steht!
    - ich habe versucht mit sscanf zu arbeiten, jedoch habe ich nirgends gefunden, wie ich den langen zeilen string in die für mich notwendigen teilstrings runtergebrochen bekomme .. oder gibt es etwas wie platzhalter für eine belibeige länge von zeichen in scanf (wie bei sql mit dem % oder * )??
    - wenn ich die elemente der verketteten liste wieder free() dann kann ich doch gar nicht mehr drauf zugreifen weil der speicher freigegeben wurde oder nicht?
    ich brauche die elemente später zur ausgabe noch ...



  • mekick schrieb:

    Kurz zu den einzelnen Punkten:

    DirkB
    - warum zu wenig Speicher? Wegen dem \0 ??
    - in welchem fall hat malloc denn 0? Die Länge des Strings ist doch immer mindestens ein paar Zeichen lang (strlen()) ..?

    Ja, wegen '\0' brauchst Du ein Byte mehr.
    malloc gibt 0 zurück, wenn es den angeforderten Speicher nicht beschaffen konnte.

    Hier:

    strcpy(line_buffer = (char*) malloc(strlen(ptline_in)), ptline_in);
    

    beschaffst Du Speicher (zuwenig), auf den line_buffer zeigt.

    Hier:

    line_buffer = strtok(line_buffer, "\"");
        line_buffer = strtok(NULL, "\"");
    

    zeigt line_buffer aber nicht mehr auf den beschafften Speicher, so dass hier:

    free(line_buffer);
    

    der Speicher nicht mehr freigegeben werden kann.



  • Kurz zu den einzelnen Punkten:
    - warum zu wenig Speicher? Wegen dem \0 ??

    Ja.

    - in welchem fall hat malloc denn 0? Die Länge des Strings ist doch immer mindestens ein paar Zeichen lang (strlen()) ..?

    Nicht 0 sondern NULL . Schau dir die Referenz zu malloc an.
    Dann weißt du was es wann, wie und warum macht und zurückgibt.
    Z.B.: da http://www.cplusplus.com/reference/cstdlib/malloc/

    - weil strtok den Quellstring verändert habe ich ja extra den buffer genommen den string dort reinkopiert und danach den buffer mit strtok bearbeitet und nicht die ursprüngliche LINE_IN Variable (ptline_in)

    War auch nur als Hinweis gemeint.

    - also müsste ich nach jedem strcpy( Variable_eines_elemnts, line_buffer) free(line_buffer); aufrufen?

    Nein.
    Eine anderen Pointer für den Rückgabewert von strtok verwenden.
    Allerdings musst du den Speicher freigeben, bevor du den letzten Verweis darauf überschreibst.

    - cast .. okay .. hab ich aus diesem C von A bis Z von Jürgen Wolf oder so .. bei Galileo Open Books.

    Hast ja selber gelesen dass das Buch keinen guten Ruf hat. Einen Grund weißt du jetzt.

    - strtok ist nicht reentrant ( und ist deshalb prinzipiell zu vermeiden insbesondere im Multithread-Umfeld ), besser sscanf
    ?

    strok merkt sich den letzten Zustand (sonst könntest du es nicht mit NULL als ersten Paramter aufrufen) Daher kann es nur einen String zu einer Zeit bearbeiten. Mehrere Threads oder noch ein (versteckter) Aufruf in einer Unterfunktion bringen das alles durcheinander.

    - ich habe versucht mit sscanf zu arbeiten, jedoch habe ich nirgends gefunden, wie ich den langen zeilen string in die für mich notwendigen teilstrings runtergebrochen bekomme .. oder gibt es etwas wie platzhalter für eine belibeige länge von zeichen in scanf (wie bei sql mit dem % oder * )??

    Du suchst doch Trennzeichen, keine Platzhalter.
    scanf ist sehr mächtig. Unter anderem gibt es auch einen Formatspecifier für ein scanset %[
    Kannst du auch unter www.cplusplus.com/reference/clibrary/cstdio/scanf/ nachlesen



  • Ah okay!

    Vielen Dank schonmal, das erste hab ich verstanden!

    Und wie bekomme ich den Speicher des line_buffer s wieder freigegeben, wenn ich doch strtok() benötige um mir meinen gewünschten teilstring auszulesen?

    gibt es dafür einen Tip? 🙂

    Liebe Grüße,
    Felix



  • mekick schrieb:

    Google/Openbooks.Galileo Computing gelernt ..

    Tja, das war der Griff ins Klo. Pfuscher JW hat keine Ahnung, kann nichts und macht alles falsch. Und du auch, wenn du C nach diesem Pfusch lernst. Siehe auch:
    http://www.c-plusplus.net/forum/272350-full

    Mit free der Elemente war gemeint, dass das am Ende der Funktion/des Programms geschehen soll.
    Verk. Listen sind besser durch unverk. struct-Listen bzw. struct-Arrays zu ersetzen, egal was irgendwelche Buchautoren oder Hochschulprofessoren behaupten.

    Klassisch sieht eine zeilenweise Verarbeitung von Textdateien in standardkonformen C so aus:

    FILE *f = fopen("datei.txt","r");
    char zeile[1000];
    if( !f )
      perror("datei.txt"),exit(1);
    while( fgets(zeile,1000,f) )
    {
      funktion(zeile);
    }
    fclose(f);
    

    Da du Linux hast, kannst du POSIX (getline,popen usw.) nutzen, für dich also dann in etwa

    typedef struct {....} Eintrag;
    typedef struct {Eintrag *eintraege;int z;} Liste;
    
    Liste liste={0};
    FILE *f = popen(cmd_output, "r");
    size_t st = 1000;
    char *line = malloc(st);
    
    if( !f )
      perror(cmd_output),free(line),exit(1);
    while( getline(&line, &st, f)> -1 )
    {
      verarbeite(line,&liste);
    }
    free(line);
    pclose(f);
    dann hier noch irgendwas mit < liste > machen...
    free(liste.eintraege); /* zum Schluss wieder freigeben */
    

    Ich hoffe, du erkennst das Schema.
    Trenne Funktionalitäten in verschiedene Funktionen auf, das ist besser lesbar, wartbar, debugbar...



  • DirkB schrieb:

    Kurz zu den einzelnen Punkten:
    - ich habe versucht mit sscanf zu arbeiten, jedoch habe ich nirgends gefunden, wie ich den langen zeilen string in die für mich notwendigen teilstrings runtergebrochen bekomme .. oder gibt es etwas wie platzhalter für eine belibeige länge von zeichen in scanf (wie bei sql mit dem % oder * )??

    Du suchst doch Trennzeichen, keine Platzhalter.
    scanf ist sehr mächtig. Unter anderem gibt es auch einen Formatspecifier für ein scanset %[
    Kannst du auch unter www.cplusplus.com/reference/clibrary/cstdio/scanf/ nachlesen

    Aber bei sscanf() muss man doch immer genau das angeben was gescannt wird, das heist wenn ich eine zeile habe mit ungeregeltem input (dh. bei einem input_line kann es sein dass im gegensatz zu dem davor ein ganzes tag-attribut fehlt [zB: reason="arp-response"] und wenn ich dann mit scanf einlesen will muss ich doch irgendwie alles abspeichern in irgendwelchen variablen oder ich brauche platzhalter ..?

    Oder könntest du mir kurz einmal einen sscanf aufruf als beispiel texten, der folgende aufgabe erfüllt:

    <hostname name="test02.meinedomäne.de" type="PTR"/>
    
    <port protocol="tcp" portid="3389"><state state="open" reason="syn-ack" reason_ttl="128"/><service name="ms-wbt-server" method="table" conf="3"/></port>
    <port protocol="tcp" portid="5357"><state state="open" reason="syn-ack" reason_ttl="128"/><service name="wsdapi" method="table" conf="3"/></port>
    <port protocol="tcp" portid="8081"><state state="open" reason="syn-ack" reason_ttl="128"/><service name="blackice-icecap" method="table" conf="3"/></port>
    

    und dabei jetzt allgemein:

    wenn "<hostname " in line_in steht soll der name in ptnewHost->hostname eingelesen werden,
    wenn "<port " drin steht soll protocol in ptnewPort->protocol, portid in ptnewPort->portid und der servicename in ptnewPort->service_name eingelesen werden.

    how to sscanf that?

    Bitte um Entschuldigung, es kann durchaus passieren, dass ich mir gleich die Hände überm Kopf zusammenschlage und denke: warum bin ich da denn die letzten Wochen nicht drauf gekommen bitte ...?

    LG
    Felix



  • mekick schrieb:

    Und wie bekomme ich den Speicher des line_buffer s wieder freigegeben, wenn ich doch strtok() benötige um mir meinen gewünschten teilstring auszulesen?

    Indem du den Pointer line_buffer nicht für den Rückgabewert von strtok missbruachst sondern einen anderen dafür definierst.

    char *pointer_fuer_Rueckgabewert_von_strok; // *pc geht auch
    ....
    pointer_fuer_Rueckgabewert_von_strok = strtok(line_buffer, "\"");
    


  • DirkB schrieb:

    mekick schrieb:

    Und wie bekomme ich den Speicher des line_buffer s wieder freigegeben, wenn ich doch strtok() benötige um mir meinen gewünschten teilstring auszulesen?

    Indem du den Pointer line_buffer nicht für den Rückgabewert von strtok missbruachst sondern einen anderen dafür definierst.

    char *pointer_fuer_Rueckgabewert_von_strok; // *pc geht auch
    ....
    pointer_fuer_Rueckgabewert_von_strok = strtok(line_buffer, "\"");
    

    könntest du das mal in einer schleife für getline() zeigen, ich bekomme das nicht hin.
    ich wüsste auch gar nicht wo ich die definition von *pc / *pointer_fuer_Rueckgabewert_von_strok hintun sollte .. wenn ich sie über die schleife mache muss ich ja wieder mit malloc die speicherreservierung machen .. -.- dieses schei*** malloc geht mir langsam auf den sack :s 😞

    Danke für Antworten ..

    Felix



  • Jammere hier nicht rum.
    Es wurde gesagt und gezeigt, was falsch ist und wie es richtig geht.
    Wenn du das nicht umsetzt, bist du selbst schuld brauchst nicht rumjammern.
    Ich habe dir z.B. empfohlen, die getline-Schleife und die eigentliche Stringverarbeitung zu trennen, d.h. die wesentlichen Aktionen laufen dann in der Funktion ab, während die übergeordnete getline-Schleife ausschließlich für das zeilenweise Lesen zuständig ist und auch genau 1x free benötigt und nicht mehr.

    FILE *f = popen(cmd_output, "r");
    size_t st = 1000;
    char *line = malloc(st);
    
    if( !f )
      perror(cmd_output),free(line),exit(1);
    while( getline(&line, &st, f)> -1 )
    {
      verarbeite(line,&liste);
    }
    free(line);
    


  • Okay ich versuche jetzt alles so umzusetzen .. muss dann allerdings etwas früher anfangen ...

    Warum ist das so, dass man wenn man das in eine Funktion Out-Sourced nur einmal dieses free für die Funktion braucht? Werden alle anderen Variablen und Speicher nach dem Funktionsaufruf/dessen Ausführung wieder freigegeben?

    Wutz schrieb:

    Mit free der Elemente war gemeint, dass das am Ende der Funktion/des Programms geschehen soll.
    Verk. Listen sind besser durch unverk. struct-Listen bzw. struct-Arrays zu ersetzen, egal was irgendwelche Buchautoren oder Hochschulprofessoren behaupten.

    was ist eine "unverkettete struct-liste" ?

    Ich kann mir gerade nciht vorstellen, wie man eine unverkettete Liste erstellen soll, da kann man dann ja gar nicht per zähl-schleife die Elemente abfragen ..?

    LG
    Felix


  • Mod

    mekick schrieb:

    Warum ist das so, dass man wenn man das in eine Funktion Out-Sourced nur einmal dieses free für die Funktion braucht? Werden alle anderen Variablen und Speicher nach dem Funktionsaufruf/dessen Ausführung wieder freigegeben?

    Alle Variablen in deinem Programm funktionieren vollautomatisch. Nur Sachen, die du irgendwo von Hand erzeugst (malloc*), musst du auch wieder aufräumen.
    http://en.wikipedia.org/wiki/Automatic_variable

    was ist eine "unverkettete struct-liste" ?

    Das ist Wutz' poetische Beschreibung für ein Array. Die Fälle in denen eine verkettete Liste einem Array praktisch überlegen wäre, sind allesamt sehr konstruiert. Deswegen fällt die verkettete Liste als Datenstruktur in die Kategorie "theoretisch interessant, aber praktisch nicht relevant".

    *: Aber auch andere Sachen. Wenn man mit Dateien hantiert, hat man ja nur einen Zeiger auf ein FILE-Objekt. Mit open erzeugt man dann ein konkretes Objekt und mit close räumt man es wieder auf (Der Zeiger selbst fällt natürlich nach wie vor unter die automatischen Variablen).



  • SeppJ schrieb:

    mekick schrieb:

    Warum ist das so, dass man wenn man das in eine Funktion Out-Sourced nur einmal dieses free für die Funktion braucht? Werden alle anderen Variablen und Speicher nach dem Funktionsaufruf/dessen Ausführung wieder freigegeben?

    Alle Variablen in deinem Programm funktionieren vollautomatisch. Nur Sachen, die du irgendwo von Hand erzeugst (malloc*), musst du auch wieder aufräumen.
    http://en.wikipedia.org/wiki/Automatic_variable

    was ist eine "unverkettete struct-liste" ?

    Das ist Wutz' poetische Beschreibung für ein Array. Die Fälle in denen eine verkettete Liste einem Array praktisch überlegen wäre, sind allesamt sehr konstruiert. Deswegen fällt die verkettete Liste als Datenstruktur in die Kategorie "theoretisch interessant, aber praktisch nicht relevant".

    *: Aber auch andere Sachen. Wenn man mit Dateien hantiert, hat man ja nur einen Zeiger auf ein FILE-Objekt. Mit open erzeugt man dann ein konkretes Objekt und mit close räumt man es wieder auf (Der Zeiger selbst fällt natürlich nach wie vor unter die automatischen Variablen).

    DANKE! *check* 😉

    /*Edit*/

    Aber in meinem Programm weis vorher niemand wie viele Hosts und wie viele Ports pro Host vorhanden sind .. für genau solche Fälle sind doch Listen genau das richtige ..?
    Ich müsste sonst ja bei jedem neuen Host, der durchs Parsen hinzukommt, die Größe des Arrays erweitern/verändern ..?

    Lieben Gruß,
    Felix



  • DirkB schrieb:

    mekick schrieb:

    Und wie bekomme ich den Speicher des line_buffer s wieder freigegeben, wenn ich doch strtok() benötige um mir meinen gewünschten teilstring auszulesen?

    Indem du den Pointer line_buffer nicht für den Rückgabewert von strtok missbruachst sondern einen anderen dafür definierst.

    char *pointer_fuer_Rueckgabewert_von_strok; // *pc geht auch
    ....
    pointer_fuer_Rueckgabewert_von_strok = strtok(line_buffer, "\"");
    

    Das habe ich jetzt probiert gehabt und mich damit beschäftigt, jedoch ist das Problem, dass strtok() den Quell-String verändert. d.h. wenn ich folgendes schreibe:

    char *pc = strtok(line_buffer, "\"");
    

    wird der Zeiger line_buffer schon verändert.
    Ab da habe ich keine Möglichkeit mehr, den gesamten Speicher des ursprünglich allokierten line_buffer per free() freizugeben. So habe ich das bisher verstanden und da ist momentan mein Problem ...

    Liebe Grüße,
    Felix



  • mekick schrieb:

    Ich müsste sonst ja bei jedem neuen Host, der durchs Parsen hinzukommt, die Größe des Arrays erweitern/verändern ..?

    Und, wo ist das Problem?

    mekick schrieb:

    wird der Zeiger line_buffer schon verändert.
    Ab da habe ich keine Möglichkeit mehr, den gesamten Speicher des ursprünglich allokierten line_buffer per free() freizugeben.

    Und, wo ist das Problem?
    Die Leseschleife macht genau 1x malloc vor der Schleife und 1x free nach der Schleife und die Verarbeitungsfunktion in der Schleife bekommt automatisch eine Kopie des Zeigers übergeben, und mit dieser Kopie kannst du dann dein unseliges strtok aufrufen, sooft du willst.



  • 1. Ich weis noch nicht wie das mit dem größe verändern geht .. muss ich mir halt angucken ..

    2. Ich bin noch am rumtricksen, wie ich das hinbekomme mit einer funktion das zu verarbeiten, weil ich zwei listen brauche. Eine, in der die hosts alle aufgelistet sind und dann noch pro Listenelement der Hostliste eine eigene Liste, in der die Ports des jeweiligen Hosts aufgeführt sind.
    wie kann ich denn der Funktion zum verarbeiten sagen/mitgeben, dass sie pro element des Liste Arrays ein weiteres Array anlegen muss und dann halt mit daten füllen .. da hakts noch ..

    Muss ich da dann evtl in der einen verarbeite(..)-Funktion noch eine weitere funktion aufrufen um das zu realisieren? ..

    LG



  • mekick schrieb:

    char *pc = strtok(line_buffer, "\"");
    

    wird der Zeiger line_buffer schon verändert.
    Ab da habe ich keine Möglichkeit mehr, den gesamten Speicher des ursprünglich allokierten line_buffer per free() freizugeben. So habe ich das bisher verstanden und da ist momentan mein Problem ...

    Nein.

    line_buffer wird da nicht verändert. Der Bereich auf den line_buffer zeigt wird durch strtok verändert.
    Aber das ist auch erlaubt und gewünscht denn sonst hätte malloc ja keinen Sinn.



  • DirkB schrieb:

    mekick schrieb:

    char *pc = strtok(line_buffer, "\"");
    

    wird der Zeiger line_buffer schon verändert.
    Ab da habe ich keine Möglichkeit mehr, den gesamten Speicher des ursprünglich allokierten line_buffer per free() freizugeben. So habe ich das bisher verstanden und da ist momentan mein Problem ...

    Nein.

    line_buffer wird da nicht verändert. Der Bereich auf den line_buffer zeigt wird durch strtok verändert.
    Aber das ist auch erlaubt und gewünscht denn sonst hätte malloc ja keinen Sinn.

    Wenn ich jedoch genannte code-zeile so programmiere und evtl anschließend noch ein paar weitere

    pc = strtok(NULL, "\"");
    

    -Zeilen, wird durch free(line_buffer); nicht mehr der gesamte zuvor reservierte speicher freigegeben. Warum auch immer .. aber das ist fakt, denn nur da hängt mein memory leak ... an anderen stellen hab ich das manuelle allokieren aus meinem code verbannt ...


Anmelden zum Antworten