Document

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