Array declaration
Déclare un objet de type tableau.
ContenuSyntaxeUne déclaration de tableau est toute déclaration simple dont le déclarateur a la forme
Une déclaration de la forme Les tableaux peuvent être construits à partir de tout type fondamental (sauf
Il n'existe pas de tableaux de références ni de tableaux de fonctions. L'application de qualificateurs cv à un type tableau (via typedef ou manipulation de type de modèle) applique les qualificateurs au type d'élément, mais tout type tableau dont les éléments sont de type qualifié cv est considéré comme ayant la même qualification cv. // 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 = {};
Lorsqu'il est utilisé avec new[]-expression, la taille d'un tableau peut être nulle ; un tel tableau n'a pas d'éléments : int* p = new int[0]; // accessing p[0] or *p is undefined
delete[] p; // cleanup still required
En pratique, pour simplifier le langage, un pointeur vers un élément de tableau est parfois appelé pointeur vers le tableau : int arr[5] {};
int *p = arr;
On dit que AffectationLes 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-pointeurIl 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 :
Exécuter ce code
#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 multidimensionnelsLorsque 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 inconnueSi 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 tableauBien 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 .
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.
Exécuter ce code
#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éfautsLes rapports de défauts modifiant le comportement suivants ont été appliqués rétroactivement aux normes C++ précédemment publiées.
Voir aussi
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||