char str[x]
の初期化(P1) | char str1[10] = "123456789"; |
(P2) | char str2[10] = "1234567890"; |
(P3) | char str3[10] = "12345678901"; // compile-time error |
C言語では
(P2)のような間違い?をしてもコンパイルエラーにならないことに注意しよう.
(P2)は10文字分の配列しか用意していないところに10文字の初期値をしていしているので,末尾のNUL
文字を格納するスペースがたりていない.
このような場合,配列str2
の中身は{ 0x31, 0x32, ..., 0x39, 0x30 }
になって終端がNUL
文字にならなくなる.
なので,printf("%s\n", str2);
とすると,
1234567890^E)x※wk△bl%@@-$^x&…
みたいなメチャクチャ ハチャメチャな文字列が表示されることになる.
この動作は
char str[10] = "123456789";
のような書き方が単なるシンタックス シュガーであり
実はchar str[10] = { 0x31, 0x32, ..., 0x39, 0x00 };
と展開されるのだということを思い出せば納得できるかもしれない.
(P2)はコンパイル時エラーにしてほしいなぁ,コンパイルをうまく通ったなら“期待通りに”動作してほしいなぁ,と思う人は多いだろうけど,
C言語はあまり特例規則を増やさない方針で設計されているので,こんな感じになってる.
[※C++では,文字の配列を文字列で初期化する場合に限って,末尾にNUL
文字を入れる領域が足りない場合
(char array[4] = "abcd";
のように書いた場合)はエラーになることになった(C++ C.1.6参照).
ただし,C++でもchar array[4] = { 0x61, 0x62, 0x63, 0x64 };
のように書いた場合は依然としてエラーにならない(C言語と同じ動作になる).]
0x00
が補われる
あと,char str[10] = "abc";
は,char str[10] = { 0x61, 0x62, 0x63, 0x00, 0x00, 0x00, ... , 0x00 };
になることも覚えておこう.
char str[10] = { 0x61, 0x62, 0x63 };
も同じ結果になる.
“あれ?末尾に0x00
が必要では?”({ 0x61, 0x62, 0x63, 0x00 }
が正しいのでは?)と思うかもしれないけど,
意外にも“不要”が正しい[この仕様はC++“8.5.1 集成体”に明示されている].
配列の初期化では,初期化子並び内の要素数が足りないときは0
が付け足されることになっている.
[※ただし,この規則は初期化子をひとつももたない場合には適用されないことにも注意しよう.]
次の表は文字配列の初期化のルールをまとめたもの.
初期化方法 | 初期値(16進) | 備考 |
---|---|---|
char str1[10] = "123456789";
| 61 62 63 64 65 66 67 68 69 00 |
|
char str1[10] = "1234567890";
| 61 62 63 64 65 66 67 68 69 60 |
※C++ではコンパイル時エラー(Cはスルー) |
char str1[10] = "12345678901";
| ×コンパイル時エラー | |
char str[10] = "abc"; |
61 62 63 00 00 00 00 00 00 00 |
足りない部分は0x00 が補われる |
char str[10] = { 0x61, 0x62, 0x63 }; |
61 62 63 00 00 00 00 00 00 00 |
|
char str[10] = ""; |
00 00 00 00 00 00 00 00 00 00 |
|
char str[10]; |
不定値 | 未初期化変数の場合は何も起こらず不定値のまま |
C++の初期化は恐ろしく複雑になってて,
struct S { int a; static int b; int c; } s = { 1, 3 };
と書いたらs.a = 1
,s.c = 3
と初期化されるなんてルールも決まっている.
あんまり深入りしないでおこう….
[1] |
strncpy 文字配列の初期化の動作と strncpy の動作はとてもよく似てる(そのままかも).
char str[10] = "abc"; の初期化動作は,strncpy(str, 10, "abc"); と同じ感じ.
|