学生の成績を管理したい.

1
! 
学生の成績を管理したい.
2
! 
!  ID,名前,試験の成績
! 
学生の成績を管理したい.
!  ID,名前,試験の成績
どうやって管理する?
! 
!  配列を用いるのも1つ.
構造体を用いて新しい型を作成する.
!  IDと名前と試験の成績をもつStudent型を作成する.
!  ただ,成績でソートするときに面倒 情報を1つにまとめたい.
!  構造体は複数の情報を1つの型として扱える.
▪  1つ入れ換えると全配列を入れ換える必要がでる.
id[0]
id[1]
id[2]
id[3]
Student型
id
name
score
id[4]
na[0] na[1] na[2] na[3] na[4]
sc[0]
sc[1]
sc[2] sc[3] sc[4]
3
id: 4
name: Suzuki
score : 74
Student型の配列
st[0]
st[1]
st[2]
st[3]
st[4]
4
構造体を作るには,structを使う.
! 
定義したStudentを使う.
! 
!  using namespace std; の直後に定義するのが一般的.
Student x;
struct Student{
x.id = 4;
int id;
string name;
x.score = 74;
int score;
};
struct (型の名前){必要なデータ型} ;
! 
構造体の変数宣言:「構造体の名前」+「変数名」
構造体の各要素にアクセス:「.(ドット)」を使う.
!  { }の後ろのセミコロンを忘れないこと
! 
あとは,普通のデータ型と同じように扱える.
! 
! 
!  自作する型の名前は先頭を大文字にする方がベター
▪  セミコロンの前にxと書くと,Student型のxを同時に宣言できる仕様なので,何も宣言
しない場合もセミコロンが必要.(教科書参照)
5
会社のスタッフの管理.
! 
id: 4
name: Suzuki
score : 74
x.name = Suzuki ;
//staff.cpp
Staff z;
John : 38
int age;
cin >> z.name >> z.age;
cout << z.name <<
John : 38
};
Staff x;
cout << x.name <<
:
<< x.age << endl;
Staff y = x;
cout << y.name <<
:
<< y.age << endl;
<< z.age << endl;
構造体の配列も宣言できる.
list[0] = x;
list[1] = y;
x.name = John ;
x.age = 38;
:
Staff list[3];
名前と年齢をもつ
Staff構造体を作成
int main(void){
キーボードからの入力.
z.nameで変数zの名前に
入力された値を代入.
//続き
% staff
string name;
会社のスタッフの管理.
! 
//左までの実行例
struct Staff{
6
list[2] = z;
Staff xでStaff型の変数xを宣言.
x.nameで名前にアクセス.
for(int i=0; i<3; i++){
cout << list[i].name <<
:
<< list[i].age << endl;
listの中の1つ1つはStaff型.
list[0].ageは配列の先頭のStaff型
の年齢にアクセスしている.
}
Staff型の変数同士の代入も可能
return 0;
7
}
8
! 
配列のように初期化できる.
!  構造体の各要素の型に注意して初期化すること.
Staff型のxを
name = John ,age =38
で初期化
//staff.cpp
//Staff構造体の宣言
Student x;
int main(void){
x.id = 4;
x.name = Suzuki ;
Staff x = { John , 38};
Student x ={4, Suzuki , 74};
xをコピーしたyのnameを
Bob に変更.
Staff y = x;
y.name = Bob ;
x.score = 74;
! 
会社のスタッフの管理.
! 
Staff list[3] = {x, y, { David , 27}};
構造体の配列の初期化は2次元配列の初期化に似ている.
for(int i=0; i<3; i++){
cout << list[i].name <<
Student list[2] = {{ 4, Suzuki , 74}, { 6, Tanaka , 63}};
:
Staff型の1次元配列を宣言
し,xとyと27歳のDavidで
初期化.
<< list[i].age << endl;
}
return 0;
}
9
! 
構造体の要素には任意の型を用いることができる.
! 
!  違う構造体の中身は変数の名前が同じでも大丈夫.
struct Point{
int x, y;
//x座標,y座標
};
Point型をもつTriangle型の利用.
//triangle.cpp
△ABC
//Point構造体の定義
struct Triangle{
string name //点の名前
10
//Triangle構造体の定義1
string name; //三角形の名前
Point a, b, c; //3点を用意.
cout << t.name <<
={
<< t.a.name <<
A:(3, 5)
B:(1, 1)
struct Triangle{
C:(4, 2)
C:(4, 2)
Triangle t = { ABC , { A ,3, 5}, { B , 1, 1}, { C , 4, 2}};
}; //Triangle定義1
△ABC
B:(1, 1)
int main(void){
A:(3, 5)
:(
<< t.b.x << , << t.b.y << ),
<< t.c.name <<
:(
<< t.c.x << , << t.c.y << )
return 0;
Point abc[3]; //3点を用意.
}
}; //Triangle定義2
11
<< t.a.x << , << t.a.y << ),
<< t.b.name <<
<<
string name; //三角形の名前
:(
} << endl;
//実行例
% triangle
ABC = { A:(3,5), B:(1,1), C(4,2)}
Triangle型の
名前,Point型a, b, c
の順に初期化.
まずTriangle型の各要
素にアクセスし,
Point型がもっている
各要素にアクセスする.
12
Point型をもつTriangle型の利用.
! 
! 
//triangle2.cpp
△ABC
//Point構造体の定義
//Triangle構造体の定義2
B:(1, 1)
int main(void){
!  関数の戻り値や引数としても利用できる.
A:(3, 5)
!  値渡しの場合,関数内で構造体の中身を変更してもmainでは反
={ ;
for(int i=0; i<3; i++){
cout << t.abc[i].name << : ( << t.abc[i].x << , << t.abc[i].y
<< ) ;
if(i!=2){ cout << , ;}
}
cout << } << endl;
return 0;
}
//実行例
% triangle2
ABC = { A:(3,5), B:(1,1), C(4,2)}
//inoutPoint.cpp
//Point構造体の宣言
//Point input(void)関数
//void printPoint(Point)関数
int main(void){
Point a = input( );
printPoint(a);
for(int i=0; i<N; i++){
まずTriangle型の
Point型配列にアクセス
してから,Point型の各
要素にアクセスする.
}
}
printPoint関数内で,
p.name = abc ;
としてもmain内では変更されていない.
13
14
! 
リファレンス引数
!  (ざっくり)関数で変更した値を引き継ぎたいときに用いる.
! 
構造体のリファレンス引数
!  関数で変更した値を引き継ぎたいときに用いる.(左)
B11
!  構造体のデータサイズが大きい場合にも用いる.(右)
▪  値を変更しない場合はconst宣言をしておく.
C:(2,4)
void update(Point &p){
list[i] = input( );
void printPoint(const Point &p){
p.x += 2;
printPoint(list[i]);
cout << p.name
p.y += 3;
}
<< :( p.x << , << p.y << ) << endl;
return;
return 0;
}
return;
return p;
A:(3,5)
C24
<< :( p.x << , << p.y << ) << endl;
cin >> p.name >> p.x >> p.y;
A35
const int N=2;
cout << p.name
Point p = { NULL , 0, 0};
% inputPoint
B:(1,1)
void printPoint(Point p){
Point input(void){
Triangle型の
名前,Point型配列
の順に初期化.
//実行例
cout << endl;
Point list[N];
映されない.
C:(4, 2)
Triangle t = { ABC , {{ A ,3, 5}, { B , 1, 1}, { C , 4, 2}}};
cout << t.name <<
構造体は1つのデータ型として扱える.
}
15
return;
}
16
//refPoint.cpp
//Point構造体の宣言
//update関数
//point関数
int main(void){
Point a = { X , 1, 2};
//実行例
! 
% refPoint
!  (ざっくり)構造体のリファレンスと同じような用途で使用できる.
X:(3, 5)
!  ポインタ先の構造体の各要素にアクセスする方法.
A:(5, 7)
▪  「.」を用いる場合 (*p). x
B:(7, 9)
▪  「->」アロー演算子を用いる場合 p->x
update(a);
print(a);
const int N = 2;
Point b[N] = {{ A , 3, 4}, { B , 5, 6}};
構造体のポインタ引数
リファレンス引数には,
変数をそのまま渡す.
void update(Point *p){
update(b[i]);
}
return 0;
if(p!=0){
(*p).x += 2;
for(int i=0; i<N; i++){
print(b[i]);
void update(Point *p){
if(p!=0){
p->x += 2;
(*p).y += 3;
リファレンス引数には,
変数をそのまま渡す.
p->y += 3;
}
}
return;
return;
}
}
}
17
//refPoint.cpp
//Point構造体の宣言
//update関数
//point関数
int main(void){
Point a = { X , 1, 2};
! 
//実行例
const int N = 2;
Point b[N] = {{ A , 3, 4}, { B , 5, 6}};
配列と配列の要素数を1つの構造体にする.
% refPoint
!  配列内の要素数の出力:配列に保存されている要素数が重要.
X:(3, 5)
!  構造体にしてしまって,配列とその要素数を1まとめにする.
A:(5, 7)
B:(7, 9)
const int N =10;
update(&a);
print(&a);
18
struct MyArray{
int num;
ポインタ引数には,
アドレスを渡す.
double array[N];
arrayに実際に入っている要
素数を保存するための変数.
};
for(int i=0; i<N; i++){
update(&b[i]);
print(&b[i]);
}
return 0;
}
ポインタ引数には,
アドレスを渡す.
19
20
! 
MyArray構造体のもつarray配列の要素の表示.
//myArray.cpp
!  numを利用する.
//printR
!  左がリファレンス引数版,右がポインタ引数版
void printR(const MyArray &a){
cout << a->array[i] <<
cout << endl;
printR(x);
MyArray型のxの
numを5,
array[N]を
1.2, 2.3, 3.4, 4.5, 5.6, 残りは0
で初期化.
cout << endl;
;
printP(&x);
}
}
1.2 2.3 3.4 4.5 5.6
MyArray x = {5, {1.2, 2.3, 3.4, 4.5, 5.6}};
for(int i=0; i<a->num; i++){
}
% myArray
1.2 2.3 3.4 4.5 5.6
int main(void){
if(a!=0){
;
(リファレンス版)
//printP関数(ポインタ版)
void printP(const MyArray *a){
for(int i=0; i<a.num; i++){
cout << a.array[i] <<
//実行例
//MyArray構造体の宣言
return 0;
}
}
cout << endl;
}
ポインタ引数には,アドレスを渡す.
21
! 
Point型変数pへのキーボードからの入力
22
! 
!  cinやcoutを使うときに毎回以下を書くのは面倒.
istream& operator >>(istream &in, Point& p){
▪  cin >> p.name >> p.x >> p.y;
return in >> p.name >> p.x >> p.y;
▪  cout << p,name :( << a.x < << , << a.y << ) ;
! 
cinやcoutをPoint型にも対応させる.
}
解決法
ostream& operator <<(ostream &out, Point& p){
!  input関数,output関数を作成する.
return out << p.name :( << p.x < << , << p.y << )
!  cinやcoutをPoint型にも対応させる.
}
! 
これで,Point型変数pに対応したcin, coutが利用できる.
!  cin >> p;
!  cout << p;
23
24