「配列の初期化 指示付きの初期化指定子」の版間の差分

提供: C言語入門
移動: 案内検索
(ページの作成:「C言語の配列は、配列の宣言時に初期化することができます。C99で追加された配列の指示付き初期化指定子により、従来より...」)
 
(相違点なし)

2014年3月31日 (月) 15:55時点における最新版

C言語の配列は、配列の宣言時に初期化することができます。C99で追加された配列の指示付き初期化指定子により、従来よりもコードのわかりやすさや柔軟な初期化ができるようになりました。

読み方

指示付きの初期化指定子
しじつき の しょきかしていし

概要

従来までのC言語の配列の初期化では、要素を指定できませんでした。配列の要素数が増えるにしたがって、どの要素を初期化しているコードなのか、見通しが悪くなる問題がありました。

// 従来の初期化
int a[3] = {
	1,
	2,
	3
};

C99で導入された、「指示付きの初期化指定子」で初期化する場合、要素を指定して、初期化ができるため、見通しが良くなります。

int a[3] = {
	[0] = 1,
	[1] = 2,
	[2] = 3
};

配列サイズを指定せず、以下の初期化を行う場合、要素数が 10 で、 0番から9番が0で初期化され、10番目(要素9)が9で初期化されます。

int a[] = {
	[9] = 9
};

指示付きあり、と、指示なしを混在させたケースは、以下の通りです。

int a[] = {
	[3] = 3,
	4,
	[8] = 8,
	9
};

上記のコードは、以下の初期化が行われるのと同義です。

a[0] = 0;
a[1] = 0;
a[2] = 0;
a[3] = 3;
a[4] = 4;
a[5] = 0;
a[6] = 0;
a[7] = 0;
a[8] = 8;
a[9] = 9;

C99の配列の指示付き初期化の罠

初期化は、上から順番に評価されます。 このコードがおかしいのは、3番目の要素(a[2])が2回初期化されている点です。

int a[] = {
	[2] = 33,
	[1] = 22,
	55		// <- [2] = 55 と同義
};

最後を0ターミネートするような配列の初期化を行う場合に、指示付きで、ターミネットの1つ前の指示を「ターミネートの1つ前の指示」を与えないと間違いがおきます。

char a[] = {
	1,
	2,
	0
};

これは、ポインタ配列の最後にNULLを設定しておく、といったときによくあるコードです。

char *str[] = {
	str1,
	str2,
	NULL
};

指示付きは、指示があるため、並び順を適当にしても初期化できてしまいます。ターミネートの指示を出さないときに、間違いが起こる可能性があります。

const int ZERO = 0;
const int ONE = 1;
char a[] = {
	[ONE] = 2,
	[ZERO] = 1,
	0
};

意図通りのコードという意味では、以下のコードが正しいです。

char a[] = {
	[ZERO] = 1,
	[ONE] = 2,
	0
};

もしくは、ターミネートの指示を省略しない、というのが間違いをなくします。ターミネートがあれば、並び順は、自由になります。

const int ZERO = 0;
const int ONE = 1;
const int TERMINATE = 2;
char a[] = {
	[ZERO] = 1,
	[ONE] = 2,
	[TERMINATE] = 0
};

init_array1.c の例

ソースコード init_array1.c

/*
 * init_array.c
 * Copyright (C) 2014 kaoru <kaoru@bsd>
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int
main(int argc, char *argv[])
{
        int a[3] = {
                [0] = 1,
                [1] = 2,
                [2] = 3
        };
        exit(EXIT_SUCCESS);
}

コンパイル

cc  init_array1.c -o init_array1

実行例

出力なし。

% ./init_array1

init_array2.c の例

ソースコード init_array2.c

/*
 * init_array.c
 * Copyright (C) 2014 kaoru <kaoru@bsd>
 */
#include <stdio.h>
#include <stdlib.h>
 
int
main(int argc, char *argv[])
{
        int a[] = {
                [9] = 9
        };
        int i = 0;
        (void)printf("%ld\n", sizeof(a) / sizeof(int) );
        for (i = 0; i < (sizeof(a)/sizeof(int)); i++) {
                (void) printf("%d ", a[i]);
        }
        putchar('\n');
        exit(EXIT_SUCCESS);
}

コンパイル

cc  init_array2.c -o init_array2

実行例

% ./init_array2
10
0 0 0 0 0 0 0 0 0 9

init_array3.c の例

ソースコード init_array3.c

/*
 * init_array.c
 * Copyright (C) 2014 kaoru <kaoru@bsd>
 */
 
#include <stdio.h>
#include <stdlib.h>
 
int
main(int argc, char *argv[])
{
        int a[] = {
                [3] = 3,
                4,
                [8] = 8,
                9
        };
        int i = 0;
        (void)printf("%ld\n", sizeof(a) / sizeof(int) );
        for (i = 0; i < (sizeof(a)/sizeof(int)); i++) {
                (void) printf("%d ", a[i]);
        }
        putchar('\n');
        exit(EXIT_SUCCESS);
}

コンパイル

cc  init_array3.c -o init_array3

実行例

% ./init_array3
10
0 0 0 3 4 0 0 0 8 9

関連項目

  1. 配列の初期化
  2. 配列の要素数を調べる
  3. 配列の初期化 指示付きの初期化指定子