プログラミング入門II

第17章 その他の制御文
17.1
17.2
17.3
17.4
17.5
do-while文
goto文とラベル
break文による繰返し制御
continue文による繰返し制御
return文
17.1 do-while文
#include <stdio.h>
/* ex17_1_1.c */
int main(void)
{
int i;
条件を満たさなく
i = 0;
ても1回は実行
do {
printf("繰返し\n");
i = i + 1;
} while (i < 10);
return 0;
}
i = 10; とすると違いがわかる
p.161
例17.1.1
p.22
例5.1.1
#include <stdio.h>
/* ex5_1_1.c */
int main(void)
{
int i;
i = 0;
while (i < 10) {
printf("繰返し\n");
i = i + 1;
}
条件を満たす
return 0;
ときのみ実行
}
17.1 do-while文
p.162
例17.1.2
2) 12
#include <stdio.h>
2) 6...0
/* 整数の2進表現を下位から表示 */
2) 3...0
int main(void)
2) 1...1
{
0...1
int n, b;
while 文を使って
n = 12;
n = 0 としたとき
書き直せ
do {
どうなるか?
b = n % 2;
さらに…
printf("%d\n", b);
n = 0 としたときにも
n /= 2;
同じ結果を得るには
どうすればよいか?
} while (n > 0);
return 0;
}
17.2 goto文とラベル
#include <stdio.h>
/* ex17_2_1.c */
int main(void)
{
int i;
i = 0;
loop:
if (i >= 10) goto next;
printf("繰返し\n");
i = i + 1;
goto loop;
next:
return 0;
}
p.162
例17.2.1
p.22
例5.1.1
#include <stdio.h>
/* ex5_1_1.c */
int main(void)
{
int i;
i = 0;
while (i < 10) {
printf("繰返し\n");
i = i + 1;
}
return 0;
}
17.2 goto文とラベル
p.164
例17.2.2
#include <stdio.h>
#define MAX 10
/* ex17_2_2.c */
i2 + j2 = k2 を満たす自然数の組を探す
int main(void)
{
int i, j, k;
for (k = 1; k < MAX; k++) {
for (i = 1; i < k; i++) {
for (j = i; j < k; j++)
if (k * k == i * i + j * j) goto found;
}
}
printf("not found\n");
return 0;
found:
printf("%d * %d + %d * %d = %d * %d\n", i, i, j, j, k, k);
return 0;
}
p.166
例17.3.2
17.3 break文による繰返し制御
#include <stdio.h>
800未満の素数
#define MAX 800
10個ごとに改行
#define N
10
エラトステネスの篩(ふるい)
/* ex17_3_2.c */
int main(void)
{
int primes[MAX]; // 素数判定結果用配列
int i, j, p; // i: 範囲, p: 素数カウンタ
for (i = 2; i < MAX; i++) primes[i] = 1;
p = 0;
"真"で初期化
17.3 break文による繰返し制御
for (i = 2; i < MAX; i++) {
素数を印刷
if (primes[i]) {
N(=10)個ごとに改行
printf("%5d", i);
if ((++p) % N == 0) printf("\n");
ループの
100個めで強制終了
外に脱出 if (p == 100) break;
for (j = 2 * i; j < MAX; j += i)
primes[j] = 0; // 偽
ここで篩(ふるい)
にかけている
}
}
return 0;
break は、ループ(iのfor文)の外に出る
}
p.169
例17.4.2
17.4 continue文による繰返し制御
#include <stdio.h>
#define MAX 100
完全数を探し、その総和を求める
/* ex17_4_2.c */
int main(void)
{
int i, j, sum, total = 0;
for (i = 2; i < MAX; i++) {
sum = 0;
完全数: ある自然数に対して、その数以外の約数の和がその数に等しいもの
17.4 continue文による繰返し制御
for (j = 1; j < i; j++)
j が i の約数
if (i % j == 0) sum += j;
なら加算
if (sum != i) continue;
完全数でない
ならスルー
printf("%d\n", i);
total += i;
完全数なら印刷
}
printf("total = %d\n", total);
return 0;
}
continue は、ループ(iのfor文)の最後に飛ぶ
p.170
例17.5.1
17.5 return文
#include <stdio.h>
#define NEGATIVE (-1)
/* ex17_5_1.c */
int factorial(int x);
階乗の計算
int main(void)
{
int x, y;
printf("入力 = "); scanf("%d", &x);
y = factorial(x);
17.5 return文
if (y == NEGATIVE)
printf("負の数が入力されました\n");
else
入力値が負なら終了
printf("%d! = %d", x, y);
return 0;
}
入力値が正なら答えを印刷
17.5 return文
int factorial(int x)
階乗の計算ルーチン
{
int i, result = 1;
if (x < 0) return NEGATIVE;
if (x == 0) return result;
else {
for (i = 1; i <= x; i++) result *= i;
return result;
階乗計算
}
}
return は、その関数から抜けて、値を返す
第18章 マクロ
18.1 引数を持たないマクロ
18.2 引数を持つマクロ
デバッグ用マクロ
18.1 引数を持たないマクロ
p.172
例18.1.1
#define PI 3.1415926
ex18_1_1.c という名前で保存
#define WORD 32
#define ROOT sqrt
#define NEWLINE printf("\n")
int main(void)
{
double x, y;
int w;
x = PI * 2.0:
y = ROOT(x);
printf("%f\n", x);
NEWLINE;
w = WORD / 8;
}
18.1 引数を持たないマクロ
Z:\nyumon2> cl -E ex18_1_1.c
プリプロセッサの出力を表示
int main(void)
{
double x, y;
int w;
x = 3.1415926 * 2.0:
y = sqrt(x);
printf("%f\n", x);
printf("\n");
w = 32 / 8;
}
18.2 引数を持つマクロ
p.174
例18.2.1
#include <stdio.h>
#define larger(x, y) (((x) > (y)) ? (x) : (y))
#define smaller(x, y) (((x) < (y)) ? (x) : (y))
int main(void)
{
int x[] = {6, 10, 4, 1, 3, 9, 11, 3, 20, 3, 4, 4, 6,
int n = sizeof x / sizeof x[0];
int i, max, min;
max = min = x[0];
if (max > x[i]) max
for (i = 1; i < n; i++) {
else
max
max = larger(max, x[i]);
min = smaller(min, x[i]);
if (min < x[i]) min
}
else
min
printf("最大値 = %d\n", max);
printf("最小値 = %d\n", min);
return 0;
}
3, 2};
= max;
= x[i];
= min;
= x[i];
デバッグ用マクロ




