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

Declara un objeto de tipo array.

Contenidos

Sintaxis

Una declaración de array es cualquier declaración simple cuyo declarador tiene la forma

noptr-declarator [ expr  (opcional) ] attr  (opcional)
noptr-declarator - cualquier declarator válido, pero si comienza con * , & , o && , debe estar rodeado por paréntesis (de lo contrario, todo el declarator se trata como un pointer declarator o reference declarator ).
expr - una integral constant expression (until C++14) una converted constant expression de tipo std::size_t (since C++14) , que evalúa a un valor mayor que cero
attr - (since C++11) lista de attributes

Una declaración de la forma T a [ N ] ; , declara a como un objeto array object que consiste en N objetos de tipo T asignados contiguamente. Los elementos de un array se numeran 0 , …, N - 1 , y pueden accederse con el operador de subíndice [] , como en a [ 0 ] , …, a [ N - 1 ] .

Los arrays pueden construirse a partir de cualquier tipo fundamental (excepto void ), punteros , punteros a miembros , clases , enumeraciones , o desde otros arrays de tamaño conocido (en cuyo caso se dice que el array es multidimensional). En otras palabras, solo los tipos de objeto excepto los tipos array de tamaño desconocido pueden ser tipos de elemento de los tipos array. Los tipos array de tipo de elemento incompleto también son tipos incompletos.

El especificador posiblemente restringido (desde C++20) auto puede utilizarse como tipo de elemento de array en la declaración de un puntero o referencia a array, que deduce el tipo de elemento del inicializador o del argumento de función (desde C++14) , por ejemplo auto ( * p ) [ 42 ] = & a ; es válido si a es un lvalue de tipo int [ 42 ] .

(desde C++11)

No existen arrays de referencias ni arrays de funciones.

Aplicar cv-qualifiers a un tipo de array (a través de typedef o manipulación de tipos de plantilla) aplica los calificadores al tipo de elemento, pero cualquier tipo de array cuyos elementos sean de tipo calificado-cv se considera que tiene la misma calificación-cv.

// a y b tienen el mismo tipo calificado como const "array de 5 const char"
typedef const char CC;
CC a[5] = {};
typedef char CA[5];
const CA b = {};

Cuando se utiliza con new[]-expression , el tamaño de un array puede ser cero; dicho array no tiene elementos:

int* p = new int[0]; // acceder a p[0] o *p es indefinido
delete[] p; // la limpieza aún es requerida

Asignación

Los 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 puntero

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

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

Cuando 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 desconocido

Si 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 array

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

Al igual que los prvalues de clase, los prvalues de array se convierten en xvalues mediante materialización temporal cuando se evalúan.

(since C++17)

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.

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

Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.

DR Aplicado a Comportamiento publicado Comportamiento correcto
CWG 393 C++98 un puntero o referencia a un array de límite
desconocido no podía ser un parámetro de función
permitido
CWG 619 C++98 cuando se omitía, el límite de un array no podía
inferirse de una declaración previa
inferencia permitida
CWG 2099 C++98 el límite de un miembro de datos estático de array no
podía omitirse incluso si se proporcionaba un inicializador
omisión permitida
CWG 2397 C++11 auto no podía usarse como tipo de elemento permitido

Véase también

Documentación de C para Declaración de array