Allokation von Speicherbereichen

Hallo liebe Experten,

wenn ich mit Visual C++ ein Programm erstelle und ein größeres Variablenfeld benötige, gibt es zwei Möglichkeiten:

  1. das Variablenfeld wird gleich komplett deklariert (Speicherbelegung inklusive):

    #define MAX_WIDTH (irgendwas)
    #define MAX_HEIGHT (auch irgendwas)
    UINT uBitmap[MAX_HEIGHT*MAX_WIDTH];
    … (irgendein Code, der uBitmap verwendet)

  2. Es wird nur ein Zeiger deklariert, und vor der ersten Verwendung mttels z. B. new die Speicherallokation durchgeführt und nach der letzten Verwendung wieder mit free oder delete freigegeben:

    UINT *uBitmap;

    uBitmap = new UINT[MAX_HEIGHT*MAX_WIDTH];
    … (irgendein Code…)
    delete uBitmap;

Wenn nun die Feldgröße nicht im Vorhinein bekannt wäre, sehe ich ein, daß es sinnvoll ist, erst im Bedarfsfall die benötigte Feldgröße zu berechnen und dann zu allokieren. Aber wenn es eh eine konstante Größe ist, sind die beiden Möglichkeiten gleichwertig?

Früher einmal habe ich unter DOS mit Borland C++ 3.0 programmiert und da wirkte es sich auf die Größe der EXE-Datei aus. Bei Visual C++ scheint es aber keine Auswirkung zu haben.

Sind dann also beide Möglichkeiten gleich oder gibt es da Unterschiede?

Grüße,

I.

Hallo I.,

Früher einmal habe ich unter DOS mit Borland C++ 3.0
programmiert und da wirkte es sich auf die Größe der EXE-Datei
aus. Bei Visual C++ scheint es aber keine Auswirkung zu haben.

Sind dann also beide Möglichkeiten gleich oder gibt es da
Unterschiede?

Unter DOS war vor allem das Laufzeitverhalten unterschiedlich, wenn zu wenig Speicher vorhanden war!

  1. Statisch:
    DOS murmelt was von „zu wenig Speicher“ und unterbindet den Programmstart.
  2. Dynamisch
    Du hast als Programmierer die Oberhand und kannst dem Benutzer angeben, dass ihm genau 325 Byte freier Speicher fehlen um das Programm zu benutzen. u.U. kann man auch eine weniger effektiven Algorithmus verwenden, welcher mit weniger Speicher auskommt …

Bei Windows kann das allerdings auch vorkommen, wenn die festplatte voll oder die Auslagerungsdatei zu klein ist.
Zu DOS-Zeiten musste man noch damit rechnen, dass nur 256 KiB RAM vorhanden sind, bei Windows sind es mindestens 1’000 mal mehr. Ein 64KiB statischer Buffer konnte also bei DOS schon ein KO-Kriterium sein.

Ein weiteres Problem lag teilweise auch bei den Compilern. Eine Speicheradresse beim 8086 setzte sich aus Segment und Offset zusammen. Beide waren je 16 Bit lang. Manche der damaligen Compiler konnten gar keine statischen Variablen ansteuern, welche über 64KiB belegten auch wenn sie Huge-Pointer kannten.

Die Grösse der EXE hängt auch noch etwas von der Intelligenz des Compilers ab. Das EXE-Format erlaubt die Angabe von Speicherbereichen, welche 1:1 von der Platte geladen werden. Diese Form ist zwingend für statische Variablen, welche mit Werten initialisiert sind. Bei der anderen Form wird nur der Speicherplatz als Grösse angegeben und der Programmloader füllt dann diesen Bereich mit 0x00. Der Compiler, bzw. eigentlich der Linker, wird etwas einfacher, wenn man alles in der ersten Form ablegt.

MfG Peter(TOO)

Hallo,

wenn ich mit Visual C++ ein Programm erstelle und ein größeres
Variablenfeld benötige, gibt es zwei Möglichkeiten:

UINT uBitmap[MAX_HEIGHT*MAX_WIDTH];

