21.01.2015 Views

第7回(6/4)

第7回(6/4)

第7回(6/4)

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

TORU WAKAHARA<br />

第 7 回 (6/4)<br />

2. 構 造 体<br />

構 造 体 とは, 同 じ 型 に 限 定 されない 複 数 の 関 連 するデータメンバの 集 合 である。<br />

・ 構 造 体 の 宣 言 構 造 体 指 定 子 struct を 用 いて<br />

struct 構 造 体 タグ 名 {<br />

メンバ 1 の 宣 言 ;<br />

メンバ 2 の 宣 言 ;<br />

…<br />

メンバ n の 宣 言 ;<br />

};<br />

注 ) 構 造 体 タグ 名 は 構 造 体 の 型 名 で, 内 容 を 定 義 するものでオブジェクトではなく,<br />

論 理 的 なテンプレートである。<br />

・ 構 造 体 の 変 数 の 宣 言 実 際 の 記 憶 領 域 を 占 める 物 理 的 実 体 を 確 保 する。<br />

struct 構 造 体 タグ 名 変 数 リスト;<br />

または 構 造 体 の 宣 言 と 合 わせて<br />

struct 構 造 体 タグ 名 {<br />

メンバ 1 の 宣 言 ;<br />

メンバ 2 の 宣 言 ;<br />

…<br />

メンバ n の 宣 言 ;<br />

} 変 数 リスト;<br />

あるいは<br />

struct {<br />

メンバ 1 の 宣 言 ;<br />

メンバ 2 の 宣 言 ;<br />

…<br />

メンバ n の 宣 言 ;<br />

} 変 数 リスト;


TORU WAKAHARA<br />

例 . 構 造 体 の 宣 言 と 初 期 化<br />

struct sintai {<br />

char *name;<br />

int sinchou;<br />

int taijuu;<br />

};<br />

struct sintai a = {"Jack", 180, 66 },<br />

b = {"Betty", 172, 59 };<br />

・ 構 造 体 の 参 照 ドット 演 算 子 を 用 いて<br />

構 造 体 の 変 数 名 .メンバ 名<br />

構 造 体 配 列 の 要 素 .メンバ 名<br />

ex. a.taijuu<br />

ex. constel[i].name<br />

・ 構 造 体 に 対 する 演 算 同 じ 型 を 持 った 構 造 体 間 では 代 入 演 算 子 が 使 用 できてメンバ 全 部<br />

の 複 写 ができる。<br />

ex. sa = sb;<br />

・ 関 数 との 関 係 構 造 体 は,ほかの 型 の 値 とまったく 同 じように, 関 数 への 仮 引 数 として<br />

渡 すことができる。また, 関 数 の 戻 り 値 として, 構 造 体 を 返 すこともできる。


TORU WAKAHARA<br />

例 . 構 造 体 のメンバにアクセスするいくつかの 方 法 を 示 す。<br />

#include <br />

struct s_type {<br />

int i;<br />

char ch;<br />

double d;<br />

char str[80];<br />

} s;<br />

int main()<br />

