Cによるプログラミング入門12
配列と構造体

 今回は、関連するデータをまとめておく方法についてです。


 入門6で配列というものを紹介しました。これは、「同じ種類のもの」を番号をつけてまとめておくのに便利です。
 入門6で考えた配列は、添字が1つだけのものでしたが、添字を複数つけることもできます。このようなものを一般に、多次元配列などといいます。たとえば、

int a[3][2];

と書けば、3x2の配列ができます。これは、

a[0][0] a[0][1]
a[1][0] a[1][1]
a[2][0] a[2][1]

という要素ができたということです。このような配列(上の例では、添字が2つなので、2次元配列などといいます)は

int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};

などとして初期化することができます。

/* hairetu.c */
#include <stdio.h>

int main(void)
{
    int a[3][2] = {{1, 2}, {3, 4}, {5, 6}};
    int i, j;
    for(i = 0; i < 3; i++){
        for(j = 0; j < 2; j++){
            printf("a[%d][%d] = %d ", i, j, a[i][j]);
        }
    }
    return 0;
}

Fig.1 Hairetu.exe

 実は、初期化では、中の中カッコをはずして、

int a[3][2] = {1, 2, 3, 4, 5, 6};

とすることもできます。
 また、Cでは改行を自由に使ってよいことを利用して

int a[3][2] = {{1, 2},
                 {3, 4},
                 {5, 6}};

などと書く人もいます。まあ、いずれにしても、「わかりやすく書く」ということが大事だと思います。

 また、for文では、処理が1行なら中カッコをはずしてもよいという話をしました。hairetu.cの2重ループは、

    for(i = 0; i < 3; i++)
        for(j = 0; j < 2; j++)
            printf("a[%d][%d] = %d ", i, j, a[i][j]);

と書くこともできるのです。外側のfor文に対して、内側のfor文は「1行」と考えられるからです。このような書き方は、好む人、嫌う人、いろいろです。

 多次元配列は、配列の配列と考えることができます。たとえば、上の例の場合、

a[0]、a[1]、a[2]

が、それぞれ(1次元の)配列を表していると考えられるのです。つまり、

a[0]の要素:a[0][0]、a[0][1]
a[1]の要素:a[1][0]、a[1][1]
a[2]の要素:a[2][0]、a[2][1]

ということです。よく考えてみると、合理的ですね。


 配列は、「同じ種類のもの」をまとめておくのに便利ですが、「違う種類のもの」をまとめておくには、構造体というものが便利です。これは、ちょっとわかりにくいものですが、例を見て考えるようにしてください。
 たとえば、Manという構造体を、次のように、定義し、使うことができます。

struct Man
{
    int num;
    char name[51];
};

 これは、numというint型変数とnameというchar配列を持った「もの」の「設計図」です。この構造体を使うには、次のようにします。

struct Man m;

 これで、Manという構造体(「設計図」)の「実体」ができ、それがmで表されることになるのです。このとき、mの中には、numとnameがあり、それぞれm.num、m.nameと表されます。たとえば、あまり意味はありませんが、次のようなプログラムが書けます。

/* kouzoutai.c */
#include <stdio.h>

struct Man
{
    int num;
    char name[51];
};


int main(void)
{
    struct Man m;
    printf("Manの実体mを作りました。\n");
    printf("mに番号をあげます。\n");
    printf("好きな数字を入力してください。\n");
    scanf("%d", &m.num);
    printf("今度は、mに名前をあげます。\n");
    printf("好きな名前を入力してください。\n");
    scanf("%s", m.name);
    printf("ありがとう。\n");
    printf("mのnumは%d、mのnameは%sになりました。", m.num, m.name);
    return 0;
}

Fig.2 kouzoutai.exe

 

 構造体は、関係のあるデータを一まとめにしておくのに使えるのです。たとえば、上のManは、「社員番号と名前」をまとめる構造体のつもりです。
 ところで、「struct Man m;」のように、毎回structを書くのが面倒と思えることもあります。Manを別のところで使う予定がないなら、Manの定義と同時に、その変数を定義することもできます。

struct Man
{
    int num;
    char name[51];
} m;

 これで、構造体Manが定義され、と同時に、その変数mも定義されるのです。

 しかし、Manをいろいろなところで使いたい場合、やはり、そのつど「struct Man m;」のように書かなければなりません。その場合、typedefというものを使って、簡単にすることもできます。

typedef struct Man SMan;

と書くと、SManが「struct Man」を表すようになるのです。これで、「struct Man」とあればそれは「SMan」のことである...という意味になるのです。これは名前の問題なので、Manの定義そのものには関係ありません。そのため、Manの定義の前に書いてもかまいません。こうすると、以後では、

struct Man m;

などのかわりに、

SMan m;

などと書くことができるのです。つまり、structを書かなくてよくなっただけ、すこーし、楽になるのです。
 実は、また、

typedef struct Man SMan;
struct Man
{
    int num;
    char name[51];
};

と同じ意味のことを、一度に、

typedef struct Man
{
    int num;
    char name[51];
} SMan;

と書くこともできます。ちょっとややこしいですが、これで、「numとnameを持つ構造体Manが定義され、同時にSManがManの別名」になるのです。しかし、こう書くと、もうManが必要なくなりますね。というのは、あとはいつでも「SMan m;」のように書けばよくなるからです。
 もう、Manという名前を使わないなら、上のコードからManを削除してもかまいません。つまり、上のコードを

typedef struct
{
    int num;
    char name[51];
} SMan;

と書いてもよいようになっているのです。ちょっとサンプルを書いてみましょう。

/* kouzoutai2.c */
#include <stdio.h>

typedef struct
{
    int num;
    char name[51];
} SMan;

int main(void)
{
    SMan m;
    printf("Manの実体mを作りました。\n");
    printf("mに番号をあげます。\n");
    printf("好きな数字を入力してください。\n");
    scanf("%d", &m.num);
    printf("今度は、mに名前をあげます。\n");
    printf("好きな名前を入力してください。\n");
    scanf("%s", m.name);
    printf("ありがとう。\n");
    printf("mのnumは%d、mのnameは%sになりました。", m.num, m.name);
    return 0;
}

 これは、kouzoutai.cと同じ動作をします。

 たとえば、構造体の配列を作れば、名簿プログラムが作れそうですね。実際の名簿プログラムは次回考えることにして、ここでは、簡単な例をお見せしましょう。

/* kouzoutai3.c */
#include <stdio.h>

typedef struct
{
    int num;
    char name[51];
} SMan;


int main(void)
{
    int i;
    SMan m[5];
    printf("社員5人分のデータを入力してください。\n");
    for(i = 0; i < 5; i++){
        printf("社員番号:");
        scanf("%d", &m[i].num);
        printf("氏名  :");
        scanf("%s", m[i].name);
    }
    printf("全員のデータを出力します。\n");
    for(i = 0; i < 5; i++){
        printf("%d:%s\n", m[i].num, m[i].name);
    }
    return 0;
}

Fig.3 kouzoutai3.c


 構造体とその変数について、基本的な書き方は上で紹介したものです。しかし、初期化などで「ちょっと楽に書く方法」はいろいろあります。これは、そういう例に出くわしたときに、覚えるようにしてください。


C入門目次

前のページ  後のページ