情報処理II

情報処理Ⅱ
2007年12月10日(月)
授業の進め方
構造体
プリプロセッサ
指令
その他の型
ライブラリ関数
自分の思う通りに,適切な形で,プ
ログラムとして表現する.
識別子
算術型
制御文
演算子
2年以降で
さらに学習・習熟
ファイル入出力
配列・文字列
ポインタ
関数
変数の
有効範囲
再帰呼び出し
プログラムの作成・
コンパイル・実行
2
本日学ぶこと

いくつかの型




なぜ「型」にこだわるか?



typedef
列挙型(enum型)
構造体
プログラムを書きやすく
読みやすくする…定性的
なメリット
実行時のコスト(メモリ使用量な
ど)を見積もることができ,そこか
らプログラムの改善が期待できる
…定量的なメリット
処理対象のデータを効果的・効率的に取り扱える
既存の機能をもとに,便利な機能を創れる
以下を読む上での注意


この色とこの色は型名を表す.
この色は変数名を表す.
リpp.108-109
3
typedef

独自に型(type)を定義(define)する.


例





ただし,メモリに割り当てるわけでないので,「宣言」である.
typedef signed char schar;
schar c; ⇒ signed char c; と同じ
typedef unsigned char uchar;
uchar c, *p; ⇒ unsigned char c, *p; と同じ
typedef char *String;
String s, t; ⇒ char *s, *t; と同じ
typedef char c5[5];
c5 x, y, z; ⇒ char x[5], y[5], z[5]; と同じ
構造体の型名定義によく用いられる.
リp.107, pp.142-145
4
typedefの考え方

変数の定義


char c5[5]; は,変数c5を定義し,その型はchar [5]型
とする.
型の定義

typedef char c5[5]; は,c5型を定義し,その型は
char [5]型と同一とみなす.
5
列挙型(enumeration)とは

「ラベル」を格納・参照・比較したいときに使う.



変数に格納される具体的な値には関心がない.
実際には,ラベルに整数値が割り当てられる.これを積極的に
活用することもある.
構文: enum タグ名 { 列挙子並び };


「enum タグ名」型が定義される.
列挙子は「,」で区切る.
リpp.65-66, p.138
6
列挙型の使用例

例

0
1
enum Boolean {FALSE, TRUE};
enum Boolean p = TRUE, q = FALSE, r = p||q;
13

enum month {
Jan = 1, Feb, Mar, ..., Dec, MONTH_END
} mloop;
型と変数を同時に定義
int rain[100][MONTH_END];
for (mloop = Jan; mloop < MONTH_END;
mloop++) {
rain[7][mloop] = ...;
}
年月単位の降水量を格納する
7
汎整数型

汎整数型(integral type)に含まれるもの




列挙型は,計算時にはint型とみなされる.

リp.64
整数型(char,int,long など)
列挙型
size_t型(sizeof演算子の評価値など.unsigned int
またはunsigned longと同一のことが多い.)
ただし,利用は代入,比較,範囲内の増分・減分にとどめておく.
8
構造体(structure)


複数のオブジェクトを取りまとめて一つのオブジェクトとして
扱うための機構
構造体で表現するとよいもの
(x,y)





入p.242
リp.366
(2次元,3次元などの)座標上の点
複素数
行列(行数と列数と各成分)
所持金
学生情報
500
100
100
100
50
10
学生番号:0001
氏名:和大太郎
情報処理Ⅰの成績:80
情報処理Ⅱの成績:75
修得単位数: 52
9
構造体宣言の例(1)

構文: struct タグ名 { メンバ宣言子並び };


「struct タグ名」型が定義される.
例

struct point {
double x;
double y;
};
struct point p = {1, -1};

セミコロンを忘れない
ように
この x と y を,
point構造体の
メンバという.
p:
x=1
y = -1
配列と同じ書式で
初期化可能
リpp.366-367, pp.205-206
10
構造体宣言の例(2)

構造体宣言と変数定義を一つの文で


struct point {
double x;
double y;
} p;
構造体宣言と型定義を一つの文で

typedef struct Point {
double x, y;
} point;
point p;
「,」を用いて
メンバを一括
宣言してよい
struct Point型と
point型が定義される
入p.242
リpp.367-368
11
構造体宣言の例(3)

無名構造体


struct {
double x;
double y;
} p;
typedef struct {
double x, y;
} point;
point p;
12
構造体宣言の例(4)

行列(行数,列数とも10まで)

struct matrix {
int row, column;
double element[10][10];
};
•
•


row
column
element
…
行列(成分はポインタ)

struct matrix {
int row, column;
double **element;
};
row
•
column
•

element
13
構造体宣言の例(5)

自己参照構造体

struct node {
graph
char label;
struct node *next;
label = 'A'
};
next
struct node graph[100];
graph[0].label = 'A';
graph[0].next = graph + 1;
graph[1].label = 'Z';
graph[1].next = NULL;
•
•