{<br />

printf(" 整 数 を 入 力 して 下 さい:\n");<br />

scanf("%d", &s.i);<br />

printf(" 文 字 を 入 力 して 下 さい:\n");<br />

scanf("\n%c, &s.ch);<br />

printf(" 浮 動 小 数 点 数 を 入 力 して 下 さい:\n");<br />

scanf("%lf", &s.d);<br />

printf(" 文 字 列 を 入 力 して 下 さい:\n");<br />

scanf("%s", s.str);<br />

printf("%d %c %f %s\n", s.i, s.ch, s.d, s.str);<br />

}<br />

return 0;


TORU WAKAHARA<br />

例 . 構 造 体 のサイズを 調 べる。<br />

#include <br />

struct s_type {<br />

int i;<br />

char ch;<br />

int *p;<br />

double d;<br />

} s;<br />

int main()<br />

{<br />

printf("s_type は %d バイトの 長 さである\n", sizeof(struct s_type));<br />

}<br />

return 0;<br />

☆ s_type のサイズを 求 めるのに,sizeof(struct s_type) 以 外 の 書 き 方 は


TORU WAKAHARA<br />

・ 構 造 体 へのポインタの 宣 言 構 造 体 にアクセスするにはポインタを 利 用 するのが 一 般 的<br />

な 方 法 である。 構 造 体 を 指 すポインタを 用 いて 構 造 体 のメンバにアクセスするときは,<br />

アロー 演 算 子 ( -> )を 使 用 する。<br />

例 . 構 造 体 を 指 すポインタの 扱 い 方 を 示 す。<br />

#include <br />

#include <br />

struct s_type {<br />

int i;<br />

char str[80];<br />

} s, *p;<br />

int main()<br />

{<br />

p = &s;<br />

s.i = 10;<br />

p->i = 15;<br />

strcpy(p->str, "I like structure");<br />

printf("%d %d %s\n", s.i, p->i, p->str);<br />

}<br />

return 0;


TORU WAKAHARA<br />

・ビットフィールド 構 造 体 の 便 利 な 機 能 として,ビット 単 位 でデータを 取 り 扱 うことが<br />

できるビットフィールドがある。<br />

構 造 体 メンバとしてビットフィールドを 定 義 するには 次 の 書 式 を 用 いる。<br />

型 名 前 :サイズ;<br />

但 し,「 型 」は int または unsigned<br />

signed の 場 合 , 最 上 位 ビットは 符 号 ビットと 見 なされる。<br />

移 植 可 能 にするには,signed あるいは unsigned と 明 示 的 に 指 定 すべきである。<br />

「サイズ」はフィールドでのビット 数<br />

ビットフィールドを 参 照 するには, 通 常 の 構 造 体 と 同 じように「.」または<br />

「->」 演 算 子 によってメンバを 指 定 する。<br />

例 .ビットフィールドと 他 の 型 を 混 在 させることが 可 能 であり,またバイトやワードのす<br />

べてのビットが 埋 まるように 定 義 する 必 要 はない。<br />

struct b_type {<br />

char name[40]; /* 品 目 名 */<br />

unsigned int instock: 1; /* 在 庫 があれば 1, 在 庫 切 れなら 0 */<br />

unsigned int backordered: 1; /* 未 納 注 文 であれば 1, 納 品 済 みなら 0 */<br />

unsigned int lead_time: 3; /* 発 注 から 納 品 までの 月 数 (7 ヶ 月 まで) */<br />

} inv[MAX_ITEM];<br />

注 )メモリのアドレス 可 能 な 最 小 単 位 はバイトであるため,ビットフィールド 変 数 の<br />

アドレスを 得 ることはできない。<br />

ビットフィールドには,ブール( 真 / 偽 ) 型 のデータを 格 納 することがよくある。<br />

1 バイトに 8 個 のブール 型 の 値 を 格 納 できる。


TORU WAKAHARA<br />

《 補 足 例 題 》a, b, c の3つのビットフィールドを 持 つ 構 造 体 (タグ 名 b_type, 変 数 名 bvar)<br />

を 使 ったプログラムを 作 りなさい。a と b は 3 ビットの 長 さとし,c は 2 ビットの 長 さと<br />

する。また,すべて signed 変 数 とする。 次 に,bvar の a, b, c にそれぞれ 値 -1, 3, 1<br />

を 代 入 し,その 値 を 表 示 しなさい。<br />

#include <br />

main()<br />

{<br />

struct b_type {<br />

signed int a: 3; /* a, b, c それぞれ 表 現 できる 値 の 範 囲 は */<br />

signed int b: 3;<br />

signed int c: 2;<br />

} bvar;<br />

}<br />

bvar.a = -1; /* -5 を 代 入 するとどうなるか */<br />

bvar.b = 3;<br />

bvar.c = 1; /* 3 を 代 入 するとどうなるか */<br />

printf("%d %d %d\n", bvar.a, bvar.b, bvar.c);<br />

printf("size of b_type = %d\n", sizeof(struct b_type));


TORU WAKAHARA<br />

・ 共 用 体 複 数 のメンバが 同 じメモリの 領 域 を 共 通 して 使 用 するように 配 置 された 単 一 の<br />

メモリ 領 域 のことを 指 す。<br />

メモリを 共 用 する 変 数 は, 型 が 異 なってもいいが, 一 度 に1つの 変 数 しか 使 用<br />

できない。 共 用 体 指 定 子 union を 用 いて 次 の 書 式 で 宣 言 する。<br />

