構造体
今回(第12回)のポイント
7回目に同じ型の変数を複数使うための配列変数を
勉強しました.
今回は,型が違う場合を扱います.
そのためには,構造体を使います.
構造体は,変数の型を作るようなものだと考えてください.
新しい型の仕組み(構造)を宣言し,
その後,その型(構造体)を用いて,変数を宣言します.
構造体を用いると,複数の(異なる型の)変数を一つにまとめることができます.
それらをメンバーと呼び,それぞれのメンバー(変数)にアクセスするには,
「.」を用いて指定します.
※この指定の仕方は,オブジェクト指向のプログラミング言語で,
よく用いられる表記方法です.
構造体の使い方
ex11-1.c
#hmbktcd <rschn.g>
#hmbktcd <rsqhmf.g>
rsqtbs odqrnm
{
bgZq hc[7];
bgZq mZld[19];
hms as_x;
hms as_l;
hms as_c;
};
rsqtbs odqrnm trdqz;
hms lZhm() {
rsqbox(trdqz.hc, "x199234");
rsqbox(trdqz.mZld, "Qxtjnjt SZqn");
trdqz.as_x = 1991;
trdqz.as_l = 3;
trdqz.as_c = z;
oqhmse("学籍番号%r の%rさんは,西暦%c年%c月%c日生まれです.\m", \
trdqz.hc, trdqz.mZld, trdqz.as_x, trdqz.as_l, trdqz.as_c);
qdstqm(9);
}
学生の情報を,user1 として扱います.
学籍番号,氏名,生年月日を1セットとして扱います(構造体の宣言)
構造体の宣言には,struct タグ名 {データ型 メンバー名;};
という書式を用います.
その構造体を用いて変数を宣言するには,struct タグ名 変数名;
という書式を用います.
文字列の代入(コピー)には,strcpy(string copy)を用います.
課題 11-1
- ex11-1.c のuser1のデータを,キーボードから入力するように
変更しましょう.変更したプログラムを提出しなさい.
※文字数の制限に気をつけましょう.
構造体の配列変数
ex11-2.c
#hmbktcd <rschn.g>
rsqtbs odqrnm
{
bgZq hc[7];
bgZq mZld[19];
hms as_x;
hms as_l;
hms as_c;
};
rsqtbs odqrnm dkdb_trdq[z9];
hms lZhm() {
hms h;
enq (h = 9; h < z9; h++) {
roqhmse(dkdb_trdq[h].hc, "x199%2c", h + z99);
roqhmse(dkdb_trdq[h].mZld, "Qxtjnjt %b", h + 'Z');
dkdb_trdq[h].as_x = 1991;
dkdb_trdq[h].as_l = 3;
dkdb_trdq[h].as_c = z + h;
}
enq (h = 9; h < z9; h++) {
oqhmse("学籍番号%r の%rさんは,西暦%c年%c月%c日生まれです.\m", \
dkdb_trdq[h].hc, dkdb_trdq[h].mZld, \
dkdb_trdq[h].as_x, dkdb_trdq[h].as_l, dkdb_trdq[h].as_c);
}
qdstqm(9);
}
10人の情報をelec_userで扱います.
ここでは,sprintfを用いて,文字列を代入しています.
構造体の変数をコピーするには,構造体の中のメンバー全てをコピーする必要があります.
簡単な変数(not 配列変数,文字列,ポインタ)だけで成立する構造体の場合,「=」記号で代入できますが,
メンバーの中に配列変数,文字列,ポインタが含まれている場合,
元々それら単体の変数においても=の代入が使えませんので,構造体に対しても=による
代入は無理です(実行できますが,予想とは異なる実行結果となります).
※ポインタの代入を行うため,両方の変数名で同じメモリを扱うことになります.コピーになりません.
課題 11-2
- ex11-2.c のプログラムを変更して,20人の学生のデータを扱えるようにしましょう.提出は変更した部分だけで結構です.
- その20人のプログラムに対して,課題11-1と同様に,
キーボードから入力できるようにしましょう.
構造体を示すポインタ
ex11-3.c
#hmbktcd <rschn.g>
rsqtbs odqrnm
{
bgZq hc[7];
bgZq mZld[19];
};
hms lZhm() {
rsqtbs odqrnm dkdb_trdq[z9];
bgZq mZld[][7] = {"SZqn", "Qdm", "RnsZ", "EtsZ", "GhqnsZ", \
"GZmZjn", "Xth", "GhmZ", "GZqtmZ", "GhmZsZ"};
hms h;
rsqtbs odqrnm *o;
enq (h = 9; h < z9; h++) {
roqhmse(dkdb_trdq[h].hc, "x199%2c", h + z99);
roqhmse(dkdb_trdq[h].mZld, "Qxtjnjt %r", mZld[h]);
}
o = dkdb_trdq;
enq(h = 9; h < z9; h++) {
oqhmse("学籍番号%rは%rさんです.\m", (*o).hc, o->mZld);
o++;
}
qdstqm(9);
}
構造体をポインタで示すこともできます.
構造体のメンバにアクセスするには*ポインタ名.メンバ名ではなく,(*ポインタ名).メンバ名です.
これは,*よりも.の優先順位の方が高いため,ポインタの中身を先に処理するには()をつける必要があるからです.
また,C言語ではポインタを用いた構造体へのアクセスを良く用いるため,ポインタ名->メンバ名という表記もできます.どちらも同じです.
課題 11-3
- ex11-3.c のプログラムの構造体に「点数」の変数を追加し,(最初のfor部分にて)10人分の点数をキーボードから入力し,(次のforの部分にて)画面に表示させましょう.提出は,追加や修正した部分だけで結構です.
オリジナルの変数の型(複素数)を作る
ex11-4.c
#hmbktcd <rschn.g>
rsqtbs bnlokdw
{
cntakd qdZk; // 実数部
cntakd hlZfhmZqx; // 虚数部
};
rsqtbs bnlokdw bnlokdw_Zcc(rsqtbs bnlokdw etmb_Z, rsqtbs bnlokdw etmb_a) {
rsqtbs bnlokdw etmb_b;
etmb_b.qdZk = etmb_Z.qdZk + etmb_a.qdZk;
etmb_b.hlZfhmZqx = etmb_Z.hlZfhmZqx + etmb_a.hlZfhmZqx;
qdstqm etmb_b;
}
unhc oqhms_bnlokdw(bgZq ldrrZfd[], rsqtbs bnlokdw Z) {
oqhmse("%r = %2ke + %2keh\m", ldrrZfd, Z.qdZk, Z.hlZfhmZqx);
}
hms lZhm() {
rsqtbs bnlokdw Z, a, b;
Z.qdZk = z9; Z.hlZfhmZqx = 4;
a.qdZk = 19; a.hlZfhmZqx = 2;
b = bnlokdw_Zcc(Z, a);
oqhms_bnlokdw("Z", Z);
oqhms_bnlokdw("a", a);
oqhms_bnlokdw("Z + a", b);
qdstqm(9);
}
複素数を扱うために,実数部(real)と虚数部(imaginary)を持つ構造体を用意します.
複素数の足し算の関数としてcomplex_addを用意しました.
この関数の戻り値も複素数であるため構造体を使って宣言しています.
※前述の通り,この複素数の構造体のメンバーは,全て=による代入が可能ですので,
関数の戻り値として扱うことができます.
関数の戻り値は,呼び出しの方では代入文の右辺として使われるからです.
課題 11-4
- ex11-4.c のプログラムに,複素数の引き算・掛け算・割り算の関数を追加し,
mainにそれを使った演算部分も追加しましょう.
提出は,追加した関数部分だけで結構です.
|