第 7 回 構造体

本日の内容


このドキュメントは http://edu.net.c.dendai.ac.jp/ 上で公開されています。

7-1. 構造体

構造体の基礎

座標のように、複数の値を一つのものとして扱いたい場合があります。 C 言語では構造体という仕組みで扱うことができます。 まず、構造体の型の名前を宣言し、その型のメンバー変数を宣言します。 型を宣言するには struct 宣言 をします。 struct の後に、構造体の名前を指定し、その後にメンバーの宣言のブロック({} で括られたもの)が来て、最後にセミコロン(;)で終了します。 メンバーの宣言は変数宣言と同じ形になりますが、変数が宣言されるわけでは ないことに注意が必要です。 例えば座標の構造体の型は次のように宣言されます。これは変数宣言ではなく、 型の宣言です。 従ってこれだけで変数が使用できるわけではありません。


struct point {
  double x; 
  double y;
};

このようにすると point という構造体の型だけが作られます。 point は構造体の型であって、変数ではありません。 point 型の変数 p と q を宣言するには次のようにします。


struct point p,q;

これで p と q という point 型の変数ができました。 宣言した変数は次のように使います。

各項目をアクセスするには

p.x=1.0;
printf("%f\n",p.y);
このように変数名の後にピリオドをつけ、その後にメンバ 名をつけます。 こうすると通常の変数と同様に使用することができます。 この場合、型はメンバを宣言した型になります。
構造体の変数から変数へ代入するには

q=p;
printf("%f\n",q.x);
同じ型であれば単なる代入文で全てのメンバの値がコピーされます。
配列変数のように、宣言時には一括して初期化

struct point p={1.0,2.0};
/* p という変数が作られ、 p.x に 1.0, p.y に 2.0 が代入される */
但し、プログラム実行中はできない。

なお、二つの構造体の変数が一致しているかどうかは == で調べられませんの で、一つ一つ要素を比べるしかありません。

typedef

構造体 A という型を宣言しても、変数宣言は struct A x; と struct を書く必要があります。 (C++ ではちゃんと A x; と書けますが……) そのため、 struct を書かなくて済むように typedef という宣言があります。


typedef struct point {
  double x; 
  double y;
} POINT;

と宣言すると、この宣言以降、 struct point の代わりに POINT と書けば済 むようになります。 変数宣言は次のようになります。


POINT p,q;
/* point 型の変数 p と q が宣言される */
POINT r={1.0,2.0};
/* point 型の変数 r が宣言され、 r.x に 1.0, r.y に 2.0 が代入される。 */

なお、複数のファイルで構造体を使う場合、ファイル毎に構造体の宣言がそれ ぞれ必要です。 そのため、構造体の宣言はヘッダファイルに入れると便利です。

構造体のポインタ

構造体のポインタの宣言は通常のポインタと同様です。


POINT *p;
POINT q={1.0,2.0};

q の番地を p に入れるのも同様です。


p=&q;

但し、p の指す構造体の要素をアクセスする場合、 (*p).x と も書けますが、これを p->x と書くこともできます。

構造体の配列

構造体の配列の取り扱いは、通常の配列の取り扱いと同様です。


POINT p[5];
int i;
for(i=0; i<5 ; i++){
  p[i].x=0.0;
  p[i].y=1.0;
}

関数とのやりとり

構造体は普通の変数と同様に関数と値をやりとりできます。 つまり、特にポインタなどを使用しなくてもよいということです。

---------------p.h----------------

typedef struct p {
    int x;
    int y;
} POINT;
POINT sub(POINT p);

---------------sub.c--------------

#include "p.h"
POINT sub(POINT p){
  p.x--;
  p.y++;
  return p;
}

---------------main.c-------------
#include <stdio.h>
#include "p.h"
int main(void){
  POINT p={1,2},q;
  q=sub(p);
  printf("%d\n%d\n",p.x,p.y);
  printf("%d\n%d\n",q.x,q.y);
  return 0;
}

7-2. 演習

構造体 POINT を次のように定義します。


typedef struct point {
  double x;
  double y;
} POINT;

演習7-1

POINT 型の引数をもらい、原点からの距離を double 型で返す関数 distance を作りなさい。 そして、以下の main 関数によりその関数をテストしなさい。

----point.h----

typedef struct point {
  double x;
  double y;
} POINT;
double distance(POINT p);

----main.c----
#include <stdio.h>
#include "point.h"
int main(void){
  POINT p={3.0,4.0};
  printf("点 %f, %f と原点の距離は %f です。\n",p.x,p.y,distance(p));
  return 0;
}

----distance.c----

#include "point.h"
double distance(POINT p){
/* この部分を書く (必要ならヘッダファイルを追加する)*/
}

演習7-2

POINT 型のポインタを引数とし、その引数の x 座標、y 座標とも 1/2 にする 関数 void halve(POINT *p)を作りなさい。 そして、以下の main 関数によりその関数をテストしなさい。

----point.h----

typedef struct point {
  double x;
  double y;
} POINT;
void halve(POINT *p);

----main.c----
#include <stdio.h>
#include "point.h"
int main(void){
  POINT p={6.0,8.0};
  printf("最初の点は %f, %f です。",p.x,p.y);
  halve(&p);
  printf("半分の位置は %f, %f です。",p.x,p.y);
  return 0;
}

----halve.c----

#include "point.h"
void halve(POINT *p){
/* この部分を書く */
}


坂本直志 <sakamoto@c.dendai.ac.jp>
東京電機大学工学部情報通信工学科