Array declaration
Declara un objeto de tipo array.
ContenidoSintaxisUna declaración de array es cualquier declaración simple cuyo declarador tiene la forma
Una declaración de la forma Los arrays se pueden construir a partir de cualquier tipo fundamental (excepto
No existen arrays de referencias ni arrays de funciones. Aplicar calificadores cv a un tipo array (a través de typedef o manipulación de tipos de plantilla) aplica los calificadores al tipo de elemento, pero cualquier tipo array cuyos elementos son de tipo calificado con cv se considera que tiene la misma calificación 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 = {};
Cuando se usa con new[]-expresión, el tamaño de un array puede ser cero; dicho array no tiene elementos: int* p = new int[0]; // accessing p[0] or *p is undefined
delete[] p; // cleanup still required
En la práctica, por simplicidad en la redacción, a veces se hace referencia a un puntero a un elemento de array como un puntero al array: int arr[5] {};
int *p = arr;
Se dice que AsignaciónLos objetos de tipo array no pueden ser modificados en su totalidad: aunque son lvalues (por ejemplo, se puede tomar la dirección de un array), no pueden aparecer en el lado izquierdo de un operador de asignación: int a[3] = {1, 2, 3}, b[3] = {4, 5, 6}; int (*p)[3] = &a; // correcto: se puede tomar la dirección de a a = b; // error: a es un array struct { int c[3]; } s1, s2 = {3, 4, 5}; s1 = s2; // correcto: el operador de asignación de copia definido implícitamente // puede asignar miembros de datos de tipo array Decaimiento de array a punteroExiste una conversión implícita de lvalues y rvalues de tipo array a rvalues de tipo puntero: construye un puntero al primer elemento de un array. Esta conversión se utiliza siempre que los arrays aparecen en contextos donde no se esperan arrays, pero sí punteros:
Ejecutar este código
#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' // imprime el tamaño del array << sizeof p << '\n'; // imprime el tamaño de un puntero // donde los arrays son aceptables pero los punteros no, solo pueden usarse arrays g(a); // correcto: la función toma un array por referencia // g(p); // error for (int n : a) // correcto: los arrays pueden usarse en bucles range-for std::cout << n << ' '; // imprime los elementos del array // for (int n : p) // error // std::cout << n << ' '; std::iota(std::begin(a), std::end(a), 7); // correcto: begin y end toman arrays // std::iota(std::begin(p), std::end(p), 7); // error // donde los punteros son aceptables pero los arrays no, ambos pueden usarse: f(a); // correcto: la función toma un puntero f(p); // correcto: la función toma un puntero std::cout << *a << '\n' // imprime el primer elemento << *p << '\n' // mismo << *(a + 1) << ' ' << a[1] << '\n' // imprime el segundo elemento << *(p + 1) << ' ' << p[1] << '\n'; // mismo } Arreglos multidimensionalesCuando el tipo de elemento de un array es otro array, se dice que el array es multidimensional: // arreglo de 2 arreglos de 3 enteros cada uno int a[2][3] = {{1, 2, 3}, // puede verse como una matriz 2 × 3 {4, 5, 6}}; // con disposición row-major Tenga en cuenta que cuando se aplica la conversión de array a puntero, un array multidimensional se convierte a un puntero a su primer elemento (por ejemplo, un puntero a su primera fila o a su primer plano): la conversión de array a puntero se aplica solo una vez. int a[2]; // array de 2 int int* p1 = a; // a decae a un puntero al primer elemento de a int b[2][3]; // array de 2 arrays de 3 int // int** p2 = b; // error: b no decae a int** int (*p2)[3] = b; // b decae a un puntero a la primera fila de 3 elementos de b int c[2][3][4]; // array de 2 arrays de 3 arrays de 4 int // int*** p3 = c; // error: c no decae a int*** int (*p3)[3][4] = c; // c decae a un puntero al primer plano de 3 × 4 elementos de c Arreglos de límite desconocidoSi expr se omite en la declaración de un array, el tipo declarado es "array de límite desconocido de T", que es un tipo de tipo incompleto , excepto cuando se utiliza en una declaración con un inicializador de agregado : extern int x[]; // el tipo de x es "array de límite desconocido de int" int a[] = {1, 2, 3}; // el tipo de a es "array de 3 int" Debido a que los elementos de un array no pueden ser arrays de límite desconocido, los arrays multidimensionales no pueden tener límite desconocido en una dimensión distinta a la primera: extern int a[][2]; // correcto: array de límite desconocido de arrays de 2 int extern int b[2][]; // error: array tiene tipo de elemento incompleto Si hay una declaración previa de la entidad en el mismo ámbito en el que se especificó el límite, un límite de arreglo omitido se toma igual que en esa declaración anterior, y de manera similar para la definición de un miembro de datos estático de una clase: extern int x[10]; struct S { static int y[10]; }; int x[]; // CORRECTO: el límite es 10 int S::y[]; // CORRECTO: el límite es 10 void f() { extern int x[]; int i = sizeof(x); // error: tipo de objeto incompleto } Se pueden formar referencias y punteros a arrays de límite desconocido, pero no pueden (until C++20) y pueden (since C++20) ser inicializados o asignados desde arrays y punteros a arrays de límite conocido. Nótese que en el lenguaje de programación C, los punteros a arrays de límite desconocido son compatibles con punteros a arrays de límite conocido y por lo tanto son convertibles y asignables en ambas direcciones. extern int a1[]; int (&r1)[] = a1; // correcto int (*p1)[] = &a1; // correcto int (*q)[2] = &a1; // error (pero correcto en C) int a2[] = {1, 2, 3}; int (&r2)[] = a2; // correcto (desde C++20) int (*p2)[] = &a2; // correcto (desde C++20) Los punteros a arrays de límite desconocido no pueden participar en aritmética de punteros y no pueden usarse en el lado izquierdo del operador de subíndice , pero pueden ser desreferenciados. Valores r de arrayAunque los arrays no pueden ser devueltos de funciones por valor y no pueden ser objetivos de la mayoría de expresiones de cast, los prvalues de array pueden formarse usando un alias de tipo para construir un temporal de array usando cast funcional con inicialización entre llaves .
Array xvalues pueden formarse directamente accediendo a un miembro array de un rvalue de clase o utilizando std::move u otra conversión o llamada a función que devuelva una referencia a rvalue.
Ejecutar este código
#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'; // tamaño del array f(X().i); // correcto: se enlaza a xvalue // f(x.i); // error: no se puede enlazar a lvalue int a[2][3]; f(std::move(a)); // correcto: se enlaza a xvalue using arr_t = int[2][3]; f(arr_t{}); // correcto: se enlaza a prvalue f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // correcto: se enlaza a prvalue } Salida: 24 24 24 24 24 Informes de defectosLos siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.
Véase también
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||