Array declaration
Deklariert ein Objekt vom Array-Typ.
InhaltSyntaxEine Array-Deklaration ist jede einfache Deklaration, deren Deklarator die Form hat
Eine Deklaration der Form Arrays können aus jedem fundamentalen Typ (außer
Es gibt keine Arrays von Referenzen oder Arrays von Funktionen. Das Anwenden von cv-Qualifizierern auf einen Array-Typ (durch typedef oder Template-Typ-Manipulation) wendet die Qualifizierer auf den Elementtyp an, aber jeder Array-Typ, dessen Elemente vom cv-qualifizierten Typ sind, gilt als dieselbe cv-Qualifikation zu haben. // a and b have the same const-qualified type "array of 5 const char"
typedef const char CC;
CC a[5] = {};
typedef char CA[5];
const CA b = {};
Wenn mit new[]-Ausdruck verwendet, darf die Größe eines Arrays Null sein; ein solches Array hat keine Elemente: int* p = new int[0]; // accessing p[0] or *p is undefined
delete[] p; // cleanup still required
In der Praxis wird der Einfachheit halber ein Zeiger auf ein Array-Element manchmal als Zeiger auf das Array bezeichnet: int arr[5] {};
int *p = arr;
Man sagt, dass ZuweisungObjekte vom Array-Typ können nicht als Ganzes modifiziert werden: Obwohl sie Lvalues sind (z.B. kann die Adresse eines Arrays genommen werden), können sie nicht auf der linken Seite eines Zuweisungsoperators stehen: int a[3] = {1, 2, 3}, b[3] = {4, 5, 6}; int (*p)[3] = &a; // okay: Adresse von a kann genommen werden a = b; // Fehler: a ist ein Array struct { int c[3]; } s1, s2 = {3, 4, 5}; s1 = s2; // okay: implizit definierter Kopierzuweisungsoperator // kann Datenelemente vom Array-Typ zuweisen Array-zu-Pointer-ZerfallEs gibt eine implizite Konvertierung von Lvalues und Rvalues des Array-Typs zu Rvalues des Pointer-Typs: Sie konstruiert einen Pointer zum ersten Element eines Arrays. Diese Konvertierung wird verwendet, wann immer Arrays in Kontexten erscheinen, in denen Arrays nicht erwartet werden, aber Pointer erwartet werden:
Diesen Code ausführen
#include <iostream> #include <iterator> #include <numeric> void g(int (&a)[3]) { std::cout << a[0] << '\n'; } void f(int* p) { std::cout << *p << '\n'; } int main() { int a[3] = {1, 2, 3}; int* p = a; std::cout << sizeof a << '\n' // gibt die Größe des Arrays aus << sizeof p << '\n'; // gibt die Größe eines Zeigers aus // wo Arrays akzeptiert werden, aber Zeiger nicht, dürfen nur Arrays verwendet werden g(a); // okay: Funktion nimmt ein Array per Referenz // g(p); // Fehler for (int n : a) // okay: Arrays können in Range-for-Schleifen verwendet werden std::cout << n << ' '; // gibt Elemente des Arrays aus // for (int n : p) // Fehler // std::cout << n << ' '; std::iota(std::begin(a), std::end(a), 7); // okay: begin und end nehmen Arrays // std::iota(std::begin(p), std::end(p), 7); // Fehler // wo Zeiger akzeptiert werden, aber Arrays nicht, können beide verwendet werden: f(a); // okay: Funktion nimmt einen Zeiger f(p); // okay: Funktion nimmt einen Zeiger std::cout << *a << '\n' // gibt das erste Element aus << *p << '\n' // dasselbe << *(a + 1) << ' ' << a[1] << '\n' // gibt das zweite Element aus << *(p + 1) << ' ' << p[1] << '\n'; // dasselbe } Mehrdimensionale ArraysWenn der Elementtyp eines Arrays ein anderes Array ist, wird gesagt, dass das Array mehrdimensional ist: // Array von 2 Arrays mit jeweils 3 int int a[2][3] = {{1, 2, 3}, // kann als 2×3-Matrix betrachtet werden {4, 5, 6}}; // mit row-major layout Beachten Sie, dass bei Array-zu-Pointer-Zerfall ein mehrdimensionales Array in einen Zeiger auf sein erstes Element umgewandelt wird (z.B. ein Zeiger auf seine erste Zeile oder seine erste Ebene): Array-zu-Pointer-Zerfall wird nur einmal angewendet. int a[2]; // Array von 2 int int* p1 = a; // a zerfällt zu einem Zeiger auf das erste Element von a int b[2][3]; // Array von 2 Arrays von 3 int // int** p2 = b; // Fehler: b zerfällt nicht zu int** int (*p2)[3] = b; // b zerfällt zu einem Zeiger auf die erste 3-Element-Zeile von b int c[2][3][4]; // Array von 2 Arrays von 3 Arrays von 4 int // int*** p3 = c; // Fehler: c zerfällt nicht zu int*** int (*p3)[3][4] = c; // c zerfällt zu einem Zeiger auf die erste 3 × 4-Element-Ebene von c Arrays unbekannter GrößeWenn expr in der Deklaration eines Arrays weggelassen wird, ist der deklarierte Typ "Array unbekannter Größe von T", was eine Art unvollständiger Typ ist, außer wenn es in einer Deklaration mit einem Aggregat-Initialisierer verwendet wird: extern int x[]; // der Typ von x ist "Array unbekannter Größe von int" int a[] = {1, 2, 3}; // der Typ von a ist "Array von 3 int" Da Array-Elemente keine Arrays unbekannter Größe sein können, können mehrdimensionale Arrays keine unbekannte Größe in einer anderen Dimension als der ersten haben: extern int a[][2]; // okay: Array mit unbekannter Größe von Arrays mit 2 int extern int b[2][]; // Fehler: Array hat unvollständigen Elementtyp Falls eine vorherige Deklaration der Entität im selben Gültigkeitsbereich existiert, in dem die Grenze angegeben wurde, wird eine ausgelassene Array-Grenze als dieselbe wie in dieser früheren Deklaration angenommen, und ähnlich für die Definition eines statischen Datenelements einer Klasse: extern int x[10]; struct S { static int y[10]; }; int x[]; // OK: Grenze ist 10 int S::y[]; // OK: Grenze ist 10 void f() { extern int x[]; int i = sizeof(x); // Fehler: unvollständiger Objekttyp } Referenzen und Zeiger auf Arrays unbekannter Größe können gebildet werden, können aber nicht (bis C++20) und können (seit C++20) von Arrays und Zeigern auf Arrays bekannter Größe initialisiert oder zugewiesen werden. Beachten Sie, dass in der Programmiersprache C Zeiger auf Arrays unbekannter Größe mit Zeigern auf Arrays bekannter Größe kompatibel sind und daher in beide Richtungen konvertierbar und zuweisbar sind. extern int a1[]; int (&r1)[] = a1; // in Ordnung int (*p1)[] = &a1; // in Ordnung int (*q)[2] = &a1; // Fehler (aber in C in Ordnung) int a2[] = {1, 2, 3}; int (&r2)[] = a2; // in Ordnung (seit C++20) int (*p2)[] = &a2; // in Ordnung (seit C++20) Zeiger auf Arrays unbekannter Größe können nicht an Zeigerarithmetik teilnehmen und können nicht auf der linken Seite des Subskriptoperators verwendet werden, können aber dereferenziert werden. Array-RvaluesObwohl Arrays nicht als Wert von Funktionen zurückgegeben werden können und nicht Ziel der meisten Cast-Ausdrücke sein können, können Array- prvalues gebildet werden, indem ein Typalias verwendet wird, um ein Array-Temporary mittels funktionaler Cast mit Initialisiererliste zu konstruieren.
Array xvalues können direkt durch Zugriff auf ein Array-Mitglied eines Klassen-rvalues gebildet werden oder durch Verwendung von std::move oder einer anderen Umwandlung oder Funktionsaufruf, der eine Rvalue-Referenz zurückgibt.
Diesen Code ausführen
#include <iostream> #include <type_traits> #include <utility> void f(int (&&x)[2][3]) { std::cout << sizeof x << '\n'; } struct X { int i[2][3]; } x; template<typename T> using identity = T; int main() { std::cout << sizeof X().i << '\n'; // Größe des Arrays f(X().i); // okay: bindet an xvalue // f(x.i); // Fehler: kann nicht an lvalue binden int a[2][3]; f(std::move(a)); // okay: bindet an xvalue using arr_t = int[2][3]; f(arr_t{}); // okay: bindet an prvalue f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // okay: bindet an prvalue } Ausgabe: 24 24 24 24 24 FehlerberichteDie folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
Siehe auch
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||