__FILE__: ファイル名(文字列)
__LINE__: コードの行数(整数)
__DATE__: コンパイルの日付(文字列)
__TIME__: コンパイルの時間(文字列)
定義の例


#define CLINE printf(__FILE__":%d\n",__LINE__)
#define DTIME printf(__DATE__" ["__TIME__"]\n")
デバッグ用マクロ
#include <stdio.h>
#include <math.h>
#define CLINE(x) fprintf(stderr,__FILE__":%d\n",__LINE__)
int main(void)
{
double a = 1, b = 0, c = -1;
printf("ここまでOK?\n"); CLINE;
printf("a / b = %f\n", a / b); CLINE;
printf("sqrt(c) = %f\n",sqrt(c)); CLINE;
return 0;
}
テスト用関数 assert()
#include <stdio.h>
コメントをはずせばassertが無効に…
//#define NDEBUG
assert用ヘッダファイル
#include <assert.h>
#define VERSION printf(__FILE__": "__DATE__" ["__TIME__"]\n")
int main(void)
{
double a=1, b=0, c;
VERSION;
printf("ここまでOK?\n");
assert( b != 0 ); // 条件を満たさない場合に異常終了
c = a / b;
printf("a / b = %f\n", c);
return 0;
}
ゲームの準備
乱数の発生(再掲)
制御コード
WAVファイルの再生
列挙型
system関数
■ 乱数の発生



p.183
int rand(void)
 疑似乱数の発生
 範囲:0~RAND_MAX(=32767)
 <stdlib.h>内で宣言
void srand(unsigned n)
 疑似乱数のシード(種)の指定・変更
 <stdlib.h>内で宣言
time_t time(time_t *timer)
 経過時間を秒単位で表した数値
 引数は NULL (空ポインタ)でよい
 <time.h>内で宣言
現在時間を使って
乱数の種を決定
サイコロ・プログラム(dice.c)
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
int i;
/* 実行するたびに違う値が得られるように、
* 現在の時刻値を使って乱数ジェネレータを初期化 */
srand((unsigned)time(NULL));
/* サイコロを10回振る */
for (i = 0; i < 10; i++)
printf("%d ", (rand() % 6) + 1); // 6の剰余系+1
printf("\n");
return 0;
}
■ 制御コード

教科書 p.180, 表A.2: 制御コード






\a ベル・警告音の出力
\r 行頭に戻る(キャリッジ・リターン)
\f そのままの位置で行送り(ライン・フィード)
\n 改行(\r\f)
\t 水平タブ
使用例


putchar('\a');
printf("現在 %d 回目\r\a", i);
サイコロ・プログラム2(dice2.c)
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int i, n, m;
/* 現在の時刻値を使って乱数ジェネレータを初期化 */
srand((unsigned)time(NULL));
printf(" ---\n");
n = rand() % 6; m = n + 8 + rand() % 10;
for (i = n; i < m; i++)
n=0~5
m = n+8 ~ n+17
printf("\r| %d |\a", i % 6 + 1);
printf("\n ---\n");
1回の alert に約200 ms かかる
return 0;
→ このサイコロは1.6 ~3.4秒間転がる
}
WAVファイルの再生
/* WAVファイルの再生 */
#include <windows.h>
#pragma comment(lib,"winmm") // winmm.lib をリンクする
int main(void)
{
if (!PlaySound("kidou.wav", 0, SND_FILENAME))
printf("The sound didn't play.");
if (!PlaySound("shuryo.wav", 0, SND_FILENAME))
printf("The sound didn't play.");
return 0;
}
C:\WINDOWS\Media フォルダにシステムが用いるサウンドファイルがある。
C:\Program Files\Microsoft Office\OFFICE11\MEDIA フォルダ
■ 列挙型



名前付き定数をゼロからの整数に対応させる
enum タグ {列挙子リスト};
例:
enum DAYS {
SUNDAY, MONDAY, ..., SATURDAY
};
実体→
0,
1,
...,
6
■ system関数



OS(コマンドプロンプト)のコマンドをプログラム
の中から実行できる。
system("cls") で画面クリア
#include <stdlib.h> が必要
■スキルアップタイム

「地底探検ゲーム」のプログラムにおいて、地底
マップを毎回描き換えるようにsystem関数を用
いて改良せよ。
本日のパズル
このプログラムは何を出力するか
#include <stdio.h>
#define PRINT2(fmt,x1,x2) printf("%"#fmt", %"#fmt"\n",x1,x2)
int main(void)
{
static struct S1 {char c[4], *s;} s1 = { "abc", "def" };
static struct S2 {char *cp; struct S1 ss1;
} s2 = { "ghi", { "jkl", "mno" } };
PRINT2(c,
PRINT2(s,
PRINT2(s,
PRINT2(s,
return 0;
}
s1.c[0], *s1.s);
s1.c, s1.s);
s2.cp, s2.ss1.s);
++s2.cp, ++s2.ss1.s);
1.
2.
3.
4.