4. 構造体 4.1 構造体とは たとえば 分数をそのまま扱うときを考えてみましょう 分数は分子と分母の 2 つの部分からな っていることから 2 つの変数を用いて表すことが必要です ここでは約分も行うこととします ex34.c /* 分数の計算 */ int gcd(int m, int n); int a_num, a_den; /* 分数 a */ int b_num, b_den; /* 分数 b */ int c_num, c_den; /* 分数 c */ int x; /* 分子 : numerator 分母 : denominator */ printf("2 つの分数の値を入力してください :\n"); printf("1 つめ \n"); printf(" 分子 : "); scanf("%d", &a_num); printf(" 分母 : "); scanf("%d", &a_den); printf("2 つめ \n"); printf(" 分子 : "); scanf("%d", &b_num); printf(" 分母 : "); scanf("%d", &b_den); c_num = a_num * b_num; /* 分子の計算 */ c_den = a_den * b_den; /* 分母の計算 */ x = gcd(c_num, c_den); c_num = c_num / x; c_den = c_den / x; printf("%d / %d * %d / %d = %d / %d\n", a_num, a_den, b_num, b_den, c_num, c_den); return (0); /* ユークリッドの互除法により最大公約数を求める関数 */ int gcd(int m, int n) { /* 引数は 2 つでどちらも整数 戻り値は整数 */ int r; for(r = m % n; r!= 0; r = m % n) { m = n; n = r; return (n); 分子と分母の 2 つに分けて考えなければなりません また 変数自体も 2 つのものを同時に扱わな ければならず面倒です このようにいくつかの型をあわせて一つにまとめて使う必要があるときには構造体といわれるものを使うと楽になります 25
ex35.c /* 構造体を用いた分数 */ 応用プログラミング I II 2014.12.15 /* 分数の構造体 */ struct fraction { int num; /* 分子 */ int den; /* 分母 */ ; int gcd(int m, int n); struct fraction a, b, c; /* 分数 a, b, c */ int x; printf("2 つの分数の値を入力してください :\n"); printf("1 つめ \n"); printf(" 分子 : "); scanf("%d", &a.num); printf(" 分母 : "); scanf("%d", &a.den); printf("2 つめ \n"); printf(" 分子 : "); scanf("%d", &b.num); printf(" 分母 : "); scanf("%d", &b.den); c.num = a.num * b.num; /* 分子の計算 */ c.den = a.den * b.den; /* 分母の計算 */ x = gcd(c.num, c.den); c.num = c.num / x; c.den = c.den / x; printf("%d / %d * %d / %d = %d / %d\n", a.num, a.den, b.num, b.den, c.num, c.den); return (0); /* ユークリッドの互除法により最大公約数を求める関数 */ int gcd(int m, int n) { /* 引数は 2 つでどちらも整数 戻り値は整数 */ int r; for(r = m % n; r!= 0; r = m % n) { m = n; n = r; return (n); このように構造体を使えば 複数の変数をまとめて一つとして宣言でき 使うことができます 26
構造体を宣言するときには次のようにします struct 構造体名 { 型 1 メンバ変数 1;... ( 同時に変数宣言するときにはここに変数名を書く ); その構造体を用いた変数を定義するときには次のようにします struct 構造体名変数名 ; 4.2 構造体と関数 このままでは 構造体の良さがあまり見えません 構造体は分子 分母を合わせて一つにしているのですので 関数と組み合わせれば プログラムがわかりやすくなります ex36.c /* 構造体を用いた分数 */ /* 分数の構造体 */ struct fraction { int num; /* 分子 */ int den; /* 分母 */ ; struct fraction input_fraction(void); struct fraction mul(struct fraction x, struct fraction y); void print_fraction(struct fraction x); int gcd(int m, int n); struct fraction a, b, c; /* 分数 a, b, c */ printf("2 つの分数の値を入力してください :\n"); printf("1 つめ \n"); a = input_fraction(); printf("2 つめ \n"); b = input_fraction(); c = mul(a, b); print_fraction(a); printf(" * "); print_fraction(b); printf(" = "); print_fraction(c); printf("\n"); return (0); struct fraction input_fraction(void) { struct fraction x; printf(" 分子 : "); scanf("%d", &x.num); printf(" 分母 : "); scanf("%d", &x.den); return(x); 27
struct fraction mul(struct fraction x, struct fraction y) { struct fraction z; int g; z.num = x.num * y.num; /* 分子の計算 */ z.den = x.den * y.den; /* 分母の計算 */ g = gcd(z.num, z.den); z.num = z.num / g; z.den = z.den / g; return(z); void print_fraction(struct fraction x) { printf("%d / %d", x.num, x.den); /* ユークリッドの互除法により最大公約数を求める関数 */ int gcd(int m, int n) { /* 引数は 2 つでどちらも整数 戻り値は整数 */ int r; for(r = m % n; r!= 0; r = m % n) { m = n; n = r; return (n); このように構造体を使えば c = a のような代入もできますし 関数の戻り値として使うこともで きます これによって 本来 2 つの実数であったものを 1 つのもののように扱えるというわけです 構造体はこのように複数のものを 1 つにまとめることができるのです 複素数の例では 2 変数と も int 型でしたが 違う型のものを組み合わせてもかまいません 練習問題 4.1 ex36.c を参考に 和の計算を行う関数 (add) を完成させなさい ただし きちんと約分される ようにしなさい ex37.c /* 構造体を用いた分数の和の関数 */ /* 分数の構造体 */ struct fraction { int num; /* 分子 */ int den; /* 分母 */ ; struct fraction input_fraction(void); struct fraction add( ); void print_fraction(struct fraction x); int gcd(int m, int n); 28
struct fraction a, b, c; /* 分数 a, b, c */ printf("2 つの分数の値を入力してください :\n"); printf("1 つめ \n"); a = input_fraction(); printf("2 つめ \n"); b = input_fraction(); c = add(a, b); print_fraction(a); printf(" + "); print_fraction(b); printf(" = "); print_fraction(c); printf("\n"); 応用プログラミング I II 2014.12.15 return (0); struct fraction input_fraction(void) { struct fraction x; printf(" 分子 : "); scanf("%d", &x.num); printf(" 分母 : "); scanf("%d", &x.den); return(x); struct fraction add( ) { void print_fraction(struct fraction x) { printf("%d / %d", x.num, x.den); /* ユークリッドの互除法により最大公約数を求める関数 */ int gcd(int m, int n) { /* 引数は 2 つでどちらも整数 戻り値は整数 */ int r; for(r = m % n; r!= 0; r = m % n) { m = n; n = r; return (n); 29
4.3 構造体と配列 応用プログラミング I II 2014.12.15 構造体のメンバーに配列を持たせることもできますし 構造体の配列を作ることもできます 次 の例では成績管理用の構造体を作っていますが 学籍番号は文字列なので文字型の配列になっています ex38.c /* 成績表 */ #include <stdlib.h> /* 成績管理用の構造体の定義 */ struct student { char idnumber[8]; /* 学籍番号 */ int math; /* 点数 ( 数学 ) */ int eng; /* 点数 ( 英語 ) */ int jpn; /* 点数 ( 国語 ) */ ; /* プロトタイプ宣言 */ struct student input_student(void); void print_student(struct student x); struct student data; /* 配列 */ data = input_student(); print_student(data); return(0); /* 入力用関数 */ struct student input_student(void) { struct student x; printf(" 学籍番号 : "); scanf("%7s", x.idnumber); printf(" 数学 : "); scanf("%d", &x.math); printf(" 英語 : "); scanf("%d", &x.eng); printf(" 国語 : "); scanf("%d", &x.jpn); return(x); /* 表示用関数 */ void print_student(struct student x) { printf("%10s: %3d %3d %3d\n", x.idnumber, x.math, x.eng, x.jpn); 30
さらに この構造体を利用して 複数人数を扱うことにします 複数並べるためには 構造体の配列が必要になります 配列を含んだ構造体の配列 なので複雑に見えるかもしれません 今回は 数学の得点が高い順に並び替えを行っています 構造体の配列なので メンバにアクセスするには [ ] のあとに. メンバ名 をつけることになります ex39.c /* 成績表 */ #include <stdlib.h> #define MAX 100 /* 最大人数 */ /* 成績管理用の構造体の定義 */ struct student { char idnumber[8]; /* 学籍番号 */ int math; /* 点数 ( 数学 ) */ int eng; /* 点数 ( 英語 ) */ int jpn; /* 点数 ( 国語 ) */ ; /* プロトタイプ宣言 */ void input_students(struct student x[], int len); void print_students(struct student x[], int len); struct student data[max]; /* 配列 */ int numstudent; /* 人数 */ printf(" 人数を入力してください (1-%d): ", MAX); scanf("%d", &numstudent); input_students(data, numstudent); /* データの入力 */ printf("\n\n 入力結果 :\n"); print_students(data, numstudent); /* データの出力 */ return(0); /* 入力用関数 */ void input_students(struct student x[], int len) { int i; for(i = 0; i < len; i++) { printf("%d 人目 :\n", i + 1); printf(" 学籍番号 : "); scanf("%7s", x[i].idnumber); printf(" 数学 : "); scanf("%d", &x[i].math); printf(" 英語 : "); scanf("%d", &x[i].eng); printf(" 国語 : "); scanf("%d", &x[i].jpn); 31
/* 表示用関数 */ void print_students(struct student x[], int len) { int i; for(i = 0; i < len; i++) { printf("%10s: %3d %3d %3d\n", x[i].idnumber, x[i].math, x[i].eng, x[i].jpn); 練習問題 4.2(ex40.c) ex39.c の構造体 student に 平均点 を表すメンバを追加し input_student 関数内で平 均点を計算し print_student 関数内で平均点も出力するように変更しなさい 32