union 共 用 体 タグ 名 {<br />

メンバ 1 の 宣 言 ;<br />

メンバ 2 の 宣 言 ;<br />

…<br />

メンバ n の 宣 言 ;<br />

} 変 数 名 ;<br />

注 )タグ 名 , 変 数 名 のいずれかを 省 略 することができる。<br />

例 .<br />

union u_type {<br />

int i;<br />

char c[4];<br />

double d;<br />

} sample, *p;<br />

←―――――――――――――――――――― d ―――――――――――――――――<br />

――――――→<br />

c[0] c[1] c[2] c[3]<br />

← i →<br />

共 用 体 のメンバを 参 照 するには, 構 造 体 と 同 様 ,ドット 演 算 子 もしくはアロー 演 算 子 を<br />

使 用 する。


TORU WAKAHARA<br />

《 注 意 》<br />

共 用 体 のサイズは, 最 も 大 きいメンバのサイズとなるが,コンパイラがワード 境 界 で<br />

そろえることがあり,sizeof 演 算 子 で 確 認 した 方 がよい。また, 一 度 に1つの 変 数 し<br />

か 使 用 できないことに 注 意 しよう。<br />

#include <br />

main()<br />

{<br />

union u_type {<br />

int i;<br />

char c[4];<br />

double d;<br />

} sample, *p;<br />

}<br />

p = &sample;<br />

sample.i = 1234;<br />

printf("int i : %d\n", sample.i);<br />

p->c[0] = 'O';<br />

p->c[1] = 'K';<br />

p->c[2] = '\0';<br />

printf("char c[4] : %s\n", sample.c);<br />

p->d = 12.34;<br />

printf("double d : %f\n", sample.d);<br />

printf("size of b_type = %d\n", sizeof(union u_type));


TORU WAKAHARA<br />

例 題 3-2<br />

生 まれた 月 と 日 を 入 力 し, 星 座 が 何 であるかを 出 力 するプログラムをつくりなさい。た<br />

だし, 誕 生 日 と 星 座 の 関 係 は 次 のとおりである。<br />

山 羊 (12/13~1/20), 水 瓶 (~2/18), 魚 (~3/20), 牡 羊 (~4/20), 牡 牛 (~5/21),<br />

双 子 (~6/21), 蟹 (~7/23), 獅 子 (~8/23), 乙 女 (~9/23), 天 秤 (~10/23),<br />

さそり(~11/22), 射 手 (~12/22)<br />

▼ 出 力 結 果 3-2<br />

何 月 生 まれですか<br />

3↵<br />

何 日 生 まれですか<br />

26↵<br />

3 月 26 日 生 まれの<br />

あなたは, 牡 羊 座 です


TORU WAKAHARA<br />

▼プログラム3-2<br />

01 /* E3-2 */<br />

02 /* 星 座 調 べ */<br />

03 #include <br />

04<br />

05 struct {<br />

06 char name[9];<br />

07 int date;<br />

08 } constel[] = { " 山 羊 ", 120, " 水 瓶 ", 218, " 魚 ", 320,<br />

09 " 牡 羊 ", 420, " 牡 牛 ", 521, " 双 子 ", 621,<br />

10 " 蟹 ", 723, " 獅 子 ", 823, " 乙 女 ", 923,<br />

11 " 天 秤 ", 1023, "さそり", 1122,<br />

12 " 射 手 ", 1222, " 山 羊 ", 1231 };<br />

13<br />

14 main()<br />

