multi Arrays mit malloc()

AckiB

Mitglied
Hallo,
ich möchte ein 2d Array über malloc() erstellen.
Ein einfaches Array ist kein Problem:
Code:
  mDat* Map;
  Map = (mDat*)malloc(sizeof(mDat) * (mWidth * mHeight + 2));
  for(int x = 0; x < mWidth; x++){
    for(int y = 0; y < mHeight; y++){
      Map[x + y * mHeight].walkable = true;
    }
  }

Wenn ich das Gleiche aber mit einem 2d Array versuche, stürtzt der komplette Rechner ab
Code:
  mDat** Map;
  Map = (mDat**)malloc(sizeof(mDat) * (mWidth * mHeight + 2));
  for(int x = 0; x < mWidth; x++){
    for(int y = 0; y < mHeight; y++){
      Map[x][y].walkable = true;
    }
  }

WO ist mein Denkfehler !!

Danke, Acki
 
Der komplette Rechner stürzt ab? Das sollte eigentlich bei einem vernünftigen Betriebssystem und einem Prozessor im Protected Mode nicht passieren. (außer du schreibst gerade an einem Kernel-Modul oder sowas ;))

Dein Denkfehler ist, das ein 2-dim. Array auch hintereinander im Speicher liegt und lediglich die Werte des Arrays enthält. Im Grunde sind 2-dim. Arrays nichts anderes als Arrays von Arrays. Und Arrays sind nix weiter als Pointer zu dem Beginn des Arrays. So müssen also im ersten Array Pointer zum 2-ten Array stehen. Die mußt du erstmal initialisieren, etwa so:
Code:
mDat** Map;
  Map = (mDat**)malloc(sizeof(mDat*) * (mWidth+1));
  for (int i = 0; i < mHeight; ++i) {
    Map[i] = (mDat*)malloc(sizeof(mDat) * (mHeight+1));
  }
Dann klappt auch die Pointerarithmetik, mit dessen Hilfe der Wert an der Stelle i,j ermittelt wird:

Code:
Map[i][j] == *(*(Map+i)+j)
 
Danke

Ja, der Rechner stürtzt ab, obwohl ich nichtsanderes mache als das Array zu erstellen (geht nocht) und versuche Daten ins Array zu schreiben (dann verabschiedet er sich)

Ich hab's jetzt erstmal ein eindimensionales Array benutzt und errechne den Index...

Aber Deinem Tip werde ich auf jeden Fall nachgehen ! :)

CU, Acki
 
Gut. :)

Mir ist allerdings grad aufgefallen, das es in der Schleife natürlich nicht "i < mHeight" sondern "i < mWidth" heißen muß.

Außerdem, um das vielleicht nochmal etwas klarer zu machen:

Wenn du ein mehrdimensionales Array so definierst:
Code:
int a[3][2];
, dann liegt dieses Array normalerweise tatsächlich als großer Block im Speicher und der Zugriff auf
Code:
a[2][1];
geschieht so, das die Adresse a mit 2 multipliziert und dann die 1 addiert wird; dann wird dereferenziert und man erhält den Wert an der Stelle (2, 1).

Definiert man ein mehrdimensionales Array hingegen so:
Code:
 int **a;
, dann wird wie ich oben schon geschrieben habe mit den Pointern einzeln gerechnet. Der Zugriff auf a[2][1] geschieht also indem (a+2) dereferenziert wird, dazu wird die 1 addiert und dann nochmal dereferenziert.

Der Vorteil ist, das man sich eine Multiplikation spart indem man sie durch eine weitere Dereferenzierung ersetzt hat. (das kann bei größeren Berechnungen mit einem großen Array schon wichtig/schneller sein)

Z.B.
Code:
int a[9][3];
int **aa = (int**)malloc( sizeof(int *) * 9);
for (int i = 0; i < 9; ++i) { aa[i] = a[i]; }
Jetzt kann man je nach Belieben entweder über aa oder a auf die Elemente des Arrays zugreifen.
 
Um das mal klarzustellen:
Die ganze Diskussion dreht sich in eine nicht ganz standardkonforme Richtung :-)

man muss da sehr genau sein:

Ein Objekt ist ein benannter Platz im Speicher. Das kann ein Array sein, eine Variable, ein Zeiger etc.

Ein Array ist ein kontinuierliches Objekt (contiguous object, laut standard...); es liegen die einzelnen Elemente im speicher jedenfalls hintereinander, dimensionen egal.

man muss lediglich bei den Typen aufpassen und da nichts durcheinanderbringen:

int a[3] ist ein "Array von int mit 3 elementen": sizeof(a) = 3 * sizeof(int)

int a[3][5] ist ein "Array von 3 Arrays von 5 int": also sizeof(a) = 5* 3* sizeof(int)
a[i] ist hier ein "Array von 5 int": sizeof(a[i]) = 5* sizeof(int)

in int a[x][y] gilt:
a liefert einen Zeiger vom Typ "Zeiger auf ein Array von 3 Arrays von 5 int"
*a liefert einen "Zeiger auf ein Array von 5 int" (bin mir da jetzt selbst nicht sicher *nachdenk*, was ich weiß ist, dass es dieselbe Adresse ist, wie a, aber in den Casts bei den Berechnungen der Pointerarithmetik anders gehandhabt wird)
&a[i] liefert einen Zeiger vom Typ "Zeiger auf ein Array von 5 int"
&a[i][j] liefert einen Zeiger auf int

Um ein Element anzusprechen in a[x][y] kann man für a[i][j] auch *(*(a+i)+j) verwenden.
i wird dann auf einen "zeiger auf array von 5 ints" gecastet und entsprechend multipliziert.
j wird auf einen Zeiger auf int gecastet und entsprechend multipliziert.
(genauso realisiert auch ein Compiler den Zugriff auf mehrdimensionale Arrays)
Man kann allerdings genauso *((int*)a + i*y + j) verwenden.

Kein Compiler teilt mehrdimensionale Arrays im Speicher auf, da es so nicht im Standard steht.

Ein mehrdimensionales Array ist also NICHT gleich einem zeiger auf einen zeiger...
man kann es dennoch so realisieren, es ist allerdings dann nicht möglich einfache Zeigerarithmetik zu verwenden.

eine weitere Möglichkeit zeigt folgender code (tested using OpenWatcom 1.3):

Code:
#include "stdio.h"
#include "stdlib.h"
#include "conio.h"

int main (void)
{
  int* Map;
  int mWidth=10;
  int mHeight=10;
  int x,y;
  Map = (int*)malloc(sizeof(int) * (mWidth * mHeight + 2));
  for(x = 0; x < mWidth; x++){
    for(y = 0; y < mHeight; y++){
      *(Map+x+y)= x+y;
      printf("%d\t",Map[x+y]);
    }
    printf("\n");
  }
  getch();
return 0;
}

hier wird ein 2-dimensionales Array als eindimensionales im speicher abgelegt, was die arithmetik vereinfacht.

greez
Johannes
 
Zurück