Dieser „Block“ wird aus dem Stack genommen …

uBitmap = new UINT[MAX_HEIGHT*MAX_WIDTH];

… und dieser aus dem Heap. Ich würde Variante zwo bevorzugen. Für so „große“ Speichermengen ist der Stack eher nicht geeignet. Du kannst da u.U. Platzprobleme bekommen bzw. musst den Compiler anweisen, da für mehr Platz zu sorgen.

Gruß

Fritze

Hallo Fritze,

wenn ich mit Visual C++ ein Programm erstelle und ein größeres
Variablenfeld benötige, gibt es zwei Möglichkeiten:

UINT uBitmap[MAX_HEIGHT*MAX_WIDTH];

Dieser „Block“ wird aus dem Stack genommen …

Nur wenn diese Zeile innerhalb einer Prozedur steht!
Steht sie ausserhalb ist die Variable global, static und nicht auf dem Stack abgelegt, sondern liegt im DATA-Segment.

MfG Peter(TOO)

Hallo Peter(TOO) und Fritze,

danke Euch beiden.

Es scheint also (unter Windows und auf neueren Computern) ziemlich egal zu sein, ob Speicherbereiche für Variablen statisch deklariert werden oder dynamisch, zumindest solange es nur um einige 100 kByte geht.

Die Probleme mit früheren Compilern und DOS kenne ich noch, ich bin da bei meinem 8-MB-Notebook oft auf Extended Memory mit dem Treiber EMM386 ausgewichen, was ziemlich umständlich war.

Grüße,

I.

Wenn nun die Feldgröße nicht im Vorhinein bekannt wäre, sehe
ich ein, daß es sinnvoll ist, erst im Bedarfsfall die
benötigte Feldgröße zu berechnen und dann zu allokieren.

Mir ist nicht ganz klar, ob dir klar ist, dass in der Variante

uBitmap = new UINT[MAX_HEIGHT*MAX_WIDTH];

MAX_HEIGHT und MAX_WIDTH normale unsigned-Variablen sein können. Das folgende Beispiel funktioniert natürlich auch:

// Erzeugt mit MSVC 2005 V.8
#include „stdafx.h“

int h=2;
int w=3;
int* garr = new int[h*w];

int _tmain(int argc, _TCHAR* argv[]) {

int hh = argc+1;
int ww = argc+3;
int* arr = new int[hh*ww];

for(int i=0; i [] arr’ OK.

und da wirkte es sich auf die Größe der EXE-Datei
aus. Bei Visual C++ scheint es aber keine Auswirkung zu haben.

In dem Fall, in dem die Größe des allokierten Speichers erst zur Laufzeit bekannt ist, kann es auch keine Auswirkung haben.

Sind dann also beide Möglichkeiten gleich oder gibt es da
Unterschiede?

Die Möglichkeiten sind nicht gleich, wie die Antworten von Fritze und Peter auf deine Frage zeigen.

Grüße,

I.

Wenn du deine uBitmap in einer Micro$oft-MFC- oder -WinAPI Methode benutzen möchtest, ist OK, new/delete zu benutzen.
Ich bevorzuge, new/delete zu vermeiden und statt dessen Container-Klassen der STL zu benutzen. Diese geben den allokierten Speicherplatz ‚automatisch‘ frei wenn die damit definierte Größe den Geltungsbereich verlässt. Das gibt mehr Sicherheit. z.B.:

// Wie oben, jedoch mit STL stat new/delete

#include „stdafx.h“
#include

typedef std::valarray MyValArrType;

void doIt(const unsigned& _u){
const unsigned dim((_u+1)*(_u+3));
MyValArrType va(unsigned(0),dim);
for(unsigned i=0; i

Hi,

so nebenbei:

UINT *uBitmap;

uBitmap = new UINT[MAX_HEIGHT*MAX_WIDTH];
… (irgendein Code…)
delete uBitmap;

führt in der Regel zu einem Absturz, denn es wird mit einem normalen delete freigeben, was mit einem delete [] haette freigegeben werden müssen.

Gruss
norsemanna