[c] null-terminiertes Array freen

haloo

Cadet 1st Year
Registriert
Feb. 2009
Beiträge
12
Hi,
welche Methode zum Aufräumen eines null-terminierten Arrays ist besser oder sind beide äquivalent (und mit ein bisschen Compiler Optimierung auch Code gleich)?

1.
Code:
char **array;
...
unsigned int / int i = 0;
while(array[i])
    free(array[i++]);
free(array);

2.
Code:
char **array;
...
char **backup = array;
while(*array)
    free(*array++);
free(backup);

mfg
 
Beide Methoden sind seltsam. Normalerweise allocierst Du ja das array als:

char *array = new char(100);


Dann ist die Länge vom allocierten Element klar. Du musst immer 100 Zeichen löschen, sonst bekommst Du ein Speicherleck.

Da ist es auch egal, wenn im Array nach 50 Zeichen ein \0 kommt. In Deinem Fall würden dann nämlich nur 50 Elemente gelöscht werden.

Frage ist auch noch, warum ein Doppelpointer? Ich habe sowas noch nie benutzt. Geht das überhaupt?

Ich gehe jetzt davon aus, Du programmierst C unter Windows? Oder in welcher Umgebung befinden wir uns?

Könntest Du mal noch sagen, was unter Punkt 2 steht. Da muss ja irgendwann der Speicher reserviert worden sein.

Hier noch ein Beispiel:

http://www.cplusplus.com/reference/cstdlib/malloc/

Hab oben versehentlich new geschrieben. Normal benutzt man dann aber delete zum löschen.

Also es muss immer new, delete oder malloc und free sein.
 
Zuletzt bearbeitet:
Irgendwann würde es krachen, weil du einfach mal auf andere Daten zuzugreifen versuchst. Dann bekommst du eine schöne Dialog Box mit "Programm funktioniert nicht mehr". ;) Bei Array-Arbeiten in C/C++ musst du immer eine Länge eines jeden Arrays in einer separaten Variable mitführen.
 
@Hellsfoul: Doppelpointer brauchst du z.B. für ein Array von Strings.. , normalerweise schreibt man das dann aber als
char str_array[100][100]; //100 Strings der Länge 100...

@haloo
meiner Meinung nach sind sie gleich, das sollte der compiler weg optimieren können.

einzig beim anlegen könntest vielleicht was gewinnen, das du nicht x mal malloc aufrufst, sondern einmal ein großen bereich holst und den intern selbst verwaltet. wobei du da sehr aufpassen musst, damit du einen Vorteil gegenüber obigen Code raus holst.

Und da Yuuri es erwähnt hat. Ich hoffe du weißt was du da machst. Weil der Code "stinkt" nach Speicherschutzverletzungen. Es kann funktionieren, Erfahrung zeigt aber das meistens wo was vergessen wurde!
 
Zuletzt bearbeitet:
Danke für eure Antworten.
Ich meinte ein Array von Strings.
Code:
array = malloc(k*sizeof(char *));
array[k] = malloc(i*sizeof(char));
 
Statt kein C zu können, aber einfach mal irgend einen Blödsinn zu antworten, der schlau klingt, oder herumzuraten, was der Compiler optimiert oder kaffeesatzzulesen, welcher Code generiert wird, gebe ich dir einfach mal einen sinnvollen Tip, der dir in Zukunft bei allen Fragen dieser Art oben genanntes erspart:

Halte den Compiler an, bevor er den Assembler aufruft und vergleiche den Output. Bei gcc geht das iirc mit der Option -S.
 
Zuletzt bearbeitet:
haloo schrieb:
Hi,

Code:
char **array;
...
char **backup = array;
while(*array)
    free(*array++);
free(backup);

Deine Schleife zum Löschen des Arrays ist nicht korrekt. Wenn wir mal davon ausgehen, daß du sowohl das äußere Array als auch die (in Form von Pointern auf ihr erstes Element) darin enthaltenen Arrays mit malloc() angelegt hast, dann solltest du nicht so lange durch das äußere Array rodeln, bis du auf einen Null-Pointer triffst sondern du solltest dir in einer separaten Variablen mitführen, wie viele "innere" Arrays du angelegt hast und dann auch genau so viele wieder freigeben. Also:


Code:
size_t numberOfArrays = 400;

// äußeres Array anlegen
char** outer = malloc( sizeof( char* ) * numberOfArrays );

// innere Arrays anlegen
for ( size_t i = 0; i < numberOfArrays ; ++i )
{
    outer[ i ] = malloc( ..... );
}

// ...

// innere Arrays wieder freigeben
for ( size_t i = 0; i < numberOfArrays ; ++i )
{
    free( outer[ i ] );
}

// äußeres Array freigeben
free( outer );
Ergänzung ()

the_nobs schrieb:
@Hellsfoul: Doppelpointer brauchst du z.B. für ein Array von Strings.. , normalerweise schreibt man das dann aber als
char str_array[100][100]; //100 Strings der Länge 100...

Was heißt hier "normalerweise"? Ob das Array, so wie du es getan hast, angelegt wird oder per malloc(), ist stark kontextabhängig. Was wäre z.B., wenn ich das Array lieber in der Göße 50000 x 50000 hätte, und zwar als lokale Variable in einer Funktion? Würdest du es dann so wie du anlegen, könnte dir da schon der Stack um die Ohren fliegen.
 
Wenn man vorher weiß, wie viele Elemente man allokieren will (wenn nicht, was übergäbe man malloc()?), ist es doch überhaupt kein Problem, ein Feld mehr anzufordern und das Letzte auf NULL zu setzen. Höchstwahrscheinlich nimmt OP eine minimale intellektuelle Eigenleistung der anderen Teilnehmer an. Verstehe nicht, was daran so verblüffend ist, dass das hier niemand versteht :(

€: Mir ist langweilig, also hier:

Code:
less cdb.c; gcc -o cdb -ggdb cdb.c; valgrind ./cdb
#include <stdlib.h>
#include <string.h>

#define ANZAHL_TOLLER_LEUTE 5

int main(void) {
        int i;
        char **tolle_leute = malloc((ANZAHL_TOLLER_LEUTE + 1) * sizeof(char*));

        if(tolle_leute == NULL)
                return EXIT_FAILURE;

        for(i = 0; i < ANZAHL_TOLLER_LEUTE; i++) {
                tolle_leute[i] = malloc(4);
                if(tolle_leute[i] == NULL) {
                        /* free(tolle_leute[0 .. i - 1] */
                        free(tolle_leute);
                        return EXIT_FAILURE;
                }
                strcpy(tolle_leute[i], "ich");
        }
        tolle_leute[i] = NULL; /* Vor dem Posten den Threadtitel zu lesen, hat gewisse Vorteile. Du weißt, wenn du gemeint bist. */

        i = 0;
        while(tolle_leute[i])
                free(tolle_leute[i++]);
        free(tolle_leute);

        return EXIT_SUCCESS;
}
==6818== Memcheck, a memory error detector
==6818== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==6818== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==6818== Command: ./cdb
==6818==
==6818==
==6818== HEAP SUMMARY:
==6818==     in use at exit: 0 bytes in 0 blocks
==6818==   total heap usage: 6 allocs, 6 frees, 44 bytes allocated
==6818==
==6818== All heap blocks were freed -- no leaks are possible
==6818==
==6818== For counts of detected and suppressed errors, rerun with: -v
==6818== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 13 from 8)
 
Zuletzt bearbeitet: (Ich brauche Urlaub.)
Und jetzt wollen wir unseren Streit bei einer großen Schale Erbeereis vergessen!
 
Zurück
Oben