C の基本:配列
メモリの連続領域
多数の同じ型を持つデータは配列(array)により効率的に扱う事ができます。
Cにおける配列は「メモリの連続する領域に名前を付けたもの」と言えます。例えば
short a[3]; |
と書くと 3 つのshort型の値を収納できる配列を宣言しますが、これはメモリ上の 2×3 バイトの領域に「a」と言う名前を付けた事に他なりません。仮にそれが0x0029ff2a~0x0029ff2fであったとすれば、
アドレス | 値 | ||
---|---|---|---|
: | : | ||
0x0029FF2A | ? | a | |
0x0029FF2B | ? | ||
0x0029FF2C | ? | ||
0x0029FF2D | ? | ||
0x0029FF2E | ? | ||
0x0029FF2F | ? | ||
: | : |
となります。配列aのi番目の要素はa[i]によってアクセスでき、メモリ上次の様に名前が付いていると考える事もできます。
アドレス | 値 | ||
---|---|---|---|
: | : | ||
0x0029FF2A | ? | a[0] | |
0x0029FF2B | ? | ||
0x0029FF2C | ? | a[1] | |
0x0029FF2D | ? | ||
0x0029FF2E | ? | a[2] | |
0x0029FF2F | ? | ||
: | : |
大括弧[ ]に入れる番号は添字(index)と呼ばれます。
sizeofはその領域のサイズを教えてくれるので、今の場合sizeof(a)は 6 です。sizeof(a[0])で要素 1 つ分のサイズが分かるので、
sizeof(a) / sizeof(a[0]) |
で配列の長さを知る事ができます。
(時に「配列はポインタと同等」と言われる事がありますが、実情はもう少し複雑です。詳しくは「C の詳細:配列とポインタ」)
文字列
文字の並びをプログラミングでは文字列(character string、または単に string)と呼びますが、C の文字列はそのままcharの配列として実現されています。例えば文字列「abc」を変数strに収納するには
char str[] = "abc"; |
とします。これにより、メモリは
アドレス | 値 | ||
---|---|---|---|
: | : | ||
? | 'a' | str | |
? | 'b' | ||
? | 'c' | ||
? | '\0' | ||
: | : |
となります。ダブルクォート"が文字列に使われるのに対して、シングルクォート'は一文字の値を表すのに使われます。'\0'は文字コードが 0 の文字、つまりヌル文字です。(「C の知識:リテラル」を参照)
ここで注意すべきなのが、最後にあるヌル文字'\0'です。これは文字列の終わりを表すもので、配列としての長さの情報が失われる、例えば文字列をcharへのポインタとして他の関数に渡したりする場合に必要となります。
配列の長さを指定してもよく、文字数+1 にすると上の場合と同じになります。
char str[4] = "abc"; |
それよりも長くするとヌル文字以降は初期化されません。一方で文字数丁度にする事もできますが、この場合はヌル文字が追加されない6.7.8#14点に注意が必要です。
charへのポインタにも同じ書き方ができるのですが、
char *str = "abc"; |
これは配列の場合と働きが異なるので注意が必要です。この場合strはポインタの名前であり、そこには何らかのアドレスが入る筈だからです。
実際このコードを実行すると、次の様に何らかの場所へ{ 'a', 'b', 'c', '\0' }が記憶され、strはそのアドレスを指す事になります。
アドレス | 値 | ||
---|---|---|---|
: | : | ||
0x0028FF2C | 0x64 | str | |
0x0028FF2D | 0xA0 | ||
0x0028FF2E | 0x40 | ||
0x0028FF2F | 0x00 | ||
: | : | ||
0x0040A064 | 'a' | *str | |
0x0040A065 | 'b' | ||
0x0040A066 | 'c' | ||
0x0040A067 | '\0' | ||
: | : |