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 />
}