名前空間
変種
操作

配列宣言

From cppreference.com
< cpp‎ | language
 
 
C++言語
全般
フロー制御
条件実行文
if
繰り返し文 (ループ)
for
範囲for (C++11)
ジャンプ文
関数
関数宣言
ラムダ式
inline指定子
動的例外仕様 (C++17まで*)
noexcept指定子 (C++11)
例外
名前空間
指定子
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
記憶域期間指定子
初期化
代替表現
リテラル
ブーリアン - 整数 - 浮動小数点数
文字 - 文字列 - nullptr (C++11)
ユーザー定義 (C++11)
ユーティリティ
属性 (C++11)
typedef宣言
型エイリアス宣言 (C++11)
キャスト
メモリ確保
クラス
クラス固有の関数プロパティ
explicit (C++11)
static

特殊メンバ関数
テンプレート
その他
 
 

配列型のオブジェクトを宣言します。

目次

[編集] 構文

配列宣言は、宣言子が以下の形式をとる単純な宣言です。

noptr-declarator [expr (オプション)] attr (オプション)
noptr-declarator - 任意の有効な宣言子ですが、*&、または&&で始まる場合は括弧で囲む必要があります(そうしないと、宣言子全体がポインタ宣言子または参照宣言子として扱われます)。
expr - 整数定数式(C++14まで)変換された定数式 (型はstd::size_t)(C++14以降)。0より大きい値に評価されます。
attr - (C++11以降) 属性のリスト

T a[N];という形式の宣言は、aを、型TN個の連続して割り当てられたオブジェクトからなる配列オブジェクトとして宣言します。配列の要素には0からN - 1までの番号が付けられており、添字演算子 [] を使用して、a[0]、…、a[N - 1]のようにアクセスできます。

配列は、任意の基本型voidを除く)、ポインタメンバへのポインタクラス列挙型、または既知の境界を持つ他の配列から構成できます(この場合、配列は多次元配列と呼ばれます)。言い換えれば、要素の型になれるのは、境界不明の配列型を除くオブジェクト型のみです。要素の型が不完全な配列型も不完全な型です。

配列へのポインタまたは参照の宣言では、制約付きの可能性がある(C++20以降) auto 指定子を配列要素型として使用できます。これは、初期化子または関数引数(C++14以降)から要素型を推論します。例えば、auto (*p)[42] = &a;は、aが型int[42]の左辺値であれば有効です。

(C++11以降)

参照の配列や関数の配列はありません。

配列型にcv修飾子を適用する(typedefまたはテンプレート型操作を通じて)と、修飾子は要素型に適用されますが、要素がcv修飾型である配列型は、同じ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 = {};

new[]-expressionで使用される場合、配列のサイズはゼロになることがあります。このような配列には要素がありません。

int* p = new int[0]; // accessing p[0] or *p is undefined
delete[] p; // cleanup still required

[編集] 代入

配列型のオブジェクトは全体として変更できません。それらは左辺値(例えば、配列のアドレスを取得できる)ですが、代入演算子の左側に現れることはできません。

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: implicitly-defined copy assignment operator
         // can assign data members of array type

[編集] 配列からポインタへの変換 (Array-to-pointer decay)

配列型の左辺値および右辺値からポインタ型の右辺値への暗黙の変換があります。これは配列の最初の要素へのポインタを構築します。この変換は、配列が予期されないがポインタが予期されるコンテキストで配列が出現するときに常に使用されます。

#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'  // 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); // okay: function takes an array by reference
//  g(p); // error
 
    for (int n : a)            // okay: 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); // okay: begin and 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); // okay: function takes a pointer
    f(p); // okay: function takes a pointer
 
    std::cout << *a << '\n' // prints the first element
              << *p << '\n' // same
              << *(a + 1) << ' ' << a[1] << '\n'  // prints the second element
              << *(p + 1) << ' ' << p[1] << '\n'; // same
}

[編集] 多次元配列

配列の要素型が別の配列である場合、その配列は多次元であると言われます。

// array of 2 arrays of 3 int each
int a[2][3] = {{1, 2, 3},  // can be viewed as a 2 × 3 matrix
               {4, 5, 6}}; // with row-major layout

