3-D Zahlenfelder und Probleme

Gast #417651
Lesenswert?

Hi,

so etwa müsste das funktionieren (Ausschnitt):


unsigned int ***Platine_l;
int i, j;

// allocate memory
Platine_l = (unsigned int***)malloc(250*sizeof(unsigned int**));
for(i=0; i<250; i++) {
   Platine_l[i] = (unsigned int**)malloc(250*sizeof(unsigned int*));
   for(j=0; j<250; j++)
      Platine_l[i][j] = (unsigned int*)malloc(5*sizeof(unsigned int));
}

// do someting

// free memory
for(i=0; i<250; i++) {
   for(j=0; j<250; j++)
      free(Platine_l[i][j]);
   free(Platine_l[i]);
}
free(Platine_l);


Grüße

mplusplus
#417652
Lesenswert?

> (unsigned int***)malloc(250*sizeof(unsigned int**));

Wenn du das Ergebnis von malloc casten musst, programmierst du
nicht C sondern C++. In diesem Fall ist new die bessere Wahl
anstellevon malloc. Noch besser wäre es allerdings dann auch
wirklich C++ zu schreiben und das ganze mit std::vector
aufzubauen.

Programmierst du allerdings wirklich in C, dann lass den Cast
weg. Er ist unnötig und kann einen grauslichen Fehler verstecken.
Gast #417653
Lesenswert?

> Programmierst du allerdings wirklich in C, dann lass den Cast
> weg. Er ist unnötig und kann einen grauslichen Fehler verstecken.

Welcher Fehler kann denn da passieren? Ich habe damit noch nie ein
Problem gehabt (in C).

Grüße

mplusplus
#417654
Lesenswert?

folgendes Szenario:
Auf deinem System sei
  sizeof(int) != sizeof(void*)

und weiters vergisst du das korrekte Header-File für malloc
zu inkludieren.

Damit ist das Szenario aufgesetzt.

Wenn du jetzt machst

    int* pi = (int*)malloc( sizeof(int) );

dann passiert folgendes:
Der Compiler hat keinen Prototypen für malloc (da ja das
Header File nicht eingebunden wurde). Also muss der Compiler
davon ausgehen, dass die Funktion malloc() einen int zurückliefert.
Das muss er aufgrund der 'implizit int' Regel in C tun.
Nun war eine weitere Voraussetzung, dass sizeof(int) nicht gleich
sizeof(void*) sei. D.h. der Compiler nimmt vom returnierten Wert
(der ja eigentlich ein Pointer ist) eine falsche Bytezahl her.
Da du einen cast da drinnen hast, wird diese falsche Bytezahl
in einen Pointer konvertiert und zugewiesen. Im Endeffekt erhält
die Pointervariable nicht die Adresse die malloc zurückliefert,
weil diese zwischendurch mal auf einen int umgewandelt wurde.

Der Compiler wird dazu auch nichts weiter sagen, da ihn der
cast ruhigstellt. Immer dran denken: Ein cast ist die C-Schreibweise
für: "Lieber Compiler. Mir ist scheissegal ob du denkst dass die
Datentypen nicht passen. Ich bin der Programmierer und ich habe
das sagen und du tust gefälligst was ich dir sage, egal was die
C-Regeln sagen".
Und das tut der Compiler.

Lässt du allerdings den cast weg, dann gibst du dem Compiler die
Möglichkeit dich auf den Fehler aufmerksam zu machen. Den ein
int kann nicht an einen Pointer zugewiesen werden. Der Compiler
wird also meckern. Du überlegst wie das sein kann, denn immerhin
liefert malloc einen Pointer und du weist den an eine Pointer-
Variable zu. Wie kommt der Compiler also dazu, von einer int
Zuweisung an einen Pointer zu faseln. Und die Antwort ist:
malloc.h wurde nicht inkludiert und daher gelten Standardannahmen
die besagen, dass alles was nicht bekannt ist, in desem Fall der
Returntyp von malloc(), als int anzunehmen ist.

Und daher ist es in C besser, diesen cast nicht zu schreiben.
Generell ist es immer besser, einen cast der nicht gebraucht wird
auch nicht zu schreiben. Aus dem einfachen Grund weil ein cast
effektiv die Typ-Überprüfung des Compilers ausschaltet. "Lieber
Compiler. Mir ist ..."
#417655
Lesenswert?

> Im Endeffekt erhält
> die Pointervariable nicht die Adresse die malloc zurückliefert,
> weil diese zwischendurch mal auf einen int umgewandelt wurde.

Konkret könnte das zb so aussehen:

sizeof( void* ) == 8
sizeof( int ) == 4

malloc() legt als Returnwert 8 Bytes auf den Returnstack für
die Adresse. Der Aufrufer holt sich aber nur 4 davon.
Nicht nur, dass damit die zurückgegebene Adresse verstümmelt
wird, kommt auch der Returnstack komplett durcheinander.
Persönliche Seite #417656
Lesenswert?

Einfacher, wenn auch nicht eleganter, wäre die Vergrößerung des
verwendeten Stacks.

Das geht mit der VC-Linkeroption /STACK:nnnn (nnn ist die Größe in
Bytes).
In VC++ 6.0 gibt es dazu sogar ein GUI:
Project Settings->Linker->Output->Stack Allocations "Reserve"

Alternativ könnte die Variable auch als "static" oder als globale
Variable deklariert werden.

Eleganter ist allerdings keine dieser Vorgehensweisen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren