Ich finde auch, dass Arrays zu den wichtigen Grundlagen gehören. Allerdings sind die Regeln von C und C++ in diesem konkreten Fall sehr verwirrend, was ja überhaupt erst der Grund für die Existenz dieses Thread ist. Ich wollte einfach nur vermeiden, ihn zum jetzigen Zeitpunkt mit unnötigen Details vom Wesentlichen abzulenken. Aber hier kurz zum Verständnis was wirklich passiert:
int a[3]; deklariert ein Array aus 3 int.
int a[4][3]; deklariert ein Array aus 4 Arrays aus jeweils 3 int.
void f(int* a); deklariert eine Funktion mit einem Pointer auf einen int als Parameter; so weit so gut. Jetzt kommt's:
void f(int a[3]); deklariert ebenfalls eine Funktion mit einem Pointer auf einen int als Parameter und keine Funktion mit einem Array als Parameter. C und C++ haben speziell für diesen Fall eine Regel, die besagt, dass die Deklaration jedes Funktionsparameters, der als Arrays deklariert ist, in eine Deklaration eines entsprechenden Pointers umgewandelt wird (man spricht auch von "array to pointer decay"). Einfaches Beispiel zum selbst ausprobieren:
Code: Alles auswählen
void f(int* a)
{
}
void f(int a[3]) // fehler: funktion bereits definiert
{
}
Wenn diese Regel nun mit mehrdimensionalen Arrays und der impliziten Konvertierung von Arrays in Pointer auf das erste Element des Arrays zusammentrifft, wird das meiner Erfahrung nach selbst für fortgeschrittene Programmierer schnell mal völlig undurchschaubar.
Gehen wir erst mal ein paar Basics durch:
Code: Alles auswählen
int a[3]; // Array aus 3 int
int* b = a; /* == */ int* b = &a[0]; // Pointer auf erstes Element eines int[3]
int (*c)[3] = &a; // Pointer auf Array aus 3 int
int aa[4][3]; // Array aus 4 Arrays aus 3 int
int (*bb)[3] = aa; /* == */ int (*bb)[3] = &aa[0]; // Pointer auf erstes Element eines int[4][3]
int* cc = aa[1]; /* == */ int* cc = &aa[1][0]; // Pointer auf erstes Element des zweiten Elements eines int[4][3]
int (*dd)[4][3] = &aa; // Pointer auf Array aus 4 Arrays aus 3 int
Ok, gut. Das hier
ist also nicht das selbe wie
während das hier
das selbe ist wie
Referenzen funktionieren mehr oder weniger analog zu den Pointern.
Wenn du nun ein zweidimensionales int[4][3] Array an eine Funktion übergeben willst, hast du prinzipiell die folgenden Möglichkeiten:
Code: Alles auswählen
void f1(int a[4][3]); /* == */ void f(int (*a)[3]); // Pointer auf erstes Element deines Arrays
void f2(int (*a)[4][3]); // Pointer auf dein Array
void f3(int (&a)[4][3]); // Referenz auf dein Array
// Aufruf:
int a[4][3];
f1(a); /* == */ f1(&a[0]);
f2(&a);
f3(a);
Einfacher wird es schon durch ein typedef:
Code: Alles auswählen
typedef int blub[4][3];
void f1(blub a); // Pointer auf erstes Element deines Arrays
void f2(blub* a); // Pointer auf dein Array
void f3(blub& a); // Referenz auf dein Array
// Aufruf:
blub a;
f1(a); /* == */ f1(&a[0]);
f2(&a);
f3(a);
Aber richtig intuitiv wird es erst, wenn man das Array in ein struct verpackt:
Code: Alles auswählen
struct blub
{
int a[4][3];
};
void f1(blub a); // Kopie deines struct
void f2(blub* a); // Pointer auf dein struct
void f3(blub& a); // Referenz auf dein struct
// Aufruf:
blub a;
f1(a);
f2(&a);
f3(a);
std::array ist nichts anderes als so ein struct mit einem Array drin... ;)