変数の初期化
(C言語における変数の初期化のわかりにくい点)
Copyright(C) 14May2003 coskx
C言語において同じ表現で,変数宣言の時と実行時で意味が異なることがあり,混乱の元となっている。
1.配列の宣言と初期化
配列を宣言する時の表現と,実行時に現れる要素を表す表現について,同じ表現が異なる意味になっている。
また宣言時には,値を配列に簡単に代入できるが,実行時に値を代入しようとすると面倒である。
int main()
{
int
ary1[10];
/*(1)*/
int ary2[]={1,2,3,4,5,6};
/*(2)*/
char str1[10]="ABCDEFG";
/*(3)*/
char
str2[]="ABCD";
/*(4)*/
ary1[9]=123;
/*(5)*/
ary2[]={4,5,6};
/*(6)この表現は誤り*/
str1[10]="ABCDEFG";
/*(7)この表現は誤り*/
str2[]="ABCD";
/*(8)この表現は誤り*/
str1="ABCDEFG";
/*(9)この表現は誤り*/
str2="ABCD";
/*(10)この表現は誤り*/
:
以下省略
この例で,変数宣言部は(1)〜(4)である。(5)〜(10)は実行部である。
(1)では次のような10この要素を持つ配列が定義される。配列ary1の第10要素を表しているわけではない。
ary1 (各要素はint型) | ||||||||||
要素番号 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
値 |
未定 |
未定 |
未定 |
未定 |
未定 |
未定 |
未定 |
未定 |
未定 |
未定 |
ところが(5)では実行部なので要素番号9の要素に123を格納するだけである。要素数9個の配列ができるわけではない。
(2)の宣言ではコンパイラは自動的に,初期値の数に等しい要素数の配列を作る。
ary2 (各要素はint型) | ||||||||||
要素番号 |
0 |
1 |
2 |
3 |
4 |
5 | ||||
値 |
1 |
2 |
3 |
4 |
5 |
6 |
ところが,(6)は実行時なので,この表現は文法上許されない。
もしこの要求を実現するには,各要素に1つずつ代入するしかない。
ary[0]=4;
ary[1]=5;
ary[2]=6;
(3)では次のような10この要素を持つ配列が定義される
str1 (各要素はchar型) | ||||||||||
要素番号 |
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
値 |
'A' |
'B' |
'C' |
'D' |
'E' |
'F' |
'G' |
'\0' |
未定 |
未定 |
ところが,(7)は実行時なので,この表現は文法上許されない。もしこの要求を実現するには,関数strcpy()を使って
strcpy(str1,"ABCDEFG")
とする。
(4)の宣言ではコンパイラは自動的に,初期値の数に等しい要素数の配列を作る。
str2 (各要素はchar型) | ||||||||||
要素番号 |
0 |
1 |
2 |
3 |
4 | |||||
値 |
'A' |
'B' |
'C' |
'D' |
'\0' |
ところが,(8)は実行時なので,この表現は文法上許されない。もしこの要求を実現するには,関数strcpy()を使って
strcpy(str2,"ABCD")
とする。
(9)(10)もともに実行時なので,文法上許されないのでもしこの要求を実現するには,関数strcpy()を使うことになる。
2.構造体の宣言と初期化
構造体を宣言する時に,構造体の各メンバに値を代入するのは簡単だが,実行時に構造体の各メンバに値を代入するには,各メンバごとに行わなければならない。
typedef struct { int main() |
この例で,変数宣言部は(1)〜(3)である。(4)は実行部である。
(1)ではp1.xに5が,p1.yに10が格納されたpoint_t型の変数p1が作られる。
(4)は実行時なので,この表現は文法上許されず,この要求を実現するには個別に代入し,次のように書く。
( p1.x=5;
p1.y=10; )
(2)(3)は配列の場合であり,(3)は最初の2つの要素が初期化される。
pa1 (各要素はpoint_t型) | ||||||||||||||||||||
要素番号 |
0 |
1 |
2 |
3 | ||||||||||||||||
値 |
未定 未定 |
未定 未定 |
未定 未定 |
未定 未定 |
pa2 (各要素はpoint_t型) | ||||||||||||||||||||
要素番号 |
0 |
1 |
2 |
3 | ||||||||||||||||
値 |
2 3 |
5 6 |
未定 未定 |
未定 未定 |
3.ポインタ変数の宣言と初期化 | |
int main() |
この例で,変数宣言部は〜(2)である。(3)〜は実行部である。
(1)「int *p1」は「p1は,int型変数のアドレスを格納することができるポインタ変数である」の意味である。
(3)「p1=&y」は(1)で宣言したint型変数のアドレスを格納することができるポインタ変数p1にint型変数yのアドレスを代入している。
(4)「*p1=x」は,変数yにxの値を代入していることになる。なぜなら,p1に変数yのアドレスが格納されているため,*p1は変数yを指しているからである。(*p1はポインタ変数p1の保持しているアドレスにあるint型変数を意味する)
次の2つが紛らわしいのでよく味わうこと
(2)「int *p2」ではint型変数のアドレスを格納することができるポインタ変数p2を確保し,ポインタ変数p2に変数xのアドレスを格納するところまで行う,変数宣言+変数初期化を表している。ポインタ変数p2に保存されているアドレスの位置にあるint型変数(p2が指しているint型変数)にxのアドレスを格納しているわけではない。
(5)「*p1=&y」は,表現が(2)と同じだが実行部にあるため「ポインタ変数p1に保存されているアドレスの位置にあるint型変数(p1が指しているint型変数)」にyのアドレスを格納する」という意味になり,文法上許されない記述である。