Array-Deklaration
Deklariert ein Objekt vom Array-Typ.
Inhalt |
[bearbeiten] Syntax
Eine Array-Deklaration ist jede einfache Deklaration, deren Deklarator die Form hat
noptr-declarator [expr (optional)] attr (optional) |
|||||||||
| noptr-declarator | - | ein beliebiger gültiger Deklarator, aber wenn er mit *, & oder && beginnt, muss er von Klammern umschlossen sein (andernfalls wird der gesamte Deklarator als Pointer-Deklarator oder Referenz-Deklarator behandelt). |
| expr | - | ein ganzzahliger konstanter Ausdruck(bis C++14)ein konvertierter konstanter Ausdruck vom Typ std::size_t(seit C++14), der zu einem Wert größer als Null ausgewertet wird |
| attr | - | (seit C++11) Liste von Attributen |
Eine Deklaration der Form T a[N]; deklariert a als Array- Objekt, das aus N zusammenhängend alloziierten Objekten vom Typ T besteht. Die Elemente eines Arrays sind nummeriert von 0 bis N - 1 und können mit dem Indexoperator [] angesprochen werden, z. B. a[0] bis a[N - 1].
Arrays können aus jedem fundamentalen Typ (außer void), Pointern, Pointern auf Member, Klassen, Enumerationen oder aus anderen Arrays bekannter Größe (in diesem Fall wird das Array als mehrdimensional bezeichnet) konstruiert werden. Mit anderen Worten, nur Objekttypen außer Array-Typen unbekannter Größe können Elementtypen von Array-Typen sein. Array-Typen mit unvollständigem Elementtyp sind ebenfalls unvollständige Typen.
|
Der möglicherweise eingeschränkte(seit C++20) |
(seit C++11) |
Es gibt keine Arrays von Referenzen oder Arrays von Funktionen.
Die Anwendung von cv-Qualifizierern auf einen Array-Typ (über typedef oder Template-Typmanipulation) wendet die Qualifizierer auf den Elementtyp an, aber jeder Array-Typ, dessen Elemente cv-qualifiziert sind, wird als gleichermaßen cv-qualifiziert betrachtet.
// 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 = {};
Bei Verwendung mit new[]-Ausdruck kann 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
[bearbeiten] Zuweisung
Objekte 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 erscheinen.
int a[3] = {1, 2, 3}, b[3] = {4, 5, 6}; int (*p)[3] = &a; // okay: address of a can be taken a = b; // error: a is an array struct { int c[3]; } s1, s2 = {3, 4, 5}; s1 = s2; // okay: implicitly-defined copy assignment operator // can assign data members of array type
[bearbeiten] Array-zu-Pointer-Zerfall
Es gibt eine implizite Konvertierung von lvalues und rvalues vom Array-Typ zu rvalues vom Pointer-Typ: Sie konstruiert einen Pointer auf das erste Element eines Arrays. Diese Konvertierung wird verwendet, wenn Arrays in einem Kontext erscheinen, in dem Arrays nicht erwartet werden, aber Pointer schon.
#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' // prints size of array << sizeof p << '\n'; // prints size of a pointer // where arrays are acceptable, but pointers aren't, only arrays may be used g(a); // okay: function takes an array by reference // g(p); // error for (int n : a) // okay: arrays can be used in range-for loops std::cout << n << ' '; // prints elements of the array // for (int n : p) // error // std::cout << n << ' '; std::iota(std::begin(a), std::end(a), 7); // okay: begin and end take arrays // std::iota(std::begin(p), std::end(p), 7); // error // where pointers are acceptable, but arrays aren't, both may be used: f(a); // okay: function takes a pointer f(p); // okay: function takes a pointer std::cout << *a << '\n' // prints the first element << *p << '\n' // same << *(a + 1) << ' ' << a[1] << '\n' // prints the second element << *(p + 1) << ' ' << p[1] << '\n'; // same }
[bearbeiten] Mehrdimensionale Arrays
Wenn der Elementtyp eines Arrays ein anderes Array ist, wird das Array als mehrdimensional bezeichnet.
// array of 2 arrays of 3 int each int a[2][3] = {{1, 2, 3}, // can be viewed as a 2 × 3 matrix {4, 5, 6}}; // with row-major layout
Beachten Sie, dass bei Anwendung des Array-zu-Pointer-Zerfalls ein mehrdimensionales Array in einen Pointer auf sein erstes Element konvertiert wird (z. B. ein Pointer auf seine erste Zeile oder seine erste Ebene): Der Array-zu-Pointer-Zerfall wird nur einmal angewendet.
int a[2]; // array of 2 int int* p1 = a; // a decays to a pointer to the first element of a int b[2][3]; // array of 2 arrays of 3 int // int** p2 = b; // error: b does not decay to int** int (*p2)[3] = b; // b decays to a pointer to the first 3-element row of b int c[2][3][4]; // array of 2 arrays of 3 arrays of 4 int // int*** p3 = c; // error: c does not decay to int*** int (*p3)[3][4] = c; // c decays to a pointer to the first 3 × 4-element plane of c
[bearbeiten] Arrays unbekannter Größe
Wenn 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 er in einer Deklaration mit einem Aggregatinitialisierer verwendet wird.
extern int x[]; // the type of x is "array of unknown bound of int" int a[] = {1, 2, 3}; // the type of a is "array of 3 int"
Da Array-Elemente keine Arrays unbekannter Größe sein können, können mehrdimensionale Arrays in keiner Dimension außer der ersten eine unbekannte Größe haben.
extern int a[][2]; // okay: array of unknown bound of arrays of 2 int extern int b[2][]; // error: array has incomplete element type
Wenn eine vorherige Deklaration der Entität im selben Gültigkeitsbereich vorhanden ist, in der die Größe angegeben wurde, wird eine weggelassene Array-Größe als gleich der in der früheren Deklaration angenommen, und ebenso für die Definition eines statischen Datenmembers einer Klasse.
extern int x[10]; struct S { static int y[10]; }; int x[]; // OK: bound is 10 int S::y[]; // OK: bound is 10 void f() { extern int x[]; int i = sizeof(x); // error: incomplete object type }
Referenzen und Pointer auf Arrays unbekannter Größe können gebildet werden, aber nicht(bis C++20)und können(seit C++20) von Arrays und Pointern auf Arrays bekannter Größe initialisiert oder zugewiesen werden. Beachten Sie, dass im C-Programmiersprachen-Standard Pointer auf Arrays unbekannter Größe mit Pointern auf Arrays bekannter Größe kompatibel sind und somit in beide Richtungen konvertierbar und zuweisbar sind.
extern int a1[]; int (&r1)[] = a1; // okay int (*p1)[] = &a1; // okay int (*q)[2] = &a1; // error (but okay in C) int a2[] = {1, 2, 3}; int (&r2)[] = a2; // okay (since C++20) int (*p2)[] = &a2; // okay (since C++20)
Pointer auf Arrays unbekannter Größe können nicht an Pointer-Arithmetik teilnehmen und können nicht links vom Indexoperator verwendet werden, können aber dereferenziert werden.
[bearbeiten] Array-Rvalues
Obwohl Arrays nicht per Wert von Funktionen zurückgegeben werden können und keine Ziele der meisten Cast-Ausdrücke sind, können Array- prvalues durch Verwendung eines Typalias gebildet werden, um ein Array-Temporäres mit einem funktionalen Cast mit geschweiften Klammern zu konstruieren.
|
Wie Klassen-prvalues konvertieren Array-prvalues durch temporäre Materialisierung zu xvalues, wenn sie ausgewertet werden. |
(seit C++17) |
Array- xvalues können direkt durch Zugriff auf ein Array-Mitglied eines Klassen-rvalues oder durch Verwendung von std::move oder eines anderen Casts oder Funktionsaufrufs, der eine rvalue-Referenz zurückgibt, gebildet werden.
#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'; // size of the array f(X().i); // okay: binds to xvalue // f(x.i); // error: cannot bind to lvalue int a[2][3]; f(std::move(a)); // okay: binds to xvalue using arr_t = int[2][3]; f(arr_t{}); // okay: binds to prvalue f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // okay: binds to prvalue }
Ausgabe
24 24 24 24 24
[bearbeiten] Defect Reports
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 393 | C++98 | ein Pointer oder eine Referenz auf ein Array unbekannter Größe konnte kein Funktionsparameter sein |
erlaubt |
| CWG 619 | C++98 | wenn weggelassen, konnte die Größe eines Arrays nicht aus einer vorherigen Deklaration abgeleitet werden |
Ableitung erlaubt |
| CWG 2099 | C++98 | die Größe eines statischen Datenmembers eines Arrays konnte nicht weggelassen werden, auch wenn ein Initialisierer bereitgestellt wurde |
Weglassen erlaubt |
| CWG 2397 | C++11 | auto konnte nicht als Elementtyp verwendet werden | erlaubt |
[bearbeiten] Siehe auch
| C-Dokumentation für Array-Deklaration
|