kanotix.com

Entwicklung - Max. statische Array-Größe bei C++?

Dannyboy - 01.08.2007, 01:20 Uhr
Titel: Max. statische Array-Größe bei C++?
Hi @ all,
ich hoffe meine Verwirrung im Kopf liegt an der Uhrzeit. Mit den Augen rollen
Für einen Leveleditor lege ich eine 2D-Map an. in diese Map müssen 15.000.000 Einträge (char) hineinpassen, also Länge * Breite * Feldgröße = 3.000 * 1.000 * 5 = 15.000.000 = 15 MB Speicher. Jedes Mal krieg' ich nun 'nen Segmentation Fault / Core Dump. Um den Fehler einzugrenzen, hab' ich das Ding unter mehreren Linux-Derivaten laufen lassen ---> gleicher Fehler. Es scheitert bereits beim Anlegen des 15 MB großen Arrays, doch das sollte doch bei 512 MB RAM (is' wenig, ich weiss Winken ) kein Problem sein. Mit den Augen rollen Compilieren einfach mit "g++ test.cpp -o test".

Hier ist der Code, der bereits das Segm. Fault erzeugt.

Code:
#include <iostream>
using namespace std;

const int MAX_LEVELWIDTH  = 3000;
const int MAX_LEVELHEIGHT = 1000;

struct Sprite { char b0, b1, b2, b3, b4; };

int main (void) {
    Sprite map [MAX_LEVELWIDTH][MAX_LEVELHEIGHT]; // <--- FEHLER!!!
    cout<<"hello world"<<endl;
    return 0;
}


Lösungsvorschläge?
Greetz
DANNYBOY
doc2 - 01.08.2007, 17:25 Uhr
Titel:
Ein int hat aber 2 bzw. 4Byte reservierten Platz. Dann sind das schon 30MB oder gar 60MB. Bin auch nicht so der c++ Experte aber in deiner Struktur sind 5 Elemente (uninitialisiert?) du übergibst aber nur 2.

Schau mal strace wo es den Speicher sprengt.
Dannyboy - 02.08.2007, 00:00 Uhr
Titel:
Es wir KEIN int übergeben, sondern 5 chars = 5 Bytes. Es sind 15 MB Speicher (vgl. Rechnung im ersten Post).

Welche zwei Werte? Es werden keine Werte übergeben, sondern ein Array mit 2 Dimensionen wird auf die 5 Byte große Struktur angelegt.

Wie dem auch sei, es scheint statisch nicht zu gehen, weil die Array-Größe scheinbar begrenzt ist, ergo werd' ich den Speicher eben dynamisch anlegen soll mir Recht sein ...


Greetz
DANNYBOY
danone - 02.08.2007, 06:59 Uhr
Titel:
Liegt wohl daran, dass du die 3000*1000*5 Bytes auf dem _Stack_ erzeugen willst und dessen maximale Größe (8MB?) überschreitest (Stack Overflow). Leg den Kram doch einfach auf dem Heap an, dann kannste deine ganzen 512MB RAM (plus Swap) vollmachen Winken Dazu kannst du der Einfachheit halber auch einen STL vector nehmen:
Code:
#include <iostream>
#include <vector>

using namespace std;

const int MAX_LEVELWIDTH  = 3000;
const int MAX_LEVELHEIGHT = 1000;

struct Sprite { char b0, b1, b2, b3, b4; };

int main (void)
{
   vector< vector<Sprite> > map(MAX_LEVELWIDTH,MAX_LEVELHEIGHT);
   cout<<"hello world"<<endl;
   return 0;
}

Dannyboy - 02.08.2007, 12:25 Uhr
Titel:
Zitat:
Leg den Kram doch einfach auf dem Heap an, dann kannste deine ganzen 512MB RAM (plus Swap) vollmachen Winken

In der Überschrift steht statisch. Winken
Wie legt man denn ein Array mit 2 Dimensionen auf dem Heap an?
Geschockt

Hier mal 'n Test mit int:
Code:
 int **s = new int[5][6];

... erzeugt leider ein:
Zitat:
error: cannot convert ‘int (*)[5]’ to ‘int**’ in initialization


Greetz
DANNY
danone - 03.08.2007, 07:05 Uhr
Titel:
Oh, ja, statisch... Winken
2D-Array auf dem Heap anlegen:
Code:
int* array[MAX_LEVELWIDTH]
for(int i=0; i<MAX_LEVELWIDTH; ++i)
   array[i] = new int[MAX_LEVELHEIGHT];
// ...
for(int i=0; i<MAX_LEVELWIDTH; ++i)
   delete[] array[i];

Da ich das selber aber auch immer zu kompliziert finde (musste es nochmal nachschauen Winken ) mache ich i.d.R. ein 1D-Array und eine Methode zur Indexberechnung, in etwa so:
Code:
class Array2D
{
   public:
      int& elem(int x, int y){ return array[index(x,y)]; }
      int index(int x, int y) const{ return y*MAX_LEVELWIDTH+x; }
      int array[MAX_LEVELWIDTH*MAX_LEVELHEIGHT];
};


dann ein Objekt dieser Klasse per new erzeugen (und später per delete löschen).
Dannyboy - 03.08.2007, 17:49 Uhr
Titel:
Hi danone,
vielen Dank für Dein Posting, nach dem ich mich nun gerichtet habe. Hab's nun voll funktionsfähig mit dynamischer Größe auf dem Heap in 2 Dimensionen und doppelter Verpointerung. Das Ding rennt: Smilie
Code:
#include <iostream>
using namespace std;

int main(void) {

unsigned int L,H;
int **array;

cout<<"Insert array-length: "; cin>>L;
cout<<"Insert array-height:  "; cin>>H;

cout<<"Trying to allocate approx. "<<L*H*sizeof(int)/1000000<<" MB of memory ... ";

array = new (nothrow) int *[L];

if (array == NULL) {
   cout<<endl<<"Could not allocate memory"<<endl;
   return 1;
}

for (int i=0; i<L; i++){
   array[i] = new (nothrow) int[H];   
   if (array[i] == NULL) {
       cout<<endl<<"Could not allocate memory"<<endl;
      cout<<"Cleaning up ... ";
      for (int x=0; x<i; x++)
         delete [] array[x];
      delete [] array;
      cout<<" done."<<endl;
       return 1;
   }
}

cout <<"done"<<endl;
      
cout<<"Cleaning up ... ";
for (int i=0; i<L; i++){
   delete [] array[i];
}
delete [] array;

cout<<"done."<<endl;

return 0;

}


Greetz
DANNYBOY
danone - 03.08.2007, 22:42 Uhr
Titel:
wenn du's jetzt doch dynamisch benutzt, sollte man sich die Frage stellen, ob der ganze Aufwand lohnt, wenn man doch ein triviales std::vector< std::vector<int> > benutzen könnte. Vorteil: Kein Kümmern um Speicherallokation etc., übersichtlicherer Code. Nachteil: evtl. etwas mehr Overhead, allerdings glaube ich, dass die STL-Sachen schon sehr optimiert sind.

Gruß
danone
Alle Zeiten sind GMT + 1 Stunde
PNphpBB2 © 2003-2007