リp.69, p.143, p.372, p.376
label = 'Z'
…
next = NULL
14
構造体の参照と代入(1)

前提


struct point {
double x, y;
};
struct point p, *pp = &p;
p:
pp
x
y
メンバへのアクセス方法


構造体オブジェクトpのメンバxは p.x と書いて
参照・代入ができる.
構造体オブジェクトを指し示すポインタppについては,
(*pp).x もしくは pp->x と書けばよい.
× *pp.x
• . と -> は演算子であり,最上位の優先順位を持つ.
入p.243
リp.157, pp.367-368
15
構造体の参照と代入(2)

構造体オブジェクトの代入




struct matrix a, b; (aを初期化) b = a; とすると,
bにはaのコピーが格納される.
構造体の中に配列があっても,コピーされる.
構造体の中のポインタは,ポインタ値がコピーされる.
構造体渡し


関数の引数や戻り値の授受でも,構造体オブジェクトが代入
(コピー)される.
しかし,構造体はしばしばポインタで渡される(参照渡し).
• 関数処理で,構造体オブジェクトの中の値を変えたいとき
• 大きなサイズの構造体オブジェクトをスタックに置きたくない
とき
リp.163, p.358, pp.97-98
16
三角形の面積:仕様

2次元座標上の三角形の面積を求める.
構造体を用いる.
三点P(a, b), Q(c, d), O(0,0)からなる⊿PQOの面積
は,|ad-bc|/2 で求められることを利用する.


y
O
x
17
三角形の面積:構造体

2次元座標の点
struct point {
double x, y;
};

三角形の3点
struct triangle {
struct point p1, p2, p3;
};

リp.103
メンバと変数は,識別子が重複していてもよい.
18
三角形の面積:関数
struct triangle transform_triangle(struct
triangle t);


三角形の3点を,メンバp3が原点になるように平行移動する.
double calc_area(struct triangle t);


三角形の面積を求める.
y
y
p1(1,3)
p1(-3,1)
p3(4,2)
p3(0,0)
O
O
p2(5,0)
x
x
p2(1,-2)
19
構造体利用時の注意




構造体と配列の使い分け
sizeof(構造体)
構造体とプログラミング
してはいけないこと
20
構造体と配列の使い分け

配列




構造体



入p.244
同一の型の集まり
各要素に番号がついている
ループなどを使って順番に処理する
様々な型の集まり(ただし,同一の型の集まりでもよい)
各要素に付けられた名前を使ってアクセスする
「配列を含む構造体」や「構造体の配列」もよく利用される.
21
sizeof(構造体)

sizeof(構造体) は,構造体の各メンバのサイズの合計
以上になる.

構造体オブジェクトの中で使用されない領域もあり得る.「パ
ディング」または「穴」と呼ばれる.
s:
c
struct s {
char c;
int i;
};
リp.373
パディング
i
sizeof(char) == 1
sizeof(int) == 4
でも sizeof(struct s) != 5
22
構造体とプログラミング

さまざまな種類の情報を持つ「実体」を一つのオブジェクトと
して処理したいとき,


まず,「何に処理をしたいか?」を考える.
• 保持すべき情報を細分化し,それぞれをメンバとするような
構造体を宣言する.
次に,「何の処理をしたいか?」を考える.
• 構造体を引数にとって処理する関数を定義する.
• 引数・戻り値ともに,型は構造体そのものにすべきか,
構造体のポインタにすべきか,そのつど検討する.
• 動作確認用に,構造体の中身を出力する関数も.
23
してはいけないこと

× 関数内のauto変数を指し示すポインタを,戻り値とする.




struct point *create_point(int x, int y)
{
struct point p = {x, y};
return &p;
}
コンパイルエラーにはならないが,実行時に支障をきたす.
関数処理が終わると,pの領域が破棄される
⇒ *(&p)が不定!
pをstatic変数とするか,mallocで実行時に領域を確保し
てそのポインタを返せば,問題を回避できる.
リpp.118-119
24
独自の型はどこで定義する?

一般には,グローバル区間で定義し,複数の関数間で利用
できるようにする.


#include文の後ろ,関数プロトタイプの前に書く.
ブロックの中で定義してもよい.

有効範囲は,そのブロックの終わりまで.
25
まとめ



独自の型(typedef,列挙型,構造体)を定義することで,
変数に持たせる意味がより明確になる.
構造体により,複数のデータからなるオブジェクトを創ること
ができる.
構造体を対象とする関数を定義するとき,(引数・戻り値の)
型は構造体そのものにすべきか,構造体のポインタにすべ
きか,そのつど検討する.
26
今後の予定

2007年12月17日(月):第11回授業






次回授業終了後すぐ,授業Webページにて,第2回レポート課
題を掲示します.
2008年1月10日(木):休講
2008年1月17日(木):第2回レポート提出期限
2008年1月21日(月):第12回授業
2008年1月28日(月):第13回授業
2008年1月30日(水):第14回授業
27