Array declaration
Declares an object of array type.
Contents |
[edit] Syntax
An array declaration is any simple declaration whose declarator has the form
noptr-declarator [ constexpr(optional) ] attr(optional)
|
(1) | ||||||||
noptr-declarator | - | any valid declarator, but if it begins with *, &, or &&, it has to be surrounded by parentheses. |
attr(C++11) | - | optional list of attributes |
constexpr | - | a constant expression of integral type which evaluates to a value greater than zero |
A declaration of the form T a[N];, declares a
as an array object that consists of N
contiguously allocated objects of type T
. The elements of an array are numbered 0...N-1
, and may be accessed with the member access operator [], as in a[0] ... a[N-1].
Arrays can be constructed from any fundamental type (except void), pointers, pointers to members, classes, enumerations, or from other arrays (in which case the array is said to be multi-dimensional). There are no arrays of references, arrays of functions, or arrays of incomplete types.
[edit] Assignment
Objects of array type cannot be modified: even though they are lvalues (e.g. an address of array can be taken), they cannot appear on the left hand side of an assignment operator:
int a[3] = {1,2,3}, b[3] = {4,5,6}; int (*p)[3] = &a; // okay, address of a can be taken a = b; // error, a is an array struct { int c[3]; } s1, s2 = {3,4,5}; s1 = s2; // okay: implicity-defined copy assignment operator // can assign data members of array type
[edit] Array to pointer decay
There is an implicit conversion from lvalues and rvalues of array type to rvalues of pointer type: it constructs a pointer to the first element of an array. This conversion is used whenever arrays appear in context where arrays are not expected, but pointers are:
#include <iostream> #include <numeric> #include <iterator> 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' // prints size of array << sizeof p << '\n'; // prints size of a pointer // where arrays are acceptable, but pointers aren't, only arrays may be used g(a); // OK: function takes an array by reference // g(p); // Error for(int n: a) // OK: arrays can be used in range for loops std::cout << n << ' '; // prints elements of the array // for(int n: p) // Error // std::cout << n << ' '; std::iota(std::begin(a), std::end(a), 7); // OK: begin/end take arrays // std::iota(std::begin(p), std::end(p), 7); // Error // where pointers are acceptable, but arrays aren't, both may be used: f(a); // OK: function takes a pointer f(p); // OK: function takes a pointer std::cout << *a << '\n' // prints the first element << *p << '\n' // same << *(a+1) << ' ' << a[1] << '\n' // prints the second << *(p+1) << ' ' << p[1] << '\n'; }
[edit] Multidimensional arrays
When the element type of an array is another array, it is said that the array is multidimensional:
// array of 2 arrays of 3 ints each int a[2][3] = {{1,2,3}, // can be viewed as a 2x3 matrix {4,5,6}}; // with row-major layout
Note that when array-to-pointer conversion is applied, a multidimensional array is converted to a pointer to its first element, e.g., pointer to the first row:
int a[2][3]; // 2x3 matrix int (*p1)[3] = a; // pointer to the first 3-element row int b[3][3][3]; // 3x3x3 cube int (*p2)[3][3] = a; // pointer to the first 3x3 plane
[edit] Arrays of unknown bound
If constexpr is omitted in the declaration of an array, the type declared is "array of unknown bound of T", which is a kind of incomplete type, except when used in a declaration with an aggregate initializer:
extern int x[]; // the type of x is "array of unknown bound of int" int a[] = {1,2,3}; // the type of a is "array of 3 int"
[edit] Array rvalues
An array rvalue expression may be formed by accessing an array member of a class rvalue or by using an identity template to construct an array temporary directly:
#include <iostream> #include <type_traits> 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'; // size of the arrary f(X().i); // OK, binds to rvalue // f(x.i); // Error: cannot bind to lvalue f(identity<int[][3]>{{1,2,3},{4,5,6}}); // OK, binds to rvalue }
Output:
24 24 24