15 {<br />

16 int i, month, day, nconstel;<br />

17<br />

18 printf("\n 何 月 生 まれですか\n");<br />

19 scanf("%d", &month);<br />

20 printf(" 何 日 生 まれですか\n");<br />

21 scanf("%d", &day);<br />

22 nconstel = sizeof constel / sizeof constel[0]; /* 配 列 の 要 素 数 */<br />

23 for (i = 0; i < nconstel; i++) {<br />

24 if (month * 100 + day


TORU WAKAHARA<br />

練 習 問 題 25<br />

1. 例 題 3-2のプログラムでは,12 月 32 日 などが 入 力 されると 正 しい 結 果 が 得 られない。<br />

これを 防 止 するため, 誤 った 月 日 のデータが 入 力 された 場 合 は 再 度 入 力 させるようにプ<br />

ログラムを 変 更 しなさい。<br />

《ヒント》 各 月 が 何 日 まであるかを 格 納 した 配 列 を 用 意 して 利 用 しなさい。<br />

2. 前 問 1.において, 構 造 体 のメンバに 対 して,<br />

constel[i].data<br />

constel[i].name<br />

と 記 述 しているのを,-> 演 算 子 によって 記 述 するようにプログラムを 変 更 しなさい。<br />

《ヒント》 構 造 体 へのポインタを 宣 言 して,これを 用 いなさい。


TORU WAKAHARA<br />

3. 姓 , 名 , 年 齢 , 郵 便 番 号 , 電 話 番 号 の 各 データをメンバとする 構 造 体 配 列 を 下 記 のよ<br />

うに 宣 言 し,その 構 造 体 配 列 にキーボードからデータを 逐 次 入 力 して, 最 大 100 名 のデ<br />

ータを 格 納 できるようにしなさい。 但 し, 入 力 の 終 了 は, 姓 入 力 の 際 に null と 入 力 する<br />

ことによって 判 定 しなさい。また, 入 力 が 終 了 した 時 点 で, 格 納 された 複 数 名 のデータ<br />

をすべて 出 力 するようにしなさい。<br />

#define MAXREC 100<br />

struct namelist {<br />

char last_name[21], first_name[21];<br />

int age;<br />

char zip[9], tel[13];<br />

} meibo[MAXREC];<br />

▼ 出 力 例<br />

Last name( 終 了 は null 入 力 )> Natsume↵<br />

First name > Soseki↵<br />

Age > 49↵<br />

Zip code > 123-4567↵<br />

Telephone > 0120-1234567↵<br />

Last name( 終 了 は null 入 力 )> null↵<br />

Name : Soseki Natsume<br />

Age : 49<br />

Zip code : 123-4567<br />

Telephone: 0120-1234567


TORU WAKAHARA<br />

4. 前 問 において, 入 力 が 終 了 した 時 点 で, 格 納 された 複 数 名 のデータを 郵 便 番 号 順 に 出<br />

力 するようにプログラムを 変 更 しなさい。<br />

《ヒント》 構 造 体 struct namelist へのポインタおよび 格 納 した 人 数 を 仮 引 数 として, 郵<br />

便 番 号 順 にデータの 並 べ 替 えを 行 う 次 のような 関 数<br />

void namelist_sort(struct namelist *pnt, int count)<br />

を 作 りなさい。<br />

以 前 に 解 いた 次 の 問 題 が 参 考 になります。<br />

================================================================================<br />

[ 参 考 ] 練 習 問 題 20<br />

ポインタの 配 列 (*name[10])を 宣 言 し, 次 のような 名 前 を 10 個 セットしなさい。<br />

"taro", "jiro", "hanako", "hirosi", …… "keiko"<br />

この 名 前 をアルファベット 順 に 整 列 ( 並 べ 換 え)させるプログラムをポインタへのポ<br />

インタを 使 ってつくりなさい。<br />

《ヒント》 文 字 列 の 比 較 にはライブラリ 関 数 の strcmp(s1, s2)を 利 用 すればよい。<br />

この 関 数 の 戻 り 値 は, 次 のようになる。<br />

s1 > s2 のとき, 0 より 大 きい 整 数<br />

s1 = s2 のとき, 0<br />

s1 < s2 のとき, 0 より 小 さい 整 数<br />

================================================================================


TORU WAKAHARA<br />

5.( 難 問 ) 共 用 体 を 用 いて,2 バイト 整 数 の 上 下 バイトを 入 れ 換 えて 暗 号 化 する 関 数 short<br />

encode(short)を 作 り,キーボードから 入 力 した 整 数 を 暗 号 化 / 復 号 化 するプログラムを<br />

作 りなさい。 但 し,main 関 数 の 部 分 は 次 のコードを 用 いなさい。<br />

/* 関 数 のプロトタイプ 宣 言 */<br />

short encode(short);<br />

main()<br />

{<br />

int n, m, k;<br />

}<br />

while (1) {<br />

printf(" 整 数 を 入 力 して 下 さい( 終 了 は 0) = ");<br />

scanf("%d", &n);<br />

if (n == 0) break;<br />

m = encode(n); /* 暗 号 化 */<br />

printf("\n\t%d を 暗 号 化 すると %d になります。\n", n, m);<br />

k = encode(m); /* 復 号 化 */<br />

printf("\n\t%d を 復 号 化 すると %d になります。\n\n", m, k);<br />

}<br />

▼ 出 力 例<br />

整 数 を 入 力 して 下 さい( 終 了 は 0)= 123↵<br />

123 を 暗 号 化 すると 31488 になります。<br />

31488 を 復 号 化 すると 123 になります。<br />

整 数 を 入 力 して 下 さい( 終 了 は 0)= -123↵<br />

-123 を 暗 号 化 すると-31233 になります。<br />

-31233 を 復 号 化 すると-123 になります。<br />

整 数 を 入 力 して 下 さい( 終 了 は 0)= 0↵


TORU WAKAHARA<br />

6.( 超 難 問 ) 整 数 係 数 の 多 項 式 について,その 次 数 と 係 数 をキーボードから 入 力 して 連 結<br />

リストに 格 納 してみましょう。 次 に, 格 納 された 多 項 式 を 画 面 に 出 力 します。 最 後 に,X<br />

の 実 数 値 をキーボードから 入 力 して 多 項 式 の 値 を 求 めてみましょう。 多 項 式 の 次 数 と 係 数<br />

を 表 現 する 構 造 体 ,および 必 要 な 関 数 のプロトタイプ 宣 言 を 次 に 示 します。 出 力 例 を 参 考<br />

にして,プログラムを 完 成 してみましょう。<br />

typedef struct Node {<br />

int pow; /* 次 数 */<br />

int coe; /* 整 数 係 数 */<br />

struct Node *next; /* 次 のノードを 指 すポインタ */<br />

} node;<br />

node *start = NULL; /* 先 頭 ノードを 指 すポインタで 最 初 は 空 , 外 部 変 数 */<br />

void insert(int pow, int coe); /* 次 数 と 係 数 をノードとして 挿 入 */<br />

void show_poly(); /* 連 結 リストに 格 納 された 多 項 式 の 表 示 */<br />

double horner(double x); /* 実 数 x に 対 する 多 項 式 の 値 の 算 出 */<br />

▼ 出 力 例<br />

整 数 次 数 の 多 項 式 を 入 力 します!<br />

最 大 次 数 を 入 力 してください:5↵<br />

小 さい 次 数 から 整 数 係 数 を 順 に 入 力 してください<br />

X^0 の 整 数 係 数 :-1↵<br />

X^1 の 整 数 係 数 :2↵<br />

X^2 の 整 数 係 数 :3↵<br />

X^3 の 整 数 係 数 :0↵<br />

X^4 の 整 数 係 数 :0↵<br />

X^5 の 整 数 係 数 :-1↵


TORU WAKAHARA<br />

多 項 式 は 次 の 通 り<br />

-X^5+3X^2+2X-1<br />

X の 値 を 入 力 してください:0.8↵<br />

多 項 式 の 値 は 2.192320 です<br />

《ヒント》 次 のプログラムは,キーボードから 整 数 を 順 に 読 み 込 んで,それらを 連 結 リス<br />

トに 格 納 して, 最 後 にそれらを 入 力 と 逆 順 に 表 示 するものです。これを 参 考 に, 連 結 リ<br />

ストの 扱 いを 理 解 して, 上 記 問 題 のプログラムを 作 成 してみなさい。<br />

/* キーボードから 整 数 を 読 み, 連 結 リストに 格 納 */<br />

#include <br />

#include <br />

typedef struct Node {<br />

int num;<br />

struct Node *next;<br />

} node;<br />

node *start = NULL;<br />

void ins(int x);<br />

main()<br />

{<br />

int x;<br />

node *p;<br />

printf(" 整 数 を 空 白 で 区 切 って 入 力 してください\n");<br />

printf(" 終 了 には 数 字 以 外 の 文 字 を 入 力 します\n\n");<br />

while (scanf("%d", &x) == 1)<br />

ins(x);<br />

printf("\n 入 力 された 数 字 を 逆 順 に 表 示 します\n");


TORU WAKAHARA<br />

}<br />

for (p = start; p != NULL; p = p->next)<br />

printf("%5d\n", p->num);<br />

void ins(int x)<br />

{<br />

node *p = start;<br />

start = (node *)malloc(sizeof(node));<br />

if (start == NULL)<br />

puts("メモリ 不 足 です\n"), exit(1);<br />

start->num = x;<br />

start->next = p;<br />

}

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!