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

Déclare un objet de type tableau.

Table des matières

Syntaxe

Une déclaration de tableau est toute déclaration simple dont le déclarateur a la forme

noptr-declarator [ expr  (optionnel) ] attr  (optionnel)
noptr-declarator - tout declarator valide, mais s'il commence par * , & , ou && , il doit être entouré de parenthèses (sinon l'ensemble du déclarateur est traité comme un pointeur déclarator ou référence déclarator ).
expr - une expression constante entière (jusqu'en C++14) une expression constante convertie de type std::size_t (depuis C++14) , qui s'évalue à une valeur supérieure à zéro
attr - (depuis C++11) liste d' attributs

Une déclaration de la forme T a [ N ] ; , déclare a comme un objet tableau constitué de N objets de type T alloués de manière contiguë. Les éléments d'un tableau sont numérotés 0 , …, N - 1 , et peuvent être accédés avec l' opérateur d'indice [] , comme dans a [ 0 ] , …, a [ N - 1 ] .

Les tableaux peuvent être construits à partir de tout type fondamental (sauf void ), pointeurs , pointeurs vers membres , classes , énumérations , ou à partir d'autres tableaux de taille connue (auquel cas le tableau est dit multidimensionnel). En d'autres termes, seuls les types objets à l'exception des types tableaux de taille inconnue peuvent être des types d'éléments de types tableaux. Les types tableaux de type d'élément incomplet sont également des types incomplets.

Le spécificateur éventuellement contraint (depuis C++20) auto peut être utilisé comme type d'élément de tableau dans la déclaration d'un pointeur ou d'une référence vers un tableau, ce qui déduit le type d'élément de l'initialiseur ou de l'argument de fonction (depuis C++14) , par exemple auto ( * p ) [ 42 ] = & a ; est valide si a est une lvalue de type int [ 42 ] .

(depuis C++11)

Il n'y a pas de tableaux de références ni de tableaux de fonctions.

L'application de cv-qualifiers à un type tableau (via typedef ou manipulation de type template) applique les qualificateurs au type élément, mais tout type tableau dont les éléments sont de type cv-qualifié est considéré comme ayant la même qualification cv.

// a et b ont le même type qualifié const "tableau de 5 const char"
typedef const char CC;
CC a[5] = {};
typedef char CA[5];
const CA b = {};

Lorsqu'il est utilisé avec une new[]-expression , la taille d'un tableau peut être zéro ; un tel tableau n'a aucun élément :

int* p = new int[0]; // l'accès à p[0] ou *p est indéfini
delete[] p; // le nettoyage reste nécessaire

Affectation

Les objets de type tableau ne peuvent pas être modifiés dans leur ensemble : bien qu'ils soient des lvalues (par exemple, l'adresse d'un tableau peut être prise), ils ne peuvent pas apparaître à gauche d'un opérateur d'assignation :

int a[3] = {1, 2, 3}, b[3] = {4, 5, 6};
int (*p)[3] = &a; // correct : l'adresse de a peut être prise
a = b;            // erreur : a est un tableau
struct { int c[3]; } s1, s2 = {3, 4, 5};
s1 = s2; // correct : l'opérateur d'affectation de copie défini implicitement
         // peut affecter les membres de données de type tableau

Dégénérescence tableau-vers-pointeur

Il y a une conversion implicite des lvalues et rvalues de type tableau vers des rvalues de type pointeur : elle construit un pointeur vers le premier élément d'un tableau. Cette conversion est utilisée chaque fois que des tableaux apparaissent dans un contexte où des tableaux ne sont pas attendus, mais des pointeurs le sont :

#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'  // affiche la taille du tableau
              << sizeof p << '\n'; // affiche la taille d'un pointeur
    // là où les tableaux sont acceptables mais pas les pointeurs, seuls les tableaux peuvent être utilisés
    g(a); // correct : la fonction prend un tableau par référence
//  g(p); // erreur
    for (int n : a)            // correct : les tableaux peuvent être utilisés dans les boucles range-for
        std::cout << n << ' '; // affiche les éléments du tableau
//  for (int n : p)            // erreur
//      std::cout << n << ' ';
    std::iota(std::begin(a), std::end(a), 7); // correct : begin et end prennent des tableaux
//  std::iota(std::begin(p), std::end(p), 7); // erreur
    // là où les pointeurs sont acceptables mais pas les tableaux, les deux peuvent être utilisés :
    f(a); // correct : la fonction prend un pointeur
    f(p); // correct : la fonction prend un pointeur
    std::cout << *a << '\n' // affiche le premier élément
              << *p << '\n' // idem
              << *(a + 1) << ' ' << a[1] << '\n'  // affiche le deuxième élément
              << *(p + 1) << ' ' << p[1] << '\n'; // idem
}

Tableaux multidimensionnels

Lorsque le type d'élément d'un tableau est un autre tableau, on dit que le tableau est multidimensionnel :

// tableau de 2 tableaux de 3 entiers chacun
int a[2][3] = {{1, 2, 3},  // peut être vu comme une matrice 2 × 3
               {4, 5, 6}}; // avec un agencement row-major

