#include <stdio.h>
void complex_add(double are, double aim, double bre, double bim, double *cre, double *cim)
{
*cre = are + bre;
*cim = aim + bim;
}
void complex_mul(double are, double aim, double bre, double bim, double *cre, double *cim)
{
*cre = are * bre - aim * bim;
*cim = are * bim + aim * bre;
}
void complex_print(double are, double aim)
{
printf("(%f)+(%f)i", are, aim);
}
int main(void)
{
double xre, xim, yre, yim, tmpre, tmpim;
scanf("%lf", &xre);
scanf("%lf", &xim);
complex_mul(xre, xim, xre, xim, &tmpre, &tmpim);
complex_add(tmpre, tmpim, xre, xim, &yre, &yim);
complex_print(yre, yim);
printf("\n");
return 0;
}
|
複素数なので、実部 (real part) と虚部 (imaginary part) が必ずペアで 現れていることが分かる。しかし、変数を2つ用意し別々に宣言や受渡しを 行っており、見通しが悪い。 構造体を使うと、両者が一組であるということをより分かりやすく表現する ことが出来る。
#include <stdio.h>
struct complex {
double re;
double im;
};
void complex_add(struct complex a, struct complex b, struct complex *c)
{
(*c).re = a.re + b.re;
(*c).im = a.im + b.im;
}
void complex_mul(struct complex a, struct complex b, struct complex *c)
{
(*c).re = a.re * b.re - a.im * b.im;
(*c).im = a.re * b.im + a.im * b.re;
}
void complex_print(struct complex a)
{
printf("(%f)+(%f)i", a.re, a.im);
}
int main(void)
{
struct complex x, y, tmp;
scanf("%lf", &(x.re));
scanf("%lf", &(x.im));
complex_mul(x, x, &tmp);
complex_add(tmp, x, &y);
complex_print(y);
printf("\n");
return 0;
}
|
また、構造体にすれば「一つの変数」なので戻り値を直接返せるので、 次のようにより簡潔に書くことも出来る。
#include <stdio.h>
struct complex {
double re;
double im;
};
struct complex complex_add(struct complex a, struct complex b)
{
struct complex c;
c.re = a.re + b.re;
c.im = a.im + b.im;
return c;
}
struct complex complex_mul(struct complex a, struct complex b)
{
struct complex c;
c.re = a.re * b.re - a.im * b.im;
c.im = a.re * b.im + a.im * b.re;
return c;
}
void complex_print(struct complex a)
{
printf("(%f)+(%f)i", a.re, a.im);
}
int main(void)
{
struct complex x, y, tmp;
scanf("%lf", &(x.re));
scanf("%lf", &(x.im));
tmp = complex_mul(x, x);
y = complex_add(tmp, x);
complex_print(y);
printf("\n");
return 0;
}
|
以下、これをサンプルとして、構造体の使い方を説明する。
struct タグ名 {
型名 メンバ名;
型名 メンバ名;
...
};
のように書く。例えば、
struct complex {
double re;
double im;
};
のように書ける。異なる型が混在していてもよい。例えば、
struct person {
char name[100];
int age;
double height;
double weight;
};
のように書くことが出来る。構造体の定義は、「タグ名」の構造体がどのような構造を持つかを 定義したに過ぎず、これだけでは実際のメモリ領域は割り当てられていない。
struct タグ名 変数名;のように宣言する。例えば、
struct complex x;と書く。普通の変数と同様に、宣言と同時に初期化することも出来る。例えば、
struct complex x = {1.0, 2.0};
中身を取り出すときは、
変数名.メンバ名のように書く。例えば、x.re、x.imなど。
構造体をポインタで渡すと、
(*x).re
のような記述がどうしても多くなるが、これに関しては、
x->re
のような略記法がある。例えば上の例のcomplex_add関数は、
void complex_add(struct complex a, struct complex b, struct complex *c)
{
c->re = a.re + b.re;
c->im = a.im + b.im;
}
と書いてもよい。
いわゆるsyntax sugar, syntactic sugar (糖衣構文)の一種。
typedef 型名 型の別名;という使い方。例えば、
typedef unsigned int uint;
main()
{
unsigned int a;
uint b;
}
のように使う。uintという名前が、unsigned intの別名として使えるようになる。
これを利用して、構造体に別名を付けて使うことが多いので、例として挙げておく。
#include <stdio.h>
typedef struct {
double re;
double im;
} complex;
complex complex_add(complex a, complex b)
{
complex c;
c.re = a.re + b.re;
c.im = a.im + b.im;
return c;
}
complex complex_mul(complex a, complex b)
{
complex c;
c.re = a.re * b.re - a.im * b.im;
c.im = a.re * b.im + a.im * b.re;
return c;
}
void complex_print(complex a)
{
printf("(%f)+(%f)i", a.re, a.im);
}
int main(void)
{
complex x, y, tmp;
scanf("%lf", &(x.re));
scanf("%lf", &(x.im));
tmp = complex_mul(x, x);
y = complex_add(tmp, x);
complex_print(y);
printf("\n");
return 0;
}
|
つまり、構造体にcomplexという別名を付けることによって、使うときに いちいちstructと書かなくて済むようになる。
先頭の宣言部は本来は
typedef struct complex {
double re;
double im;
} complex;
だが、この場合別名が付けられたことによって構造体を特定するための
タグが不要になるため、タグ名を省略している。