構造体

C言語勉強会 第八回

Mrtanaka

Jun. 12, 2013

構造体とは

例えば

普通に1つ1つ変数宣言をすると

char name1[20];
int height1;
double vision1;
char name2[20]; …

配列でまとめて変数宣言をすると

char name[10][20];
int height[10];
double vision[10];

構造体の宣言方法

構造体を利用することで、これらの情報を「生徒Aの身長」、「生徒Bの視力」といった感じに 関連付けて管理できるようになる。

typedef struct{
  要素(メンバ)の宣言;
  要素(メンバ)の宣言; …
}新しく定義したい型の名前

例)

typedef struct{
  char name[20];
  int height;
  double vision;
}STUDENT;

STUDENT a,b,c;

メンバの参照・利用方法

構造体は複数の異なる型の変数を持つ場合が多いので、a = 3;などといった直接的な代入式は用いることができない。
そのため、各メンバ1つ1つに対して式を書くことが必要となる。

例) 前のページのSTUDENT型の変数aに対して代入、参照を行う場合

a.name = "Mrtanaka";
a.height = 172;
a.vision = 0.01;

printf("%s : height = %dcm, vision = %f\n", a.name, a.height, a.vision);

構造体の初期化

構造体の変数を宣言する時に、次のように記述することで宣言と同時に初期化を行うことも可能である。

構造型名 構造体の変数名 = { 1つ目のメンバの初期値 , 2つ目のメンバの初期値 , … };

例) STUDENT型の変数aを宣言・初期化する場合

STUDENT a = {"Mrtanaka", 172, 0.01};

構造体のコピー

同じ構造体同士で代入式を書くと、構造体内のメンバの値を全てコピーすることができる。(例え配列でもうまくコピーしてくれる。)

例) STUDENT型の変数bを変数aにコピーする場合

a = b;

構造体を利用した関数

構造体は他の変数型と同じように扱えるため、関数の引数や戻り値に設定することが可能である。

例) 引数にSTUDENT型を渡すと、身長(height)を10加算させる関数

STUDENT add_height(STUDENT a){
  a.height += 10;
  /* a.height = a.height + 10; と同じ意味 */

  return a;
}

例) 上のadd_height関数を使う場合

STUDENT a = {"Mrtanaka", 172, 0.01};
STUDENT b;

b = add_height(a);

おまけ

構造体宣言

実は今までのページで説明した構造体の宣言はただの構造体宣言ではない。
構造体宣言にtypedefと呼ばれる命令を組み合わせたものである。

何故そんなものを先に紹介したのかというと、

からだ。

だが、構造体を真に理解するべく、これより、typedefと、ただの構造体宣言を紹介する。

typedef

データ型に新しい名前(別名)をつける。

文法

typedef (既存の)データ型 新しい名前
または
(既存の)データ型 typedef 新しい名前

例えば、int に自分の好きな別名をつけるには、

typedef int Seisu;

このように書く。この例では int に Seisu という別名をつけた。なので以降、以下のように書くことで int 型変数 n を宣言できる。

Seisu n;

タグ名を使った構造体宣言

struct タグ名 {メンバ1, メンバ2, ...};

という形で宣言する。タグ名は、新しく構造体として定義した型を識別するための名前である。

そして、宣言した構造体型の変数を宣言するには、

struct タグ名 変数名

とかく。

#include <stdio.h>

struct HUMAN {
    char name[20];
    double height;
    double weight;
};

int main(void) {
    struct HUMAN boku = {
        "Tanaka Taro",
        175.2,
        63.7
    };
    printf("ぼくの名前は%s。身長%.1fcmで体重%.1fcmなヤングマンだぜ!\n",
        boku.name, boku.height, boku.weight);
    return 0;
}

タグを作らず直接、構造体変数を宣言する

struct {メンバ1, メンバ2, ...} 変数名;

という形で直接、構造体変数を宣言できる。

#include <stdio.h>

int main(void) {
    struct {
        int x;
        int y;
    } point1;

    point1.x = 100;
    point1.y = 120;
    printf("(%d, %d)", point1.x, point1.y);
    return 0;
}

真の構造体宣言の文法

簡単のため省略してきたが、本当に正しい構造体宣言の文法は以下のとおりだ。

文法

struct [タグ名] {
    メンバ1,
    メンバ2,
    ...
} [変数名];

// []内は省略可

タグ名を作り、構造体変数も同時に宣言する。

struct Point2d {
    double x;
    double y;
} p1;

struct Point2d p2;

タグ名を作らず、構造体変数も作らない。

struct {
    double x;
    double y;
};

typedef + 構造体 = とても便利

typedef」と「タグ名を作らず、構造体変数も作らない方法」を組み合わせ、構造体に別名を付けるのが、今まで説明したよくある便利な構造体宣言の方法である。

typedef データ型 新しい名前

struct {メンバ1, メンバ2, ...}

typedef struct {メンバ1, メンバ2, ...} 新しい名前

typedef struct {
    メンバ1,
    メンバ2,
    ...
} 新しい名前;

これで、typedefと組み合わせた構造体宣言の仕組みがわかったはずだ。

構造体の比較

用意されていないので、自分で各メンバーを比較する必要がある。

typedef struct {
    int x;
    int y;
} POINT;

POINT a, b;

/* if ( a == b )                   駄目 */
if ( a.x == b.x && a.y == b.y ) /* OK */
    return 1;

return 0;

次回

変数について色々細かい話します。