Lecture 12 構造体と共用体

Assignment(課題)12

【課題提出における注意】
  • すべてのプログラムは,必ずコンパイル&実行し,正しく機能することをチェックしてから提出すること.
  • プログラムは正しくインデントさせること.


    1. 三次元ベクトルを表す事が可能な構造体 Vector3D を定義し, 2つのベクトルの内積を求める関数
        float dot(Vector3D&, Vector3D&);
      および 外積を求める関数
        Vector3D cross(Vector3D&, Vector3D&);
      をそれぞれ作成し,これらを用いてキーボードより入力した2つのベクトルの内外積を 求めて表示するプログラムを作成しなさい. プログラム名を学籍番号10桁-12-1.cppとする.

      出力例

      内積:nnnn
      外積:xxxx, yyyy, zzzzz
      

      解答例 A12-1


      ヒントと解説

      • この様に,構造体を用いると,ベクトルのような複雑なデータを 扱うプログラムも非常にわかりやすく書くことができる.
      • 配列を用いた方法に比べて,変数名に名前をつけられることも, わかりやすいプログラムにすることに貢献している.
      • 関数の引数に&をつけてもつなくても問題なく動く.
      • &をつけると参照型となり, 関数呼び出し時に引数のアドレスがコピーされる. 32ビットのコンパイラの場合,アドレスは32ビットなので, 引数ひとつあたり4バイトのコピーが行われる. &をつけないと値渡しとなり,Vector3Dがまるごとコピーされる. 中身をdouble 3つで構成すれば,24バイトのコピーが起こるので, 参照渡しのなんと6倍の分量のコピーが必要になる.
      • 外積の返り値を参照にすることはできない.関数を抜けると, その中で作られた実態が破壊されるので,参照が意味をなさなくなる ためである(多くの場合コンパイルエラーとなるようだ).



    2. ファイル【3d_points.csv】 には個数不明の3次元座標点が記述されている.但し最大個数は104以下とする. これらの重心座標を計算し表示するプログラムを作成せよ. また,座標点の個数も併せて表示すること. 三次元点のハンドリングには,問題1で作成した Vector3D型を用いよ. 参考にファイル中の三次元点をプロットした図を示す. プログラム名を学籍番号10桁-12-2.cppとする.

      出力例

      データ点数:nnnn
      重心位置は:xxxx, yyyy, zzzzz
      
      図 3d_points.csvの中身の三次元プロット

      解答例 A12-2


      ヒントと解説

      • 配列を作らず,ファイルからデータをひとつ読み出す度に積算計算をしてもよいが, 読み込みは配列にすべて格納し,その後平均を求めた方がプログラムが簡単になる.
      • データファイルは数字のみのCSV形式なので,fscanf() を使って "%lf,%lf,%lf" で読める.




    3. 5人分の名前(char型),身長[cm](float型),体重[kg](float型)の順に記述された ファイル【health_data.csv】 を読み込み,以下の要件を満たすプログラムを作成しなさい.
      • 名前,身長,体重,BMI指数を格納することのできる構造体HealthDataを作成する.
      • 読み込んだ値を用いてそれぞれのBMI指数を計算した後作成した構造体に格納する.
      • 「名前,身長,体重,BMI指数」の順番で各生徒のデータを書き出す.
      プログラム名を学籍番号10桁-12-3.cppとする.

      実行例

      Name    Height Weight BMI
      Aida    170.6  70.7   24.3 
      Iijima  158.3  90.9   36.3 
      Uehara  167.8  64.0   22.7 
      Eguchi  193.1  50.2   13.5 
      Ono     173.4  70.6   23.5
      

      解答例 A12-3


      ヒントと解説

      • 特に難しいところは無いと思うが,一点,読み込みの所だけ.
      • 改行後の行の最初は文字列として読むので,前の改行文字も意に反して入力されてしまう. これを避けるため,最後の改行文字を%*cで読み飛ばしている. このやり方ではなくて,最初の文字列の例外にカンマだけでなく, 改行文字も入れればよいのかも知れない.試して見てください.




    4. 上のプログラムに,任意の項目を任意に順(降順,昇順)でソートする関数
        void sort(HealthData* d, char* koumoku, int order);
      を加えよ.ただし,
      • HealthData: このデータを格納できる構造体.引数は配列へのポインタ
      • char* Koumoku: ソートする項目名(Name, Height, Weight, BMIのどれか)
      • int order: 降順:0, 昇順:1
      とする. すべての項目でソートした結果(8通り)を(ソートした項目と順がわかるようにタイトルをつけて)表示せよ. なお,名前はあいうえお順ではなく,ABC順でよい. プログラム名を学籍番号10桁-12-4.cppとする.

      実行例

      名前,昇順
      Name    Height Weight BMI
      Aida    170.6  70.7   24.3 
      Eguchi  193.1  50.2   13.5 
      Iijima  158.3  90.9   36.3 
      Ono     173.4  70.6   23.5
      Uehara  167.8  64.0   22.7 
      
      名前,降順
      Name    Height Weight BMI
      Uehara  167.8  64.0   22.7 
      Ono     173.4  70.6   23.5
      ....
      

      解答例 A12-4



      ヒントと解説

      • 一部抜粋.A13-3との共通部分は割愛.
      • L13-L17は,可読性を上げて混乱を避ける為の定義
      • sort関数の引数は適宜変えて良い.例えば,データ総数などを加えても良い.
      • 文字列のソートには,標準関数の strcmp() を使うと良い.
      • main()は全部の条件をベタ打ちしたために長くなったが, やっていることは同じことの繰り返し.
      • sort()も全部の条件に対応するコードをベタ打ちしたために長くなってしまった. 見て分かる通り,ほとんど同じコードのコピペになっている. 本来なら,共通のコードにしたいところである (それによってコード量も激減させられる可能性がある). 各自,もっと洗練されたコードにするにはどうすればよいか,考えてみてほしい.




    5. 複素数を表現する構造体 Complex を作り,2つの複素数同士の掛け算を行う関数 Complex mul(Complex&, Complex&);を作れ. プログラム名を学籍番号10桁-12-5.cppとする.

      解答例 A12-5



      ヒントと解説

      • Complexのscan関数について,ここでは参照型引数を用いてそこに格納することにし, 返り値はvoidとした.A12-1では反対に,引数をvoidにして,返り値で対応した. どちらも正解なので,好みによりどちらを用いても良い.



作成したプログラムを一つのファイル(*.zip)にしてOh-o! Meijiシステムレポート第12回に提出する. 提出するすべてのファイルには,年組番号 氏名を記入すること.締め切りは日曜日よる0時までとする.

【注意】すべてのファイル名は半角のみで構成すること.
【お願い】提出するファイルは,フォルダに入れないでそのまま圧縮してください.