配列からポインタへの変換が適用される場合、多次元配列は最初の要素へのポインタ(例えば、最初の行または最初の平面へのポインタ)に変換されます。配列からポインタへの変換は一度だけ適用されます。

int a[2];            // array of 2 int
int* p1 = a;         // a decays to a pointer to the first element of a
 
int b[2][3];         // array of 2 arrays of 3 int
// int** p2 = b;     // error: b does not decay to int**
int (*p2)[3] = b;    // b decays to a pointer to the first 3-element row of b
 
int c[2][3][4];      // array of 2 arrays of 3 arrays of 4 int
// int*** p3 = c;    // error: c does not decay to int***
int (*p3)[3][4] = c; // c decays to a pointer to the first 3 × 4-element plane of c

[編集] 境界不明の配列

配列の宣言でexprが省略された場合、宣言される型は「Tの境界不明の配列」であり、これは集約初期化子を持つ宣言で使用される場合を除き、一種の不完全型です。

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"

配列の要素は境界不明の配列にはなれないため、多次元配列は最初の次元以外の次元で境界を不明にすることはできません。

extern int a[][2]; // okay: array of unknown bound of arrays of 2 int
extern int b[2][]; // error: array has incomplete element type

同じスコープ内に、境界が指定されたエンティティの先行する宣言がある場合、省略された配列境界はその先行する宣言と同じであると見なされ、クラスの静的データメンバの定義も同様です。

extern int x[10];
struct S
{
    static int y[10];
};
 
int x[];               // OK: bound is 10
int S::y[];            // OK: bound is 10
 
void f()
{
    extern int x[];
    int i = sizeof(x); // error: incomplete object type
}

境界不明の配列への参照とポインタを形成できますが、既知の境界を持つ配列と配列へのポインタから初期化または代入することはできません。(C++20まで)既知の境界を持つ配列と配列へのポインタから初期化または代入できます。(C++20以降)。Cプログラミング言語では、境界不明の配列へのポインタは既知の境界を持つ配列へのポインタと互換性があり、両方向に変換および代入可能です。

extern int a1[];
 
int (&r1)[] = a1;  // okay
int (*p1)[] = &a1; // okay
int (*q)[2] = &a1; // error (but okay in C)
 
int a2[] = {1, 2, 3};
int (&r2)[] = a2;  // okay (since C++20)
int (*p2)[] = &a2; // okay (since C++20)

境界不明の配列へのポインタは、ポインタ算術に参加できず、添字演算子の左側で使用することはできませんが、逆参照することはできます。

[編集] 配列の右辺値 (Array rvalues)

配列は関数から値で返したり、ほとんどのキャスト式のターゲットになったりすることはできませんが、波括弧初期化関数キャストを使用して配列一時オブジェクトを構築するために型エイリアスを使用することで、配列のprvaluesを形成できます。

クラストprvaluesと同様に、配列prvaluesは評価されるときに一時的な実体化によってxvaluesに変換されます。

(C++17以降)

配列のxvaluesは、クラスのrvalueの配列メンバに直接アクセスするか、std::moveまたは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';           // size of the array
    f(X().i);                                    // okay: binds to xvalue
//  f(x.i);                                      // error: cannot bind to lvalue
 
    int a[2][3];
    f(std::move(a));                             // okay: binds to xvalue
 
    using arr_t = int[2][3];
    f(arr_t{});                                  // okay: binds to prvalue
    f(identity<int[][3]>{{1, 2, 3}, {4, 5, 6}}); // okay: binds to prvalue
 
}

出力

24
24
24
24
24

[編集] Defect reports (欠陥報告)

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
CWG 393 C++98 境界不明の配列へのポインタまたは参照は
関数パラメータになれなかった
許可
CWG 619 C++98 省略された場合、配列の境界は
以前の宣言から推論できなかった
推論が可能になった
CWG 2099 C++98 配列の静的データメンバの境界は
初期化子が提供されていても省略できなかった
省略が可能になった
CWG 2397 C++11 autoを要素型として使用できなかった 許可

[編集] 関連項目

Cドキュメント: 配列宣言
English 日本語 中文(简体) 中文(繁體)