プログラミング入門2 芝浦工業大学情報工学科青木 義満 第11回構造体
プログラミング入門2 2 構造体 5 人分のサッカー選手データ 全てのデータを関数に渡して,処理する場合 char name[5][256]; int assist[5]; int score[5]; void func( char name[ ][256], int assist[ ], int score[ ] ) void func( char name[ ][256], int *assist, int *score) ・氏名 ・所属チーム ・得点 ・アシスト ・年俸 ・・・・・ 選手 データをひとまとめにして 効率良くデータを管理・処理し たい 構造体の必要性!
プログラミング入門2 3 構造体とは? 多人数の学生の身体検査のデータ char name[5][256];/* 5 人分の学生の名前 */ int height[5];/* 5 人分の学生の身長 */ double weight[5];/* 5 人分の学生の体重 */ 1 人目のデータ name[0][256] height[0] weight[0] 2 人目のデータ name[1][256] height[1] weight[1] 各配列は独立していて,それぞれの関連性がわかりにくい 個人のデータを “ カード ” でまとめて表し,そのカードを人数分用意
プログラミング入門2 4 名前 芝浦 義満 身長 168cm 体重 70kg 名前 芝浦 義満 身長 168cm 体重 70kg 名前 芝浦 次郎 身長 165cm 体重 55.5kg 名前 芝浦 次郎 身長 165cm 体重 55.5kg 構造体とは? 構造体とは,ひとまとまりのデータを集めたデータ構造である 重要 名前 芝浦 太郎 身長 176cm 体重 64.5kg 名前 芝浦 太郎 身長 176cm 体重 64.5kg 名前 身長 体重 char 型 int 型 double 型 1 枚のカード 複数の型のデータを ひとまとめにして扱う!
プログラミング入門2 5 {}{} 中括弧でくくって ひとまとめに 構造体の宣言 ~ 自分で新しい “ 型 ” をつくる 構造体を宣言することは,意味のあるデータをひと まとまりにした,新しい変数の “ 型 “ を自分で作るこ とである 宣言の方法 char name[256]; intheight; double weight; 1 枚のカードをどう作るか? typedef struct type( 型 ) を define( 定義 ) 構造体 構造体の名前(型名) ※ int, double などと同じ役割 ※セミコロン忘れずに! student ; 手順 ①どんなデータをひとまとめにし て扱うかを決定 ②構造体の名前(変数の型)を決 定 手順 ①どんなデータをひとまとめにし て扱うかを決定 ②構造体の名前(変数の型)を決 定 構造体の メンバー という
プログラミング入門2 6 構造体データの使い方 変数(オブジェクト)の宣言 構造体内のメンバーへのアクセス intx; int 型のオブジェクト x を宣言 student aoki; student 型のオブジェクト aoki を宣言 {}{} char name[256]; intheight; double weight; typedef struct student 構造体の定義 student aoki; 構造体オブジェクト aoki は,以下のメンバを持つ aoki.name[256] aoki.height aoki.weight 構造体のメンバはドット(.)演算子でアクセス可能
プログラミング入門2 7 構造体を使ったプログラム(構造体のメン バ) ソースファイル名: list1203.c (p.274, 若干変更 ) 構造体メンバへの値の代入と表示 #include #include /* 文字列操作関数用 strcpy 使用のため */ typedef struct{ char name[20];/* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; int main(void) { student sanaka; /* 構造体メンバへの値の代入 */ strcpy(sanaka.name, "Sanaka");/* 文字列 sanaka を sanaka.name にコピー */ sanaka.height = 175;/* 身長 */ sanaka.weight = 60.5;/* 体重 */ /* 構造体メンバの表示 */ printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } #include #include /* 文字列操作関数用 strcpy 使用のため */ typedef struct{ char name[20];/* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; int main(void) { student sanaka; /* 構造体メンバへの値の代入 */ strcpy(sanaka.name, "Sanaka");/* 文字列 sanaka を sanaka.name にコピー */ sanaka.height = 175;/* 身長 */ sanaka.weight = 60.5;/* 体重 */ /* 構造体メンバの表示 */ printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); }
プログラミング入門2 8 解説 typedef struct{ char name[20];/* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; int main(void) { student sanaka ; /* 構造体メンバへの値の代入 */ strcpy(sanaka.name, "Sanaka");/* 文字列 sanaka を sanaka.name にコピー */ sanaka.height = 175;/* 身長 */ sanaka.weight = 60.5;/* 体重 */ strcpy(sanaka.name, "Sanaka"); 文字配列へのポインタ 文字配列( sanaka.name )に “Sanaka” を代入
プログラミング入門2 9 ソースファイル名: list1204.c (p.275, 若干変更 ) 構造体メンバの初期化 構造体を使ったプログラム(メンバの初期 化) /* 学生を表す構造体で表した佐中君を初期化 */ #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; int main(void) { student sanaka = {"Sanaka", 175, 60.5}; printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } /* 学生を表す構造体で表した佐中君を初期化 */ #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; int main(void) { student sanaka = {"Sanaka", 175, 60.5}; printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } 構造体メンバの初期化
プログラミング入門2 10 構造体同士の値の代入 ( p.280 ) 同じ種類の構造体データであれば,互いに値を代入する ことが可能 student aoki, maeda; aoki = maeda; maeda のメンバ( name, height, weight ) をそれぞれ aoki の対応するメンバに代入 maeda のメンバ( name, height, weight ) をそれぞれ aoki の対応するメンバに代入 配列では不可能!
プログラミング入門2 11 va[5], vb[5] と2つの配列は要素数も同じだし,もっと 簡単に次のように代入できないの? 復習: 配列のコピー 注意点 ( p.93 ) vb = va ; 重要 代入演算子によって,配列を代入することはできない for (i = 0; i < 5; i++) vb[i] = va[i]; 面倒でも,1つ1つ代入していく
プログラミング入門2 12 関数での構造体データの使用(値変更な し) ソースファイル名: struct1.c 関数への構造体データの受け渡し(値は変更しない) #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; void print_data( student std ) { printf(" 氏 名 = %s\n", std.name); printf(" 身 長 = %d\n", std.height); printf(" 体 重 = %f\n", std.weight); } int main(void) { student sanaka = {"Sanaka", 175, 60.5}; print_data( sanaka ); return (0); } #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; void print_data( student std ) { printf(" 氏 名 = %s\n", std.name); printf(" 身 長 = %d\n", std.height); printf(" 体 重 = %f\n", std.weight); } int main(void) { student sanaka = {"Sanaka", 175, 60.5}; print_data( sanaka ); return (0); } 構造体データを受け取り, 値を表示する関数 値を変更しない → ポインタでなくて OK
プログラミング入門2 13 関数での構造体データの使用(値変更あ り) ソースファイル名: struct2.c 関数への構造体データの受け渡し(値の変更あり) #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } int main(void) { student sanaka = {"Sanaka", 175, 60.5}; change_data( &sanaka ); printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } int main(void) { student sanaka = {"Sanaka", 175, 60.5}; change_data( &sanaka ); printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } 構造体データを受け取り, 値を変更する関数 値を変更する → ポインタ(アドレス)で受け取り!
プログラミング入門2 14 解説 構造体のポインタ渡し change_data( &sanaka ); void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } sanaka std *std *std は sanaka のエイリアス 106 番地 student 型のオブジェクトのアドレス を入れるための箱 ( student 型オブジェクトへのポインタ) (*std).height → *std.height () は省略不可 * よりも. の方が優先順位が高いため, *(std.height) と解釈されてしまう!
プログラミング入門2 15 関数での構造体データの使用(値変更あ り) ソースファイル名: struct3.c ( p.277 ,変更あり) 関数への構造体データの受け渡し(値の変更あり,アロー演算子使 用) #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; void change_data( student *std ) { std->height = 180; std->weight = 80.0; } int main(void) { student sanaka = {"Sanaka", 175, 60.5}; change_data( &sanaka ); printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } #include typedef struct { char name[20]; /* 名前 */ int height;/* 身長 */ float weight;/* 体重 */ } student; void change_data( student *std ) { std->height = 180; std->weight = 80.0; } int main(void) { student sanaka = {"Sanaka", 175, 60.5}; change_data( &sanaka ); printf(" 氏 名 = %s\n", sanaka.name); printf(" 身 長 = %d\n", sanaka.height); printf(" 体 重 = %f\n", sanaka.weight); return (0); } 構造体データを受け取り, 値を変更する関数 値を変更する → ポインタ(アドレス)で受け取り!
プログラミング入門2 16 アロー( -> )演算子 change_data( &sanaka ); void change_data( student *std ) { (*std).height = 180; (*std).weight = 80.0; } void change_data( student *std ) { std->height = 180; std->weight = 80.0; } = std->height = 180; 構造体へのポインタ名 -> メンバ 重要 ポインタ ptr が指す構造体のメンバ mem である (*ptr).mem は, -> 演算子を用いて ptr->mem と簡潔に記述せよ ポインタ ptr が指す構造体のメンバ mem である (*ptr).mem は, -> 演算子を用いて ptr->mem と簡潔に記述せよ
プログラミング入門2 17 ・・・・・・・ ・・・・・・ 複数のデータの扱い ( 構造体の配列, p.282) 構造体データを複数扱う際には,構造体の配列 を用いる (データカードを人数分用意する) 構造体の配列の宣言 student std[5]; typedef struct { char name[20]; int height; float weight; } student; std[2].weight std[2].heightstd[2].name std[1].weight std[1].heightstd[1].name std[0].weight std[0].heightstd[0].name std[0] std[1] std[2]
プログラミング入門2 18 構造体の配列 ソースファイル名: list1208.c (p.283 を変更) 構造体の配列 #include #define NUMBER 5 /* 学生の人数 */ typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; int main(void) { int i; student std[]= { { "Sato", 178, 61.0 }, { "Sanaka", 175, 60.5 }, { "Takao", 173, 80.0 }, { "Mike", 165, 72.0 }, { "Masaki", 179, 77.5 }, }; puts(" "); for (i = 0; i < NUMBER; i++) printf("%-8s %6d%6.1f\n", std[i].name, std[i].height, std[i].weight); puts(" "); return (0); } #include #define NUMBER 5 /* 学生の人数 */ typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; int main(void) { int i; student std[]= { { "Sato", 178, 61.0 }, { "Sanaka", 175, 60.5 }, { "Takao", 173, 80.0 }, { "Mike", 165, 72.0 }, { "Masaki", 179, 77.5 }, }; puts(" "); for (i = 0; i < NUMBER; i++) printf("%-8s %6d%6.1f\n", std[i].name, std[i].height, std[i].weight); puts(" "); return (0); }
プログラミング入門2 19 構造体の配列を関数へ渡す方法 ソースファイル名: struct4.c #include #define NUMBER 5 /* 学生の人数 */ typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; void print_data( student data[] ) { int i; puts(" "); for (i = 0; i < NUMBER; i++) printf("%-8s %6d%6.1f\n",data[i].name, data[i].height, data[i].weight); puts(" "); } in main(void) { student std[] = { { "Sato", 178, 61.0 }, { "Sanaka", 175, 60.5 }, { "Takao", 173, 80.0 }, { "Mike", 165, 72.0 }, { "Masaki", 179, 77.5 }, }; print_data( std ); return (0); } #include #define NUMBER 5 /* 学生の人数 */ typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; void print_data( student data[] ) { int i; puts(" "); for (i = 0; i < NUMBER; i++) printf("%-8s %6d%6.1f\n",data[i].name, data[i].height, data[i].weight); puts(" "); } in main(void) { student std[] = { { "Sato", 178, 61.0 }, { "Sanaka", 175, 60.5 }, { "Takao", 173, 80.0 }, { "Mike", 165, 72.0 }, { "Masaki", 179, 77.5 }, }; print_data( std ); return (0); } 配列データを関数に渡す時には, その配列の先頭要素のアドレスを渡す std( 配列名 ) = &std[0] 配列データを関数に渡す時には, その配列の先頭要素のアドレスを渡す std( 配列名 ) = &std[0] void print_data( student data[ ] ) = student *data どちらも配列の先頭アドレスを受け取る 受け取ると,関数内で data[i] として 配列要素を扱える
プログラミング入門2 20 演習課題 (第 11 回) 問1)構造体 (kadai11-1.c) キーボードから 3 点の 2 次元座標値( x, y )を読み込み, 3 点から作られる 3 角形の面積 S を出力するプログラムを作成せ よ。 p1 p2 p3 S 但し,構造体は以下のものを用いること typedef struct { double x; double y; } point;
プログラミング入門2 21 演習課題 (第 11 回) 問2)構造体の配列と関数( kadai11-2.c ) student 構造体の配列を用い, 5 名分の学生データを体重の軽 い順に並べ替え(ソート),並べ替える前と並べ替えた後の 結果を表示するプログラムを作成せよ。 並べ替え(ソート)のアルゴリズムについては,前回のレポ ートを参考にせよ。 typedef struct { char name[20]; /* 名前 */ int height; /* 身長 */ float weight; /* 体重 */ } student; void weight_sort( student *data, int num); もしくは, student data[ ] 配列の要素数