第17章 その他の制御文 17.1 do-while文 17.2 goto文とラベル 17.3 break文による繰返し制御 17.4 continue文による繰返し制御 17.5 return文
17.1 do-while文 #include <stdio.h> /* ex17_1_1.c */ p.161 例17.1.1 p.22 例5.1.1 #include <stdio.h> /* ex17_1_1.c */ int main(void) { int i; i = 0; do { printf("繰返し\n"); i = i + 1; } while (i < 10); return 0; } #include <stdio.h> /* ex5_1_1.c */ int main(void) { int i; i = 0; while (i < 10) { printf("繰返し\n"); i = i + 1; } return 0; 条件を満たさなくても1回は実行 条件を満たすときのみ実行 i = 10; とすると違いがわかる
17.1 do-while文 2) 12 #include <stdio.h> 2) 6...0 p.162 例17.1.2 2) 12 2) 6...0 2) 3...0 2) 1...1 0...1 #include <stdio.h> /* 整数の2進表現を下位から表示 */ int main(void) { int n, b; n = 12; do { b = n % 2; printf("%d\n", b); n /= 2; } while (n > 0); return 0; } while 文を使って 書き直せ n = 0 としたとき どうなるか? さらに… n = 0 としたときにも 同じ結果を得るには どうすればよいか?
17.2 goto文とラベル #include <stdio.h> /* ex17_2_1.c */ p.162 例17.2.1 p.22 例5.1.1 #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; } #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 i2 + j2 = k2 を満たす自然数の組を探す #include <stdio.h> #define MAX 10 /* ex17_2_2.c */ 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); i2 + j2 = k2 を満たす自然数の組を探す
17.3 break文による繰返し制御 #include <stdio.h> #define MAX 800 p.166 例17.3.2 17.3 break文による繰返し制御 #include <stdio.h> #define MAX 800 #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; 800未満の素数 10個ごとに改行 エラトステネスの篩(ふるい) "真"で初期化
17.3 break文による繰返し制御 for (i = 2; i < MAX; i++) { if (primes[i]) { printf("%5d", i); if ((++p) % N == 0) printf("\n"); if (p == 100) break; for (j = 2 * i; j < MAX; j += i) primes[j] = 0; // 偽 } return 0; 素数を印刷 N(=10)個ごとに改行 ループの 外に脱出 100個めで強制終了 ここで篩(ふるい)にかけている break は、ループ(iのfor文)の外に出る
17.4 continue文による繰返し制御 #include <stdio.h> #define MAX 100 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++) if (i % j == 0) sum += j; if (sum != i) continue; printf("%d\n", i); total += i; } printf("total = %d\n", total); return 0; j が i の約数なら加算 完全数でないならスルー 完全数なら印刷 continue は、ループ(iのfor文)の最後に飛ぶ
17.5 return文 #include <stdio.h> #define NEGATIVE (-1) p.170 例17.5.1 #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.1 引数を持たないマクロ 18.2 引数を持つマクロ デバッグ用マクロ 第18章 マクロ 18.1 引数を持たないマクロ 18.2 引数を持つマクロ デバッグ用マクロ
18.1 引数を持たないマクロ #define PI 3.1415926 #define WORD 32 #define ROOT sqrt 例18.1.1 #define PI 3.1415926 #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; } ex18_1_1.c という名前で保存
18.1 引数を持たないマクロ Z:\nyumon2> cl -E ex18_1_1.c int main(void) { プリプロセッサの出力を表示 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 引数を持つマクロ #include <stdio.h> 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, 3, 2}; int n = sizeof x / sizeof x[0]; int i, max, min; max = min = x[0]; for (i = 1; i < n; i++) { max = larger(max, x[i]); min = smaller(min, x[i]); } printf("最大値 = %d\n", max); printf("最小値 = %d\n", min); return 0; if (max > x[i]) max = max; else max = x[i]; if (min < x[i]) min = min; else 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> //#define NDEBUG #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; } コメントをはずせばassertが無効に… assert用ヘッダファイル
乱数の発生(再掲) 制御コード WAVファイルの再生 列挙型 system関数 ゲームの準備 乱数の発生(再掲) 制御コード WAVファイルの再生 列挙型 system関数
■ 乱数の発生 int rand(void) 疑似乱数の発生 範囲:0~RAND_MAX(=32767) p.183 int rand(void) 疑似乱数の発生 範囲:0~RAND_MAX(=32767) <stdlib.h>内で宣言 void srand(unsigned n) 疑似乱数のシード(種)の指定・変更 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++) printf("\r| %d |\a", i % 6 + 1); printf("\n ---\n"); return 0; } n = 0 ~ 5 m = n+8 ~ n+17 1回の alert に約200 ms かかる → このサイコロは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)) return 0; } C:\WINDOWS\Media フォルダにシステムが用いるサウンドファイルがある。 C:\Program Files\Microsoft Office\OFFICE11\MEDIA フォルダ
■ 列挙型 名前付き定数をゼロからの整数に対応させる enum タグ {列挙子リスト}; 例: 実体→ 0, 1, ..., 6 実体→ 0, 1, ..., 6 enum DAYS { SUNDAY, MONDAY, ..., SATURDAY };
■ 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, s1.c[0], *s1.s); PRINT2(s, s1.c, s1.s); PRINT2(s, s2.cp, s2.ss1.s); PRINT2(s, ++s2.cp, ++s2.ss1.s); return 0; } 1. 2. 3. 4.