Namespaces
Variants

Array declaration

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

Deklariert ein Objekt vom Array-Typ.

Inhaltsverzeichnis

Syntax

Eine Array-Deklaration ist jede einfache Deklaration, deren Deklarator die Form hat

noptr-declarator [ expr  (optional) ] attr  (optional)
noptr-declarator - jeder gültige declarator , aber wenn er mit * , & oder && beginnt, muss er in Klammern gesetzt werden (andernfalls wird der gesamte Deklarator als pointer declarator oder reference declarator behandelt).
expr - ein integral constant expression (bis C++14) ein converted constant expression vom Typ std::size_t (seit C++14) , der zu einem Wert größer als Null ausgewertet wird
attr - (seit C++11) Liste von attributes

Eine Deklaration der Form T a [ N ] ; deklariert a als ein Array- Objekt , das aus N zusammenhängend allozierten Objekten des Typs T besteht. Die Elemente eines Arrays werden von 0 bis N - 1 nummeriert und können mit dem Subskript-Operator [] zugegriffen werden, wie in a [ 0 ] bis a [ N - 1 ] .

Arrays können aus jedem fundamentalen Typ (außer void ), Pointern , Pointer zu Membern , Klassen , Enumerationen oder aus anderen Arrays mit bekannter Grenze konstruiert werden (in diesem Fall wird das Array als mehrdimensional bezeichnet). Mit anderen Worten, nur Objekttypen mit Ausnahme von Arraytypen unbekannter Grenze können Elementtypen von Arraytypen sein. Arraytypen mit unvollständigem Elementtyp sind ebenfalls unvollständige Typen.

Der möglicherweise constrained (since C++20) auto -Spezifizierer kann als Array-Elementtyp in der Deklaration eines Zeigers oder Referenz auf Array verwendet werden, welcher den Elementtyp vom Initialisierer oder dem Funktionsargument (since C++14) ableitet, z.B. auto ( * p ) [ 42 ] = & a ; ist gültig, falls a ein Lvalue vom Typ int [ 42 ] ist.

(since C++11)

Es gibt keine Arrays von Referenzen oder Arrays von Funktionen.

Das Anwenden von cv-qualifiers 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, wird als mit derselben cv-Qualifikation versehen betrachtet.

// a und b haben denselben const-qualifizierten Typ "Array von 5 const char"
typedef const char CC;
CC a[5] = {};
typedef char CA[5];
const CA b = {};

Bei Verwendung mit new[]-expression kann die Größe eines Arrays null sein; ein solches Array hat keine Elemente:

int* p = new int[0]; // Der Zugriff auf p[0] oder *p ist undefiniert
delete[] p; // Bereinigung ist dennoch erforderlich

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 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-Zerfall

Es 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:

#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 Arrays

Wenn 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öß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 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-Rvalues

Obwohl 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.

Wie Klassen-PRWerte konvertieren Array-PRWerte durch temporäre Materialisierung zu XWerten, wenn sie ausgewertet werden.

(since C++17)

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.

#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

Fehlerberichte

Die folgenden verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.

DR Angewendet auf Verhalten wie veröffentlicht Korrektes Verhalten
CWG 393 C++98 Ein Zeiger oder eine Referenz auf ein Array unbekannter
Größe konnte kein Funktionsparameter sein
erlaubt
CWG 619 C++98 Wenn ausgelassen, konnte die Größe eines Arrays nicht
von einer vorherigen Deklaration abgeleitet werden
Ableitung erlaubt
CWG 2099 C++98 Die Größe eines Array-Static-Datenmembers konnte
nicht ausgelassen werden, selbst wenn ein Initialisierer vorhanden war
Auslassung erlaubt
CWG 2397 C++11 auto konnte nicht als Elementtyp verwendet werden erlaubt

Siehe auch

C-Dokumentation für Array-Deklaration