Forum: PC-Programmierung 3-D Zahlenfelder und Probleme


von Dave_ (Gast)


Lesenswert?

Hallo Zusammen

Folgendes in Visual Studio C++:

unsigned int Platine_1[250][250][5];

Warum mäckert der Compiler und linker nicht, aber wenn das programm
läuft es Probleme mit speicher gibt?


David

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Wenn das eine automatische Variable ist, reicht der Stack (Defaultgröße
1 MByte) nicht aus.

Warum aber sollte das den Compiler interessieren?

von Dave_ (Gast)


Lesenswert?

Hallo

Gibt es evntl. eine abhilfe? Vielleicht mit Speicherreservierung.

David

von mplusplus (Gast)


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

von Karl H. (kbuchegg)


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.

von mplusplus (Gast)


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

von Karl H. (kbuchegg)


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 ..."

von Karl H. (kbuchegg)


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.

von Rufus Τ. F. (rufus) Benutzerseite


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.

von mplusplus (Gast)


Lesenswert?

Vielen Dank für diese ausführliche Beschreibung. Die 'implizit int'
Regel war mir unbekannt. Man lernt nie aus...

Grüße

mplusplus

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.