2021 年度「計算数学b」 2022-01-12

§12 構造体

「構造体」という名前はいかめしいが,英語では structure である。 ひとつの変数に複数の要素がある場合に用いる。 たとえば,一つの複素数が実部と虚部からなるように。

#include <stdio.h>

struct Complex {  /* Complex 型の構造体の定義 */
  double re;
  double im;
};                /* このセミコロンを忘れやすい! */

struct Complex new(double re, double im);
struct Complex add(struct Complex z, struct Complex w);
int isequal(struct Complex z1, struct Complex z2);
void print(struct Complex z);

int main() {
  struct Complex z, w;    /* 構造体 struct Complex 型変数の宣言 */

  z.re = 1; z.im = 2;     /* ひとつの計算例 */
  w.re = 1; w.im = 3;

  print(z);
  printf(" + ");
  print(w);
  printf(" = ");
  print(add(z, w));
  printf(".\n");

  if (isequal(z, w) == 1) {     /* 別の例 */
    printf("等しい.\n");
  } else {
    printf("等しくない.\n");
  }

  print(add(new(-1, 3), new(-3, 4)));   /* こんな書き方もできる */
} 


/* 実部 re, 虚部 im の Complex 型変数を返す */
struct Complex new(double re, double im) {
  struct Complex r;

  r.re = re; r.im = im;

  return r;
}


/* 和を返す */
struct Complex add(struct Complex z, struct Complex w) {
  struct Complex r;

  r.re = z.re + w.re;
  r.im = z.im + w.im;

  return r;
}


/* 等しければ 1 を、そうでなければ 0 を返す */
int isequal(struct Complex z1, struct Complex z2) {
  if (z1.re == z2.re && z1.im == z2.im) {
    return 1;
  } else {
    return 0;
  }
}


/* 画面出力 */
void print(struct Complex z) {
  printf("(%f + %f i)", z.re, z.im);
}

Complex 型の構造体の定義」の部分。 struct は必ずこう書く。 次の Complex は,“複素数型”を作りたいので, 複素数にちなんでこの名前を選んだ。 C 言語では変数は小文字,定数は大文字である。 ここではその中間の,頭文字だけ大文字,を選んだ。 これが便利なようである。 こうすると「struct Complex」が intdouble と同じように使える。

この構造体は,実部 re と虚部 im, 二つの double 型変数からなる。 最後の行で,閉じ中カッコのあとにセミコロンがつくのを忘れないように。 forif では閉じ中カッコのあとにセミコロンはつかないのだった。

これで,main() 関数の中の「構造体 struct Complex 型変数の宣言」が理解できたであろう。 zw はこの型の変数である。

(ここで注意。構造体の定義と,その構造体型の変数の宣言を混同してはならない。 前者は,これから,そういう型を使いますよ,というもの, 後者はその型の変数の宣言である。 前者を,ベルギーワッフルの型を作ったのだと思うと理解しやすいかもしれない。 後者は,その型で焼いたベルギーワッフルである。 この比喩はとある本から借用した。)

構造体の成分を利用するには,z.re のようにする。 zstruct Complex 型の変数であり, その re 成分を表すのにはこのようにするのである。 これで、関数 add()print() はわかったであろう。 関数 isequal() は、if (z1 == z2) と書けないので、 その代わりをさせるために作ったものである。

関数 new() は、実部と虚部の値を与えると struct Complex 型変数を返すもので、 名前は C++ 言語を(不器用に)まねてみたものである。

興味のあるものは、引き算 sub(), 掛け算 mul(), 割り算 div() などを実装してみよ。

変数 z, w1, w2struct Complex 型だとして、 z = w1 + w2; のように書けたら便利だが、そうは書けない。 struct Complex 型の変数の間の加法は定義されていないからである。 C 言語のあとから開発された C++ 言語ではこれができるそうである。

また、複素数体型は、最近の C コンパイラにはついているようである。

小規模なプログラムでは、構造体を定義せず、 are, bre で a, b の実部、 aim, bim で a, b の虚部、として書いたほうが楽かもしれない。 大規模なプログラムになると、まず構造体を定義し、 その構造体に関わる関数 (複素数型の場合は画面出力、加減乗除など) を実装してから始めるほうが効率がよいと聞く。 一度きちんと作った構造体のプログラムは、あとで使いまわしがきく。

発展練習:有理数型 struct Rational を実装してみよ。 英語では、分子は numerator, 分母は denominator という。 成分名は num, denom でどうだろうか。 演算結果は既約分数にしよう。


岩瀬順一