Outline プログラミング演習第 7 回構造体 on 2012.12.06 電気通信大学情報理工学部知能機械工学科長井隆行 今日の主眼 構造体 構造体の配列 構造体とポインタ 演習課題 2 今日の主眼 配列を使うと 複数の ( 異なる型を含む ) データを扱いたい 例えば 成績データの管理 複数のデータを扱う 配列を使う! 名前学籍番号点数 ( 英語 ) 点数 ( 数学 ) Aomori 1 59.4 84.3 名前 学籍番号 点数 ( 英語 ) 点数 ( 数学 ) Aomori 1 59.4 84.3 Itamoto 2 43.8 94.2 Kimura 3 74.3 64.5 Itamoto 2 43.8 94.2 Kimura 3 74.3 64.5 Sato 4 57.3 73.4 Sugiyama 10 62.6 55.9 Sato 4 57.3 73.4 Sugiyama 10 62.6 55.9 3 float eng[5] = 59.4, 43.8, 74.3, 57.3, 62.6 他にも math[5] code[5] name[10][5] などを用意する Sato 君は数学が何点だったかを知りたい新たにYasui 君のデータを追加したい 不便? どのようなデータ構造にすべきか? 4
構造体 構造体のテンプレートを宣言する 配列 : 同じ種類 ( 型 ) のデータを複数個まとめて扱う int hoge[10] 構造体 まとめて扱いたいデータを自分で定義し 新しいデータ型として使うことができる 構造体 : 異なる型のデータを複数個まとめて扱いたい! double score; char name[50]; 構造体のテンプレート ( 枠組み ) を宣言 struct タグ名 データ型メンバ名 ; 名前 学籍番号 テストの点数 10 科目 150 人分 構造体の出番です double eng; double math; char name[50]; 5 6 構造体を宣言する 構造体のメンバを参照する 使う段階で宣言 ( 変数の宣言と同じ ) する struct タグ名変数名の並び ; struct seiseki student; struct seiseki newstudent; 実際には構造体のメンバにアクセスしたい ( つまり 名前や点数 学籍番号を知りたい ) 構造体の各メンバは 構造体変数名. メンバ名 のようにピリオド (.) を用いて指定します この (.) を ドット演算子 と呼ぶ /* 番号 名前 点数を表示する例 */ printf("%d %s %f %f n", student.code, student.name, student.eng, student.math); 他の型の変数の時と比べてみると分かり易い int data; float score; student.eng = 85.4; /* 英語の点数を 85.4 に修正する例 */ 7 8
実際に構造体を使った例 構造体のイメージ図 double eng; double math; char name[50]; 構造体の初期化 アドレス 0x10000000 0x10000001 メモリ 20 hoge student.code 1 char int double eng; char name[4]; char hoge = 20; struct seiseki student =1,64.5, AOI struct seiseki student = 10, 62.6, 55.9, "Sugiyama" struct seiseki student2; 0x10000005 student.eng student2 = student; student2.math = 20.0; 64.5 double 構造体 struct seiseki student printf("%d %s %f %f n", student.code, student.name, student.eng, student.math); printf("%d %s %f %f n", student2.code, student2.name, student2.eng, student2.math); 9 0x1000000D A student.name[0] O student.name[1] I student.name[2] char[4] \nstudent.name[3] 10 構造体を使ったソースコードの例 まだ完璧ではない? ある人の平均点を求めて表示するプログラム /* 学籍番号 */ double Average = 0.0; struct seiseki student = 1, 59.4, 84.3, "Aomori" Average = (student.eng + student.math)/2.0; ここで宣言すると他の関数でもこの構造体を使える関数の中で宣言すると他の関数ではその構造体は使えない 各人のデータはまとめて扱えるようになりましたが 名前 学籍番号 点数 ( 英語 ) 点数 ( 数学 ) Aomori 1 59.4 84.3 Itamoto 2 43.8 94.2 Kimura 3 74.3 64.5 Sato 4 57.3 73.4 Sugiyama 10 62.6 55.9 printf("average:%f n", Average); p7-1.c まとめた各人のデータをさらにまとめて扱いたい!! 11 12
構造体の配列 構造体の配列を使い複数のデータをまとめて扱う基本的な考え方は 一般的な変数 ( 型 ) の配列と同じ 構造体の配列を宣言する 使う段階で配列を宣言 ( 一般の配列宣言と同じ ) する Aomori Itamoto Kimura Sato Sugiyama 1 2 3 4 10 59.4 43.8 74.3 57.3 62.6 84.3 94.2 64.5 73.4 55.9 struct タグ名変数名 [ 配列の数 ]; struct seiseki ClassA[50]; struct seiseki ClassB[100]; 0 番 1 番 2 番 3 番 4 番 一つのデータとして扱える入れ物 全体でひとつのデータとして扱える そこから 個々のデータが取り出せる 13 他の型の変数の時と比べてみると分かり易い int data[50]; float score[100]; 14 構造体配列を初期化する 宣言時に値を代入 ( 初期化 ) することができる 基本は配列と同じ struct seiseki classa[5] = 1, 59.4, 84.3, "Aomori", 2, 43.8, 94.2, "Itamoto", 3, 74.3, 64.5, "Kimura", 4, 57.3, 73.4, "Satou", 10, 62.6, 55.9, "Sugiyama" 15 構造体配列に値を代入する 構造体ごとにまとめてデータを扱う struct seiseki student = 10, 62.6, 55.9, "Sugiyama" struct seiseki student2; struct seiseki classa[5] = 1, 59.4, 84.3, "Aomori ", 2, 43.8, 94.2, "Itamoto", 3, 74.3, 64.5, "Kimura", 4, 57.3, 73.4, "Satou" 同じ種類の構造体変数に直接代入 student2=student; classa[4]=student2; student=classa[0]; 配列の場合は添え字が使える 添え字を使ってデータを取り出せる 16
構造体配列のメンバを参照する 実際には構造体のメンバにアクセスしたい ( つまり 名前や点数 学籍番号を知りたい ) 構造体の各メンバは 構造体変数名. メンバ名 のようにピリオド (.) を用いて指定します この (.) を ドット演算子 と呼ぶ配列にした場合も基本的には同じ /* 各人の番号 名前 点数を表示する例 */ printf("%d %s %f %f n", student.code, student.name, student.eng, student.math); for(i = 0; i < 5; i++) printf("%d %s %f %f n", classa[i].code, classa[i].name, classa[i].eng, classa[i].math); classa[4].eng = 85.4; /* 英語の点数を 85.4 に修正する例 */ 17 練習問題 各科目の平均点を求めて表示するプログラムを完成しよう double AverageEng = 0.0; double AverageMath = 0.0; struct seiseki classa[5] = 1, 59.4, 84.3, "Aomori", 2, 43.8, 94.2, "Itamoto", 3, 74.3, 64.5, "Kimura", 4, 57.3, 73.4, "Satou", 10, 62.6, 55.9, "Sugiyama" for(i=0; i<5; i++) AverageEng=AverageEng/5; /* 和を総数で割る */ AverageMath=AverageMath/5; /* 和を総数で割る */ /* 学籍番号 */ 18 解答例 構造体のポインタ double AverageEng = 0.0; double AverageMath = 0.0; struct seiseki classa[5] = 1, 59.4, 84.3, "Aomori", 2, 43.8, 94.2, "Itamoto", 3, 74.3, 64.5, "Kimura", 4, 57.3, 73.4, "Satou", 10, 62.6, 55.9, "Sugiyama" for(i=0; i<5; i++) AverageEng += classa[i].eng; AverageMath += classa[i].math; AverageEng=AverageEng/5; /* 和を総数で割る */ AverageMath=AverageMath/5; /* 和を総数で割る */ /* 学籍番号 */ 構造体のポインタも使えます例 struct seiseki *p_student; struct seiseki student; p_student = &student; ポインタを使った場合のメンバーの参照の仕方に注意 " -> " を使う ( アロー演算子と呼ばれる ) (*p_student).code p_student->code (*p_student).name (*p_student).score シンタックスシュガー p_student->name p_student->score p7-2.c 19 20
構造体配列とポインタの関係 構造体配列とポインタの関係続き 構造体のポインタが使えると言うことは struct seiseki classa[5]; /* 構造体配列 */ のとき classa が &classa[0] を意味する ( シンタックスシュガー ) classa[0] と *classa は同じものを表す!! なので メンバを参照するやり方は 3 つ考えられる classa[0].eng と (*classa).eng と classa->eng さらに ポインタの演算も使えるので struct seiseki classa[5]; /* 構造体配列 */ のとき classa[0].eng と (*classa).eng と classa->eng が同じ classa[1].eng と (*(classa+1)).eng と (classa+1)->eng が同じ classa[4].eng と (*(classa+4)).eng と (classa+4)->eng が同じ 21 これかこれを使う 22 本日の演習 ー準備ー まずは p7-4.cをダウンロードする コンパイル 実行して正しく動作することを確認する ー課題ー ( ここから先をメールで送る ) p7-4.cの平均点の計算部分を関数にしましょう 引数に構造体のポインタを使う 計算結果が2つでてくる ( 英語と数学 ) ので 関数を呼び出す側で結果を入れる変数をアドレス渡しする ソースコードと実行結果をメールで送る 送る際には注意事項をよく確認すること http://apple.ee.uec.ac.jp/comprog 諸注意 今日の講義の感想 質問をメール本文に書いてください よく分かった ここが分からない など double AverageEng = 0.0; double AverageMath = 0.0; もととなるソースコード struct seiseki classa[5] = 1, 59.4, 84.3, "Aomori", 2, 43.8, 94.2, "Itamoto", 3, 74.3, 64.5, "Kimura", 4, 57.3, 73.4, "Satou", 10, 62.6, 55.9, "Sugiyama" for(i=0; i<5; i++) AverageEng += classa[i].eng; AverageMath += classa[i].math; AverageEng=AverageEng/5; /* 和を総数で割る */ AverageMath=AverageMath/5; /* 和を総数で割る */ /* 学籍番号 */ p7-2.c 23 24
/* 学籍番号 */ /* 平均計算関数のプロトタイプ宣言 */ void CalcAverage(struct seiseki* classa, double* Average1, double* Average2); double AverageEng = 0.0; /* 英語の平均値 */ double AverageMath = 0.0; /* 数学の平均値 */ struct seiseki classa[5] = 1, 59.4, 84.3, "Aomori", 2, 43.8, 94.2, "Itamoto", 3, 74.3, 64.5, "Kimura", 4, 57.3, 73.4, "Satou", 10, 62.6, 55.9, "Sugiyama" ヒント void CalcAverage(struct seiseki* classa, double* Average1, double* Average2) C 言語の総まとめ まるばつゲームを作る! おまけ まずはアルゴリズムが必要 ゲーム全体の流れ COMがどのように手を決めるのか? とりあえず作ってみた Comを強くするには? /* 平均の計算 ( 関数に情報を渡している )*/ CalcAverage( ); /* 結果をアドレス渡しにしていることに注意 */ 25 marubatsu.c 26