情報処理1 解説サイト

構造体と共用体

今回は構造体と共用体のおさらいと課題を解くにあたっての考え方について簡単に解説したいと思います.

構造体(structure)は,複数のデータを含み,ユーザが定義することで新しいデータ型が作れる機能です.プログラムを作るうちに1つの概念に対して複数のデータを扱うことが多い.そのため関連あるデータをまとめて管理したほうが効率がいい.例えば,学生のデータを作るとき,その学生の名前,年齢,学生番号といったデータをひとまとめにして扱うことになる.
このような複数データを1まとめにしたものを複合データ構造体と呼びます

構造体

先ほどの例として学生のデータベースを構造体にすると以下のようになります

struct student{
   char name[100];//名前
   int age;       //年齢
   int num;       //学生番号
};

このような,構造体の定義を構造体テンプレートと言います.structが構造体を表して,studentが構造体の名前になります.
構造体を書く上で注意点として最後に;(セミコロン)をつけるのを忘れないでください.

構造体へのアクセス

構造体へのアクセスの仕方は変数名にドット演算子をつけ,その後にメンバ名を書きます.

struct student data;//dataが変数名
data.age = 18; //dataの年齢に18を代入
strcpy(data.name,"理工太郎");//dataの名前に理工太郎を代入

実際に構造体に代入し,出力するプログラムを見ていきましょう

#include <stdio.h>
#include <string.h>
 
//  学生のデータを入れる構造体
struct student{
   char name[100];//名前
   int age;       //年齢
   int num;       //学生番号
};
 
void main(){
    struct student data;
    strcpy(data.name,"明治麻衣");   //  名前を設定
    data.age = 25;  //  年齢を設定
    data.num = 1;    //  番号を設定
    //  画面に表示
    printf("名前:%s 年齢:%d学生番号:%d ¥n",data.name,data.age,data.num);
}

構造体配列

同じ構造体を100人に使いたいという時に,配列をとって100個分を記録して処理を行う方法があります.    

#include <stdio.h>
#include <string.h>
 
//  学生のデータを入れる構造体
struct student{
   char name[100];//名前
   int age;       //年齢
   int num;       //学生番号
};

void main(){
 int i;
 struct student data[4] = {
        { "明治麻衣",18,1 },
        { "生田優子",19 ,2},
        { "理工太郎",18 ,3},
        { "機械翔",18,4 }
    };
    //  画面に出力
    for(i = 0; i < 4; i++){
        printf("名前:%s 年齢:%d学生番号:%d ¥n",data[i].name,data[i].age,data[i].num);
    }
}

構造体へのポインタ

構造体へのアクセスには,多くの場合,ポインタを用いて行われることもあります.構造体へのポインタの宣言は, いままでの変数のポインタの宣言と変わらずに使えます.

ただし,このポインタにアクセスするには,、「構造体->メンバ名」のように アロー演算子(->)を用いる.

    struct student *data;
    data->age = 20;
    data++;    // 次のdataに行く


以上が,授業のおさらいです.しっかりと復習をしておきましょう.
では,課題の考え方について解説したいと思います.

  • 5組

1.ファイル 3d_points.csv には,50個の3次元座標値が,カンマ区切りで記述されている.ダウンロードして,エディタで開いてみよ.ダブルクリックするとExcelが起動する.
まず,
(1)float または double 型 3 つの変数で 3 次元座標を表す構造体 Point を定義し
(2)ファイルから50個のデータを読み込む関数 load を作成
(3)これらの重心座標を返す calc 関数を用い
重心位置を画面に表示するプログラムを作成せよ.
main関数は下記の通りとする.
ヒント:ファイル内には1行あたり,カンマ区切りで実数が3つ並んでいるので, fscanf(fp, "%f,%f,%f", &..., &..., &...);とすれば,1行分の値3つの読み込みができる.
double 型の場合は,%lf を使用すること.

(1)double型の変数を3つ格納できる構造体を作成しましょう.
(2)まず,ファイルポインタを宣言し,ファイルを読み込みモードで開きましょう.
 次に,for文を用いて配列pntの各要素のメンバに値を格納していきましょう.
 最後に,ファイルを閉じましょう.