Notez que lorsque la conversion tableau-vers-pointeur est appliquée, un tableau multidimensionnel est converti en un pointeur vers son premier élément (par exemple, un pointeur vers sa première ligne ou vers son premier plan) : la conversion tableau-vers-pointeur n'est appliquée qu'une seule fois.

int a[2];            // tableau de 2 int
int* p1 = a;         // a se dégrade en un pointeur vers le premier élément de a
int b[2][3];         // tableau de 2 tableaux de 3 int
// int** p2 = b;     // erreur : b ne se dégrade pas en int**
int (*p2)[3] = b;    // b se dégrade en un pointeur vers la première ligne à 3 éléments de b
int c[2][3][4];      // tableau de 2 tableaux de 3 tableaux de 4 int
// int*** p3 = c;    // erreur : c ne se dégrade pas en int***
int (*p3)[3][4] = c; // c se dégrade en un pointeur vers le premier plan 3 × 4 éléments de c

Tableaux de taille inconnue

Si expr est omis dans la déclaration d'un tableau, le type déclaré est "tableau de taille inconnue de T", qui est un type de type incomplet , sauf lorsqu'il est utilisé dans une déclaration avec un initialiseur agrégé :

extern int x[];      // le type de x est "tableau de taille inconnue d'entiers"
int a[] = {1, 2, 3}; // le type de a est "tableau de 3 entiers"

Parce que les éléments de tableau ne peuvent pas être des tableaux de taille inconnue, les tableaux multidimensionnels ne peuvent pas avoir de taille inconnue dans une dimension autre que la première :

extern int a[][2]; // correct : tableau de taille inconnue de tableaux de 2 int
extern int b[2][]; // erreur : le tableau a un type d'élément incomplet

S'il existe une déclaration précédente de l'entité dans la même portée où la dimension a été spécifiée, une dimension de tableau omise est considérée comme identique à celle de cette déclaration antérieure, et de même pour la définition d'un membre de données statique d'une classe :

extern int x[10];
struct S
{
    static int y[10];
};
int x[];               // OK : limite est 10
int S::y[];            // OK : limite est 10
void f()
{
    extern int x[];
    int i = sizeof(x); // erreur : type d'objet incomplet
}

Les références et les pointeurs vers des tableaux de taille inconnue peuvent être formés, mais ne peuvent pas (jusqu'au C++20) et peuvent (depuis C++20) être initialisés ou assignés à partir de tableaux et de pointeurs vers des tableaux de taille connue. Notez que dans le langage de programmation C, les pointeurs vers des tableaux de taille inconnue sont compatibles avec les pointeurs vers des tableaux de taille connue et sont donc convertibles et assignables dans les deux directions.

extern int a1[];
int (&r1)[] = a1;  // correct
int (*p1)[] = &a1; // correct
int (*q)[2] = &a1; // erreur (mais correct en C)
int a2[] = {1, 2, 3};
int (&r2)[] = a2;  // correct (depuis C++20)
int (*p2)[] = &a2; // correct (depuis C++20)

Les pointeurs vers des tableaux de taille inconnue ne peuvent pas participer aux opérations arithmétiques sur les pointeurs et ne peuvent pas être utilisés à gauche de l' opérateur d'indice , mais peuvent être déréférencés.

Rvalues de tableau

Bien que les tableaux ne puissent pas être retournés par valeur depuis des fonctions et ne puissent pas être la cible de la plupart des expressions de cast, des prvalues de tableau peuvent être formés en utilisant un alias de type pour construire un tableau temporaire via une conversion fonctionnelle avec initialisation par accolades .

Comme les prvalues de classe, les prvalues de tableau se convertissent en xvalues par matérialisation temporaire lors de l'évaluation.

(depuis C++17)

Les tableaux xvalues peuvent être formés directement en accédant à un membre tableau d'un rvalue de classe ou en utilisant std::move ou un autre cast ou appel de fonction qui retourne une référence à un rvalue.

#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';           // taille du tableau
    f(X().i);                                    // correct : se lie à une xvalue
//  f(x.i);                                      // erreur : ne peut pas se lier à une lvalue
    int a[2][3];
    f(std::move(a));                             // correct : se lie à une xvalue
    using arr_t = int[2][3];
    f(arr_t{});                                  // correct : se lie à une prvalue
    f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // correct : se lie à une prvalue
}

Sortie :

24
24
24
24
24

Rapports de défauts

Les rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.

DR Appliqué à Comportement publié Comportement correct
CWG 393 C++98 un pointeur ou une référence vers un tableau de taille
inconnue ne pouvait pas être un paramètre de fonction
autorisé
CWG 619 C++98 lorsqu'omise, la taille d'un tableau ne pouvait
pas être déduite d'une déclaration précédente
déduction autorisée
CWG 2099 C++98 la taille d'un membre de données statique de type tableau
ne pouvait pas être omise même si un initialiseur est fourni
omission autorisée
CWG 2397 C++11 auto ne pouvait pas être utilisé comme type d'élément autorisé

Voir aussi

Documentation C pour Déclaration de tableau