2.変数・配列

2-6. 配列を使う

◆配列を使う

まずは定義から、

int i[10];

これはint型の変数を10個配列にして定義すると言う意味になります。

データ型 配列変数名[要素数];

こんな感じになります。もちろん修飾子つけることもできます。

次に配列の初期化の仕方、

int i[10]={24,64,32,78,35,23,85,77,12,76};

これは宣言時に初期化する時の書き方です。10個の要素をカンマ区切りで記述します。

また、宣言時に初期化する時は要素数を省略することが出来ます。
そのときは、初期化した要素の数により要素数が決定されます。

次に宣言時以外での代入(初期化)の仕方を示します。

i[0]=24;
i[1]=64;
i[2]=32;
i[3]=78;
i[4]=35;
i[5]=23;
i[6]=85;
i[7]=77;
i[8]=12;
i[9]=76;

とこんな感じです。ここで注目すべき点は要素番号が0から始まることです。
宣言時と違うのはカッコの中は要素番号になっていることです。

float double型の配列に関しても同じことです。

#include<stdio.h>

main()
{
    int i[10]={24,64,32,78,35,23,85,77,12,76};
    int count;
    for(count=0;count< =9;count++){
        printf("i[%d]=%d\n",count,i[count]);
    }
}

このプログラムを実行すると

i[0]=24
i[1]=64
i[2]=32
i[3]=78
i[4]=35
i[5]=23
i[6]=85
i[7]=77
i[8]=12
i[9]=76

と表示されたとおもいます。プログラムと合わせ見るとて配列全体と要素の
対応がわかると思います。

◆文字の配列

char型の配列、文字列の表示をします。

宣言時のフォーマット

char mojiretu[10]={‘A’,’B’,’C’,’D’,’E’,’F’,’G’,’H’,’I’,’\0′};

とまあこんな感じで初期化できますが余り実用的ではないですね。
そんなわけで(本当にそんなわけなのか?)特別な初期化法があります。

それは、(“)ダブルクォーテーションをつかうことでもっと簡単にできます。

char mojiretu[10]={“ABCDEFGHI”};

上の例では\0の記述が見られませんが、ダブルクォーテーションで囲まれた文字列には終端記号として自動的に\0が付加されます。

これが重要で文字列を表示する時に文字列の終わりの記号として\0を検出すると文字の出力を終了するようになっています。(でなければ暴走する)

もちろん\0の分のメモリは確保しなくてはなりませんので最低でも格納する文字数+1の要素数が必要です。(全角文字1つはは2文字で計算)

ついでですがダブルクォーテーションを使って文字列の初期化する時は、{}中括弧を省略することが可能です。

char mojiretu[]=”ABCDEFGHIJ”;

このように要素数を省略したときは初期値によりメモリの確保が行われます。
(必ず宣言時に初期化する必要があります)

char zenkaku[]=”漢字”;

もちろん、全角文字を格納するときはダブルクォーテーションを使わないと大変です。

◆二次元配列

それでは、二次元配列に移りましょう。とりあえず見た目から…

int matrix[3][4]={ { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 } };

これは3×4の行列です。

初期化するとき、列ごとに中括弧で囲んでいますが特になくてもかまいません
(ただし、見栄えは悪くなります)

int matrix[3][4]={ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

確かに、見栄えが悪いですね… でもメモリに格納される順番は同じなので両方ともまったく同じ配列として使用できます。

アクセスするときは今まで同じように行・列ともに0番目より始まります。

matrix[0][0]=1;
matrix[0][1]=2;
matrix[0][2]=3;
matrix[0][3]=4;
matrix[1][0]=5;
matrix[1][1]=6;
matrix[1][2]=7;
matrix[1][3]=8;
matrix[2][0]=9;
matrix[2][1]=10;
matrix[2][2]=11;
matrix[2][3]=12;

実際は上のように対応しています。

◆配列を使いこなそう

さっきは、二次元配列の宣言について少し触れてみました。

int matrix[3][4]={ { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 } };

通常上のとおりですが、ここで要素数の省略をやってみます。

int matrix[ ][4]={ { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 } };

これは、コンパイル可能です

int matrix[3][ ]={ { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 } };

int matrix[ ][ ]={ { 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 } };

しかし、上の2つはコンパイル時にエラーが出ます。要素の中で列数が入力されていないといけないようです。

これが三次元配列になると、

int matrix[3][4][5]=…(省略)

のように宣言しますがこれも要素の省略は一番左端の括弧の中だけになります。

int matrix[ ][4][5]=…(省略)

それでは、文字列の配列になるとどうでしょう。
(注:昨日やったのは文字の配列=文字列)

char str[][12]={
“あはよう”,
“こんにちは”,
“こんばんは”
};

ざっとこんな感じです。
『文字列』が『3行』こちらのほうが行列の意味を理解しやすいと思います。

2次元配列のときは
データ型 配列名[行][列]={{ , , , }, 縦…行
{ , , , }, 横…列
{ , , , }};
です。

しかし、ここで少し疑問が出てくると思います。
上の文字列の場合、各行の列数が違うことです。
たぶん、これが列数をあらかじめ指定しなければならないわけだと個人的に考えていますが…

◆二次元配列のまとめ

昨日の続きで、もし配列の要素数が各行で異なっていたらどうなるか?

int matrix[3][4]={{1,2,3,4},
{5,6,7 },
{8,9 }};

となっていた場合、初期化されなかった要素は0で埋められます。
実際にそうなっているかprintf()で表示してみましょう。

#include<stdio.h>

main()
{
    int i,j;
    int matrix[3][4]={{1,2,3,4},
                      {5,6,7  },
                      {8,9    }};
    for(i=0;i<3;i++){
        for(j=0;j<4;j++)printf("%d ",matrix[i][j]);printf("\n");}
}

結果、

1 2 3 4
5 6 7 0
8 9 0 0

と表示され初期化してないところは0で埋められていることが確認できます。

それでは、文字列の場合どうなるのでしょう?

#include<stdio.h>
main()
{
    int i,j;
    char str[3][12]={
                    "ABCDEFGH",
                    "abcde",
                    "ABC"
                   };
    for(i=0;i<3;i++){
        for(j=0;j<12;j++)printf("%c",str[i][j]);printf("\n");}
}

これを実行すると

ABCDEFGH
abcde
ABC

と表示され初期化されていない要素は表示されませんでした。
つぎに10進数で表示するために%cを%dに換えます。すると、

65666768697071720000
9798991001010000000
656667000000000

と表示されちゃんと初期化していないところは数値の0が入っていることがわかります。とくにNULL文字も数値は0なので文字表示のとき初期化されていない部分は、表示されなかったのでしょう。

要素の初期化は一部の省略も可能な事から、列の要素数が未指定だと最初の行をメモリに記憶するときに全体が収まる列数がどれだけ必要化がわからないからではないかと思うので列の要素数が省略できないのではないかと思っています。(かなり個人的な意見なので間違っていたらごめんなさい…)

次章
3.printfを使いこなそう