(3)まず,重心を表す変数を0で初期化して宣言しましょう.重心も3次元座標を表す構造体です.
 次にfor文を用いて,読み込んだデータのメンバの値を重心に足しこんでいきましょう.
 そして,重心をデータの個数で割って,その値を返しましょう.


2. ファイルrugby_matchup.csv には,13行のデータが含まれており,各行に
1.明治大学のチーム名(A or B の 1 文字)
2.対戦相手(文字列)
3.得点(整数)
4.失点(整数)
が,順次記されている.
このファイルを読み込み,これら各要素に加え勝敗(Win, Lose, Draw)をあらわす文字列を格納する構造体を作成せよ.
次に,チーム名を入力するとそのチームの結果を全て表示するプログラムを作成せよ.
ヒント: ファイルの読み込み(一行分)は,fscanf(fp, "%c , %[^,] , %d , %d", &..., , &..., &..., &...); とする.


まず,チーム名,対戦相手,得点,失点,勝敗の5つの変数を格納できる構造体を定義しましょう.
次に,ファイルを読み込む関数を作成しましょう.%[^,]とすることでカンマまでの文字列を格納できます.
次に,勝敗を判定する関数を作成しましょう.得点が失点よりも大きければ"Win",同じならば"Draw",小さければ"Lose"という文字列を構造体の勝敗を表すメンバに格納しましょう.この際strcpyを用いると良いでしょう.
main文では,配列を宣言し,これらの関数を呼び出しましょう.また,表示するチーム名をscanfで入力させ,for文,if文を用いて必要なデータを全て表示させましょう.


3. 5人分の
名前(char型)
身長[cm](float型)
体重[kg](float型)
の順に記述されたファイル health_data.csv をプログラムから読み込み, 以下の手順でプログラムを作成しなさい.
1.名前, 身長, 体重に加え, BMI指数(定義は各自で調べること) を格納することのできる構造体を作成.
2.ファイルから読み込んだ値を用い,それぞれのBMI指数を計算した後,作成した構造体に格納する.
3.「名前,身長,体重,BMI指数」の順番で各生徒のデータを画面に表示する.

まず,名前,身長,体重,bmiの4つの変数を格納できる構造体を定義しましょう.
次に,ファイルを読み込む関数を作成しましょう.読み込みは課題2と同様にscanfを用いると良いでしょう.
次に,bmiを計算する関数を作成しましょう.計算式をググって,bmiを表すメンバに値を格納しましょう.for文を用いて,全員分のデータを計算しましょう.
次に,データを出力する関数を作成しましょう.for文を用いて,全員分のデータを表示させましょう.
main関数では配列の宣言と,これらの関数の呼び出しを行いましょう.

  • 6組

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

double型の変数を3つ格納できる構造体を作成しましょう.
double x
double y
double z
が一般的かと思います。
格納さえできれば後は簡単な計算をする関数を作るだけです


2.ファイル【3d_points.csv】 には個数不明の3次元座標点が記述されている.但し最大個数は104以下とする. これらの重心座標を計算し表示するプログラムを作成せよ.また,座標点の個数も併せて表示すること.三次元点のハンドリングには,問題1で作成した Vector3D型を用いよ.
5組の問題1を参考に
重心の求め方はx,y,z各成分ごとに和を求めてから、座標点の個数で割ることで求められます


3.5人分の名前(char型),身長[cm](float型),体重[kg](float型)の順に記述されたファイル【health_data.csv】 を読み込み,以下の要件を満たすプログラムを作成しなさい.

  • 名前,身長,体重,BMI指数を格納することのできる構造体HealthDataを作成する.
  • 読み込んだ値を用いてそれぞれのBMI指数を計算した後作成した構造体に格納する.
  • 「名前,身長,体重,BMI指数」の順番で各生徒のデータを書き出す.

5組の問題3を参考にしてください
BMIは体重[kg]/(身長[m]*身長[m])で求められます


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


5.複素数を表現する構造体 Complex を作り,2つの複素数同士の掛け算を行う関数 Complex mul(Complex&, Complex&);を作れ.
Complexとmul()を作ったら、ふたつの複素数の実部と虚部の値をそれぞれキーボードより入力して、計算結果を表示するようにしてください