C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門...

84
C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。) 1

Transcript of C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門...

Page 1: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

C言語入門 第15週

プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

情報処理言語Ⅰ(実習を含む。)

1

Page 2: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

乱数

サイコロを振るようにランダムな値を得る

2

Page 3: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

乱数: ランダムな数値を得る

• rand 関数 : 疑似乱数整数の生成

• srand 関数 : 疑似乱数系列の初期化

• time 関数 : 現在時刻の取得 毎回違う値を得るため 乱数系列初期化に用いる

3 教科書 p.318, 322.

Page 4: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

rand 関数

• int rand(void) • [0:RAND_MAX]の範囲で整数の疑似乱数を返す

• 戻り値: • 疑似乱数の整数を返す

• 値の範囲は 0 以上 RAND_MAX 以下

• RAND_MAX は stdlib.h で定義されている

• RAND_MAX は少なくとも 32767 以上である

• RAND_MAX + 1 はオーバーフローするかもしれない

4

JM / rand(3)

教科書 p.322.

Page 5: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

srand 関数

• void srand(unsigned int seed)

• 疑似乱数系列の初期化を行う

• 引数:

• seed: 疑似乱数の新しい系列の種 初期値は1

• 同じ種からは毎回同じ疑似乱数系列が生成される。

5

JM / rand(3)

教科書 p.322.

Page 6: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

疑似乱数とは?

• 演算で生成する疑似的な乱数

• POSIX 1003.1-2003 で挙げられている実装例

static unsigned long next = 1; /* RAND_MAX を 32767 と仮定 */ int myrand(void) { next = next * 1103515245 + 12345; return((unsigned)(next/65536) % 32768); } void mysrand(unsigned int seed) { next = seed; }

計算式は決まっているので、 同じseedなら 毎回同じ計算になるため 毎回同じ乱数系列が生成される

6

Page 7: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

乱数系列の確認

• seed の値で乱数系列がどうなるか確認

7

rand_ex1.c int seed, i; printf("seed = "); scanf("%d", &seed); srand(seed); printf("RAND_MAX: %d¥n", RAND_MAX); for (i = 0; i < 10; i++) { printf("%d¥n", rand()); }

乱数系列の初期化

6 7 8 9

10 11 12 13 14 15 16

Cygwin64 mintty + bash $ gcc rand_ex1.c && ./a seed = 1 RAND_MAX: 2147483647 1481765933 1085377743 1270216262 1191391529 812669700 553475508 445349752 1344887256 730417256 1812158119

seed が同じなら 毎回同じ乱数系列が生成される

Page 8: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

乱数の初期化

実行毎に異なる乱数を得る

8

Page 9: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

実行毎に異なる乱数系列に初期化

• seed の値で乱数系列がどうなるか確認

9

rand_ex2.c int i; srand(time(NULL)); printf("RAND_MAX: %d¥n", RAND_MAX); for (i = 0; i < 10; i++) { printf("%d¥n", rand()); }

6 7 8 9

10 11 12 13

Cygwin64 mintty + bash $ gcc rand_ex2.c && ./a RAND_MAX: 2147483647 408068090 654635880 1819541412 1080013827 1356279002 1536746152 352225876 1197042546 1830476305 459739427

毎回 seed が異なるため 毎回違う乱数系列が生成される

time関数は 現在時刻を返す関数

Page 10: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

time 関数

• time_t time(time_t *t)

• 現在時刻を UNIX time で得る

• 引数:

• t: 通常はNULLで良い NULLでない場合*tにも戻り値を格納する

• 戻り値:

• 現在時刻を UNIX time で返す。

10

JM / time(2)

教科書 p.318.

Page 11: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

UNIX time (UNIX時間、UNIX時刻)

• UNIX epoch (UNIX 紀元) • 1970-01-01 00:00:00 UTC

• UNIX time • UNIX epoch からの経過秒数

• 2038年問題 • 2038-01-19 03:14:07 UTC

= UNIX time: 2,147,483,647秒 = UNIC time: 0x7fffffff秒

• time_tが符号付き32bitの環境でオーバーフロー

11

EppochConverter

Page 12: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

2038年問題

• 2038-01-19 03:14:07 UTC = UNIX time: 2,147,483,647秒 = UNIC time: 0x7fffffff秒

• time_t が符号付き 32bit の環境

• time_t がオーバーフロー

• 以降、正しい日時が処理できなくなる!

• 対策

• time_t の 64bit 化等の対応が必要

12

Page 13: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

未対策の環境はあるのか?

• SOURCEFORGE.JP MAGAZINE / 2014-05-02: 2038年問題に対応した「OpenBSD 5.5」リリース

• http://sourceforge.jp/magazine/14/05/02/160000

• OpenBSD はセキュリティ面で非常に定評のある OS

• そんな OS でもつい最近になってようやく対応している状況もある。

13

Page 14: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

time_t の確認

• 0x7fffffff秒,0x80000000秒,-1秒を確認

time_t_test.c char buf[1024]; time_t t = 0x7fffffff; struct tm *tm; printf("sizeof(time_t): %d¥n", sizeof(time_t)); printf("time_t has sign: %s¥n", (~(time_t) 0) < (time_t) 0 ? "YES" : "NO"); tm = gmtime(&t); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm); printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf); t++; tm = gmtime(&t); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm); printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf); t = -1; tm = gmtime(&t); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S UTC", tm); printf("%20luUL: %11ldL: %s¥n", (unsigned long) t, (long) t, buf);

14

Page 15: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

strftime 関数

• size_t strftime(char *s, size_t max, const char *format, const struct tm *tm) • 日付と時刻を文字列に変換する

• 引数: • s: 変換結果の格納先(通常はchar型配列) • max: sのサイズ • format: 変換の書式 • tm: time_t 型の値をlocaltime関数または gmtime関数を用いて変換した日付と時刻情報

• 戻り値: • 終端文字列'¥0'を含めた変換結果のサイズ • 格納先のサイズが不足していた場合は0

15

JM / strftime(3) JM / ctime(3)

Page 16: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

各環境のtime_tの状況

16

Cygwin64 + GNU C $ gcc time_t_test.c && ./a sizeof(time_t): 8 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: 2147483648L: 2038-01-19 03:14:08 UTC 18446744073709551615UL: -1L: 1969-12-31 23:59:59 UTC

Cygwin32 + GNU C

$ gcc time_t_test.c && ./a sizeof(time_t): 4 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 1901-12-13 20:45:52 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

Page 17: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

各環境のtime_tの状況

17

Borland C++ 5.5.1 >bcc32 time_t_test.c && time_t_test Borland C++ 5.5.1 for Win32 Copyright (c) 1993, 2000 Borland time_t_test.c: Turbo Incremental Link 5.00 Copyright (c) 1997, 2000 Borland sizeof(time_t): 4 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 2106-02-06 06:28:15 UTC

Page 18: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

各環境のtime_tの状況

Visual Studio 2013 Express Desktop Windows 32bit版 >cl time_t_test.c && time_t_test Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x86 Copyright (C) Microsoft Corporation. All rights reserved. time_t_test.c Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:time_t_test.exe time_t_test.obj sizeof(time_t): 8 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

VC は long が 32bit だったので 64bit 表示出来てない点には注意

18

Page 19: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

各環境のtime_tの状況

Visual Studio 2013 Express Desktop Windows 64bit版 >cl time_t_test.c && time_t_test Microsoft(R) C/C++ Optimizing Compiler Version 18.00.21005.1 for x64 Copyright (C) Microsoft Corporation. All rights reserved. time_t_test.c Microsoft (R) Incremental Linker Version 12.00.21005.1 Copyright (C) Microsoft Corporation. All rights reserved. /out:time_t_test.exe time_t_test.obj sizeof(time_t): 8 time_t has sign: YES 2147483647UL: 2147483647L: 2038-01-19 03:14:07 UTC 2147483648UL: -2147483648L: 2038-01-19 03:14:08 UTC 4294967295UL: -1L: 1969-12-31 23:59:59 UTC

VC は long が 32bit だったので 64bit 表示出来てない点には注意

19

Page 20: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

乱数の範囲調整

任意の範囲の乱数を得る

20

Page 21: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

[0:1) の実数の乱数生成法

• rand(): [0:RAND_MAX]の整数の乱数を生成

• [0:1) を得るには?

• 実数にして RAND_MAX + 1 で割れば良い

• RAND_MAX って幾つ?

• RAND_MAX + 1 だとオーバーフローするかも?

• RAND_MAX + 1.0 なら大丈夫

#define frand() (rand() / (RAND_MAX + 1.0))

[1] p.205.

暗黙の算術変換により 全てdoubleに型変換されて 計算される。

21

Page 22: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

[0:N-1]の整数の乱数生成法

• [0:1) の実数の乱数を生成してNを掛けた後 整数に変換する

int x; x = frand() * N;

なぜ以下の計算方法では駄目か? x = rand() / RAMD_MAX * N; x = rand() / RAMD_MAX * (N – 1); x = frand() * (N – 1); ヒント: • 生成される値の範囲は? • N が出る確率は?

[0:N-1] の整数の乱数 = [0:N) の整数の乱数

22

Page 23: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

N面体のサイコロ

• [1:N] の整数が等確率で欲しい

int x; x = frand() * N + 1;

[1:N] の整数の乱数 = [0:N-1] + 1 の整数の乱数 = [0:N) + 1 の整数の乱数

23

Page 24: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

教科書の例

• 実は間違っている

24

test_p322.c #include <stdio.h> #include <stdlib.h> #include <time.h> #define RANGE_MIN 0 #define RANGE_MAX 10 void main() { int rand10; // 0以上未満 srand( (unsigned)time(NULL) ); rand10=(int)(((double) rand() / (double) RAND_MAX) * RANGE_MAX + RANGE_MIN); printf("求まった乱数は %d¥n", rand10); }

0~9 までは (RAND_MAX / 10) / (RAND_MAX + 1) の確率で出現するので 0以上10以下の乱数を意図したとしても 出現確率のバランスが悪い

rand() は 0 以上 RAND_MAX 以下 の値を返すので、この実装では 1/(RAND_MAX+1) の確率で 10 が出現してしまう

ここのコメントも おかしいが、 0以上10未満でも 0以上10以下でも やってはいけない実装

教科書 p.322.

乱数に関してよく見られる 有名な間違いです。

Page 25: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

もっと質の良い疑似乱数

• random 関数 (POSIX.1-2001.)

• 非線形加法フィードバック

• JM / random(3)

• drand48 関数 (POSIX.1-2001.)

• 線形合同法+48bit整数

• JM / drand48(3)

• メルセンヌツイスタ

• Wikipedia / メルセンヌツイスタ

25

Page 26: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

ファイル操作

ファイルに対する入出力

26

Page 27: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

標準入出力と標準エラー出力

• 以下の入出力が利用できる

• stdin: STanDard INput: 標準入力

• stdout: STanDard OUTput: 標準出力

• stderr: STanDard ERRor output: 標準エラー出力

• scanf や getchar 等は stdin から入力している

• printf や putchar 等は stdout へ出力している

• stdin, stdout はパイプやリダイレクトの対象だが stderr は標準では対象外

[1] pp.196, 199, 218. 27

Page 28: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

標準入出力と標準エラー出力

• パイプやリダイレクトで処理されたくない内容は stderr へ出力する

• fscanf や fprintf を使うと、入出力先を自由に選択出来る

[1] pp.196, 199, 218. 28

stdiotest.c printf("output to stdout with printf¥n"); fprintf(stdout, "output to stdout with fprintf¥n"); fprintf(stderr, "output to stderr with fprintf¥n");

mintty + bash $ ./stdiotest > redirect.txt output to stderr with fprintf $ cat redirect.txt output to stdout with printf output to stdout with fprintf

Page 29: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

標準入出力と標準エラー出力

• stdin,stdout,stderrはstdio.hで定義されている

• stdio.h は standard input / output header

[1] pp.196, 199, 218. 29

Page 30: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

fprintf 関数

• int fprintf(FILE *fp, const char *FORMAT, ...);

• printfの結果をfpへ書き出す

• 引数: • fp: FILE 構造体へのポインタ

• FORMAT: 書式

• ...: 任意の数の引数

• 戻り値: • 書き出された文字数

• エラーの場合負の数

教科書 pp.61, 64-66, 98, 300.

参考: [1] pp.305-306.

30

Page 31: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

fscanf 関数

• int fscanf(FILE *fp, const char *FORMAT, ...); • fpからデータを読み込む

• 引数: • fp: FILE 構造体へのポインタ • FORMAT: 書式 • ...: 任意の数の引数

値を格納する変数へのポインタ

• 戻り値: • 変換され代入された入力項目の数 • ファイル終端またはエラーの場合EOF

教科書 pp.80-83, 254.

参考: [1] pp.307-309.

31

Page 32: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

fopen 関数

• FILE *fopen(const char *filename, const char *mode); • ファイルを開き、FILE構造体へのポインタを得る

• 引数:

• filename: ファイル名(パス)の文字列

• mode: ファイルを開くモード

• 戻り値:

• FILE 構造体へのポインタ

• エラーの場合 NULL

教科書 pp.298-305.

参考: [1] pp.194-198.

32

Page 33: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

fopen 関数の mode

mode 読み込み 書き込み 動作

"r" 任意の位置 × ファイルを開く、存在しない場合エラー

"w" × 任意の位置 ファイルを作成し、前の内容は消去する

"a" × ファイル末尾 ファイルを開く、または作成

"r+" 任意の位置 任意の位置 ファイルを開く、存在しない場合エラー

"w+" 任意の位置 任意の位置 ファイルを作成し、前の内容は消去する

"a+" 任意の位置 ファイル末尾 ファイルを開く、または作成

教科書 pp.298-305.

参考: [1] pp.194-198.

33

"r", "w", "a", "r+", "w+", "a+" はテキストモードで読み書きする テキストモードでは改行コード(¥n)の扱いが環境によって異なる • Windows: CR LF (0xd 0xa) • Mac: CR (0xd) • UNIX: LF (0xa) バイナリモードにするには、"rb", "wb", "ab", "r+b", "w+b", "a+b" のように "b" を追加する

Page 34: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

fclose 関数

• int fclose(FILE *fp);

• ファイルを閉じます

• 引数:

• fp: FILE構造体へのポインタ

• 戻り値:

• 0 を返す

• エラーの場合 EOF を返す

教科書 pp.298-305.

参考: [1] pp.194-198.

34

Page 35: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

ファイル入力の例

35

fprintf_ex1.c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; // ファイル入出力用のポインタ int value = 123; fp = fopen("sample.txt", "w"); // 書き込みモードでファイルを開く if (fp == NULL) { // エラー処理 fprintf(stderr, "Error: fopen: sample.txt¥n"); exit(EXIT_FAILURE); } fprintf(fp, "%d¥n", value); // fp に value の値を出力 fclose(fp); // 使い終わったファイルを閉じる return EXIT_SUCCESS; }

Page 36: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

ファイル出力の例

36

fscanf_ex1.c #include <stdio.h> #include <stdlib.h> int main() { FILE *fp; // ファイル入出力用のポインタ int value; fp = fopen("sample.txt", "r"); // 読み込みモードでファイルを開く if (fp == NULL) { // エラー処理 fprintf(stderr, "Error: fopen: sample.txt¥n"); exit(EXIT_FAILURE); } fscanf(fp, "%d", &value); // fp から符号付き整数の文字列を読み込む printf("%d¥n", value); // 読み込んだ値を表示 fclose(fp); // 使い終わったファイルを閉じる return EXIT_SUCCESS; }

Page 37: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

テスト

プログラムの動作を検証する

37

Page 38: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

ユニットテスト(単体テスト)

• 標準ライブラリヘッダ <assert.h>

• assert マクロの利用

• ユニットテストツールの利用

• CUnit http://cunit.sourceforge.net/

38 教科書pp.188-189.

CUnit のインストール (cygwin) apt-cyg install CUnit

Page 39: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

assert マクロ

void assert(int expression) • expression がゼロの場合以下のメッセージを stderr に出力し abort する

Assertion failed: expression, file filename, line nnn

• <assert.h>をインクルードする時点で NDEBUG マクロが定義されていると assert マクロは無視される

• ユニットテストだけでなくデバッグ時のみ有効にする不正値のチェック等でも利用される

39

JM / assert(3)

Page 40: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

assert マクロ

• 専用のテストルーチンで使用した例

40

is_leap_year_assert.c void test_leap_year() { assert(is_leap_year(-400) == 1); assert(is_leap_year(- 56) == 1); assert(is_leap_year(- 4) == 1); assert(is_leap_year( 0) == 1); assert(is_leap_year( 4) == 1); assert(is_leap_year( 56) == 1); assert(is_leap_year( 400) == 1); assert(is_leap_year(1996) == 1); assert(is_leap_year(2000) == 1); assert(is_leap_year(2004) == 1); }

is_leap_year_assert.c void test_normal_year() { assert(is_leap_year(-300) == 0); assert(is_leap_year(-200) == 0); assert(is_leap_year(-100) == 0); assert(is_leap_year(- 3) == 0); assert(is_leap_year(- 2) == 0); assert(is_leap_year(- 1) == 0); assert(is_leap_year( 1) == 0); assert(is_leap_year( 2) == 0); assert(is_leap_year( 3) == 0); assert(is_leap_year( 100) == 0); assert(is_leap_year( 200) == 0); assert(is_leap_year( 300) == 0); assert(is_leap_year(1900) == 0); assert(is_leap_year(1997) == 0); assert(is_leap_year(1998) == 0); assert(is_leap_year(1999) == 0); assert(is_leap_year(2001) == 0); assert(is_leap_year(2002) == 0); assert(is_leap_year(2003) == 0); }

is_leap_year_assert.c int main() { test_leap_year(); test_normal_year(); return EXIT_SUCCESS; }

Page 41: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

assert マクロ

• 専用のテストルーチンで使用した例

• エラーがなければ何も起きない

• エラーがあるとそこで実行が中断する

41

mintty + bash + GNU C

mintty + bash + GNU C

$ gcc is_leap_year_assert.c is_leap_year_func_ex4_2.c && ./a

$ gcc is_leap_year_assert.c is_leap_year_func_practice1.c && ./a assertion "is_leap_year(-300) == 0" failed: file "is_leap_year_assert.c", line 21, function: test_normal_year Aborted (コアダンプ)

Page 42: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

CUnit

• 専用のテストルーチンを作成して使用

42

is_leap_year_cunit.c void test_leap_year() { CU_ASSERT_EQUAL(is_leap_year(-400), 1); CU_ASSERT_EQUAL(is_leap_year(- 56), 1); CU_ASSERT_EQUAL(is_leap_year(- 4), 1); CU_ASSERT_EQUAL(is_leap_year(1996), 1); CU_ASSERT_EQUAL(is_leap_year(2000), 1); CU_ASSERT_EQUAL(is_leap_year(2004), 1); }

is_leap_year_cunit.c void test_normal_year() { CU_ASSERT_EQUAL(is_leap_year(-300), 0); CU_ASSERT_EQUAL(is_leap_year(-200), 0); CU_ASSERT_EQUAL(is_leap_year(-100), 0); CU_ASSERT_EQUAL(is_leap_year(- 3), 0); CU_ASSERT_EQUAL(is_leap_year(2002), 0); CU_ASSERT_EQUAL(is_leap_year(2003), 0); }

is_leap_year_cunit.c static CU_TestInfo test_is_leap_year[] = { {"leap year", test_leap_year}, {"normal year", test_normal_year}, CU_TEST_INFO_NULL, }; static CU_SuiteInfo suites[] = { {"is_leap_year test", NULL, NULL, test_is_leap_year}, CU_SUITE_INFO_NULL, }; int main() { CU_initialize_registry(); CU_register_suites(suites); CU_basic_set_mode(CU_BRM_VERBOSE); CU_basic_run_tests(); CU_cleanup_registry(); return EXIT_SUCCESS; }

Page 43: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

CUnit

• 専用のテストルーチンを作成して使用

• ユニットテストの達成状況がレポートされる

43

mintty + bash + GNU C $ gcc is_leap_year_cunit.c is_leap_year_func_ex4_2.c -lcunit && ./a CUnit - A unit testing framework for C - Version 2.1-2 http://cunit.sourceforge.net/ Suite: is_leap_year test Test: leap year ...passed Test: normal year ...passed Run Summary: Type Total Ran Passed Failed Inactive suites 1 1 n/a 0 0 tests 2 2 2 0 0 asserts 29 29 29 0 n/a Elapsed time = 0.000 seconds

テストの通過状況の 統計が表示される

Page 44: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

CUnit

44

mintty + bash + GNU C $ gcc is_leap_year_cunit.c is_leap_year_func_practice1.c -lcunit && ./a CUnit - A unit testing framework for C - Version 2.1-2 http://cunit.sourceforge.net/ Suite: is_leap_year test Test: leap year ...passed Test: normal year ...FAILED 1. is_leap_year_cunit.c:21 - CU_ASSERT_EQUAL(is_leap_year(-300),0) 2. is_leap_year_cunit.c:22 - CU_ASSERT_EQUAL(is_leap_year(-200),0) 3. is_leap_year_cunit.c:23 - CU_ASSERT_EQUAL(is_leap_year(-100),0) 4. is_leap_year_cunit.c:30 - CU_ASSERT_EQUAL(is_leap_year( 100),0) 5. is_leap_year_cunit.c:31 - CU_ASSERT_EQUAL(is_leap_year( 200),0) 6. is_leap_year_cunit.c:32 - CU_ASSERT_EQUAL(is_leap_year( 300),0) 7. is_leap_year_cunit.c:33 - CU_ASSERT_EQUAL(is_leap_year(1900),0) Run Summary: Type Total Ran Passed Failed Inactive suites 1 1 n/a 0 0 tests 2 2 1 1 0 asserts 29 29 22 7 n/a Elapsed time = 0.000 seconds

テストの通過状況の 統計が表示される

Page 45: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

変更箇所の管理

比較、差分、パッチ、バージョン管理等

45

Page 46: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

diff のインストール

• mintty+bash から以下のコマンドを実行

46

mintty + bash apt-cyg install diff

Page 47: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

diff

• UNIX系のファイル比較コマンド

47

mintty + bash $ diff is_leap_year_func_practice1.c is_leap_year_func_ex4_2.c 5c5 < return year % 4 == 0; --- > return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0;

上記の例では ファイル間の相違点を 一覧として表示している

Page 48: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

diff

• 並列表示

• --side-by-sideオプションによる比較

48

mintty + bash $ diff is_leap_year_func_practice1.c is_leap_year_func_ex4_2.c --side-by-side #include "is_leap_year_func.h" #include "is_leap_year_func.h" int is_leap_year(int year) int is_leap_year(int year) { { return year % 4 == 0; | return (year % 4 == 0 && year % 100 != 0) || year % 400 == } }

Page 49: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

fc

• Windows 標準添付のファイル比較コマンド

49

コマンドプロンプト >fc is_leap_year_func_practice1.c is_leap_year_func_ex4_2.c ファイル is_leap_year_func_practice1.c と IS_LEAP_YEAR_FUNC_EX4_2.C を比較しています ***** is_leap_year_func_practice1.c { return year % 4 == 0; } ***** IS_LEAP_YEAR_FUNC_EX4_2.C { return (year % 4 == 0 && year % 100 != 0) || year % 400 == 0; } *****

Page 50: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

WinMerge

• GUIによるテキストファイルの比較ツール

• 相違点の合成も出来る • http://www.forest.impress.co.jp/library/software/winmerge/

50

UNIX 環境の GUI 版の比較ツールだと meld や tkdiff 等がある

Page 51: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

Rekisa

• GUIによる複数テキストファイルの比較ツール • http://www.forest.impress.co.jp/library/software/rekisa/

51

Page 52: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

差分とパッチ

• diff : 差分比較、パッチ作成ツール

• JM / diff (1)

• Wikipedia / diff

• patch : 差分適用(パッチ適用)ツール

• JM / patch (1)

• Wikipedia / patch

52

単一ファイルのパッチの作成 $ diff -c myfile.orig myfile > myfile.patch

パッチの適用 $ patch < myfile.patch

ディレクトリ以下のパッチの作成 $ diff -crN mydir.orig mydir > mydir.patch

カレントディレクトリへのパッチの適用 $ patch -p0 -d. < mydir.patch

ファイル間の差異を パッチ(=絆創膏)として取り出し 適用することで変更箇所を反映させる

Page 53: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

バージョン管理ツール

• RCS • Wikipedia / Revision Control System

• CVS • Wikipedia / Concurrent Version System

• Subversion • Wikipedia / Apache Subversion

• Mercurial • Wikipedia / Mercurial

• Bazaar • Wikipedia / Bazaar

• git • Wikipedia / git

53

github の登場で 人気になっている

過去の改変の記録を残したり 複数人で共同で作業する際に 役立つ

Page 54: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

テキスト画面の簡易制御

tty_getchar.c

54

Page 55: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

getchar 関数

• int getchar(void) • 入力 stream から1文字読み込む

• stream というのはバッファのようなもの

• 通常はENTERが押されるまで入力streamには値が入って来ない。入力ストリームに値がない場合は値が入ってくるまで待機する

• 戻り値: • 入力された文字の文字コード返す

• ファイル終端やエラーの場合はEOFを返す

55

JM / fgetc(3)

Page 56: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

getchar 関数の動作

• ENTERが押されるまで一気に読み込む

56

getchartest.c #include <stdio.h> #include <stdlib.h> int main() { int c; while ((c = getchar()) != EOF) { printf("%#04x¥n", c); } return EXIT_SUCCESS; }

バッファリングと言います。 読み込み処理を 高速化するための仕組みです。

バッファリングに溜めてある 入力文字を1文字ずつ取り出します。 バッファが空になると ENTERが押されるまで 入力待ちの状態になります。

Page 57: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey

• ENTER待ちなしのキーボード入力

57

tty_getkey_ex1.c #include "tty_getkey.h" #include "msleep.h" int main() { int c; tty_begin(); // 開始処理 while(tty_iskeyhit() == 0) { // 打鍵待ちループ msleep(1); // CPU に負荷をかけずに 1 msec 待つ // tty_ishitkey() は即座に値を返すので空ループだと CPU に負荷がかかる } c = tty_getkey(); // 打鍵キーの取得 tty_printf("%#x key was hit.¥n", c); // tty 用の printf tty_printf("Hit ESC key to exit.¥n"); while(KEY_ESC != tty_getkey()) { // 打鍵待ちループ ; // tty_ketkey() はキー入力があるまで待機するため空ループでも CPU に負荷をかけない } tty_end(); // 終了処理 return EXIT_SUCCESS; }

Page 58: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey

• ENTER待ちなしのキーボード入力

• Windows 系の環境

• conio.h ライブラリを利用

• embarcadero / RAD Studio / conio.h

• MSDN / Console and Port I/O

• UNIX 系の環境

• curses ライブラリを利用

• http://ja.wikipedia.org/wiki/Curses

58

Page 59: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey を利用したプログラムの コンパイル

• サンプルプログラム

• tty_getkey_ex1.c : サンプルプログラム本体

• 必要なファイル

• msleep.h : ミリ秒 sleep 用ヘッダ

• tty_getkey.h : tty_getkey ヘッダファイル

• tty_getkey.c : tty_getkey 本体

59

mintty + bash + GNU C $ gcc tty_getkey_ex1.c tty_getkey.c -lcurses

コマンドプロンプト + Borland C++ >bcc32 tty_getkey_ex1.c tty_getkey.c

gcc では -lcurses オプションが必要 これには ncurses ライブラリが必要

Page 60: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey 利用前の準備 Cygwin の場合

• ncurses の開発用ライブラリが必要

• 以下のコマンドを入力してインストール

• Borland C++ では、標準添付の conio というライブラリを使っているので前準備は不要

60

Cygwin64 mintty + bash apt-cyg install libncursesw-devel

Cygwin32 mintty + bash apt-cyg install libncurses-devel

Page 61: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

Cygwinが何bit版か確認する方法

• uname コマンドに -a オプションを付けて実行

61

Cygwin64 mintty + bash $ uname -a CYGWIN_NT-6.1 EX58EXTREME 1.7.27(0.271/5/3) 2013-12-09 11:54 x86_64 Cygwin

Cygwin32 mintty + bash $ uname -a CYGWIN_NT-6.1-WOW64 EX58EXTREME 1.7.27(0.271/5/3) 2013-12-09 11:57 i686 Cygwin

i686 なら 32bit 版

x86_64 なら 64bit 版

Page 62: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey 初期化関数

• int tty_begin(void)

• tty_getkey の初期化処理を行います

• int tty_end(void)

• tty_getkey の終了処理を行います

62

Page 63: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey キー待ち受け関数

• int tty_iskeyhit(void)

• キー入力の有無を調べます。

• キー入力があれば 1 なければ 0 を返します。

• int tty_getkey(void)

• キー入力を取得します。キー入力がない場合、キー入力が発生するまで待機します。

• 通常のキーは'a'や'A'等の文字コードを返します。

• 特殊キーの場合はKEY_UPやKEY_DOWN等のマクロで定義されたキーコードを返します。

63

Page 64: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey() が返すキーコード

• KEY_INSERT

• KEY_DELETE

• KEY_HOME

• KEY_END

• KEY_PAGEUP

• KEY_PAGEDOWN

• KEY_UP

• KEY_DOWN

• KEY_LEFT

• KEY_RIGHT

• KEY_ESC

• KEY_TAB

• KEY_SPACE

• KEY_BS

• KEY_ENTER

• KEY_F1 ~ KEY_F48

通常のキーは 'a', 'A' 等の文字定数リテラルが対応

64

Page 65: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey 出力関数

• int tty_printf(char *fmt, ....)

• 書式付の出力を行います。

• 画面制御を伴うためtty_begin()~tty_end()の間では、通常のprintfは使わないでください。

• int tty_setxy(int x, int y)

• カーソルの座標を(x,y)に移動します。

65

Page 66: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey 画面情報関数

• int tty_getx(void)

• カーソルの x 座標を返します。

• int tty_gety(void)

• カーソルの y 座標を返します。

• int tty_getw(void)

• カーソルが移動可能な画面の幅を返します。

• int tty_geth(void)

• カーソルが移動可能な画面の高さを返します。

66

Page 67: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey_ex2.c

• カーソルキーで移動、ESC キーで終了

• 移動した場所に * を表示する

67

Page 68: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey_ex2.c

68

tty_getkey_ex2.c while (KEY_ESC != (c = tty_getkey())) { switch (c) { case KEY_UP: y--; break; case KEY_DOWN: y++; break; case KEY_RIGHT: x++; break; case KEY_LEFT: x--; break; } x = x < 1 ? 1 : w - 2 < x ? w - 2 : x; y = y < 1 ? 1 : h - 2 < y ? h - 2 : y; tty_setxy(0, 0); tty_printf("(%2d,%2d) : %#06x", x, y, c); tty_setxy(x, y); tty_printf("*"); }

入力された カーソルキーの方向に応じて 座標を上下左右に移動

画面から はみ出さないように 移動範囲を制限

Page 69: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tty_getkey_ex3.c

• 6面体サイコロの例

• 開始するとサイコロが転がり始める

• 何かキーを押すと3秒待って終了する

69

tty_getkey_ex3.c while(tty_iskeyhit() == 0) { d = frand() * 6 + 1; tty_setxy(0, 0); tty_printf("%d", d); msleep(1); } msleep(3000);

値域 [1:6] の乱数生成 = 6面体サイコロ

Page 70: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

総合実習

プログラムで遊んでみる

70

Page 71: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c

• テトリスの簡易版

• 操作方法

• 移動: ← →

• 落下: ↓

• 回転: z x SPACE

• 修了: ESC

71

mintty + bash + GNU C $ gcc tetris.c tty_getkey.c -lcurses && ./a

コマンドプロンプト + Borland C++ >bcc32 tetris.c tty_getkey.c && tetris

mintty + bash + GNU C ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

Page 72: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c

• フィールド

72

描画用フィールド field[0][y][x]

固定ブロック用フィールド field[1][y][x]

浮動ブロック b[y][x]

ブロック形状 block[spec][y][x]

仮り配置

選択して回転

落下したら固定

描画用フィールドにコピー

Page 73: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造

• 以下の改造を考えてみよう

• 「p」でポーズ/解除する

• 点数を表示する

• 次のブロックをランダムに決める

• 次のブロックを表示する

• 上まで積み上がったら ゲームオーバーにする

• ハイスコアを記録・表示してみる

73

mintty + bash + GNU C ## ## HISCORE: 001000 ## ## Score : 001000 ## ## ## ## NEXT ## ## ++--------++ ## ## ## || || ## ## ## || ## || ## #### ## || #### || ## ## || ## || ## ## ++--------++ ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

Page 74: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造 ヒント

• 「p」でポーズ/解除する

• ポーズフラグ用の変数が必要

• 「p」キーでポーズフラグを反転する

• ポーズフラグがONなら continue してループを先頭からやり直す

74

フラグの反転 // 以下の処理はいずれも // pause == 0 なら 1 // pause != 0 なら 0 // となる pause = pause ? 0 : 1; pause = !pause; pause = pause == 0;

Page 75: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造 ヒント

• 点数を表示する

• 点数用の変数が必要

• ブロックの落下や 1列消した場合に スコアを加算する

• 適当な位置にスコアを表示する

• 位置調整は tty_setxy()

• 表示は tty_printf()

75

mintty + bash + GNU C ## ## HISCORE: 001000 ## ## Score : 001000 ## ## ## ## NEXT ## ## ++--------++ ## ## ## || || ## ## ## || ## || ## #### ## || #### || ## ## || ## || ## ## ++--------++ ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

例えばこの位置に表示するなら tty_printf() の前に tty_setxy(W*2+2,1); を入れる

Page 76: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造 ヒント

• 次のブロックをランダムに決める

• spec の値を乱数で決定すれば良い

• 前述の frand() マクロを使うと [0:7) の乱数は frand()*7 で得られる

76

Page 77: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造 ヒント

• 次のブロックを表示する • 次のブロックを記憶するための変数が必要(※1) • ※1を使って spec を更新する • spec を更新後 ※1 も更新する • ※1 を適当な位置に表示する

• 表示位置は tty_setxy() で 調整する

• 枠は "++--------++" と "||" 以外でも 好きな文字を使えば良い

• block[※1][y][x] の値に応じて " " または "##" を表示する

77

mintty + bash + GNU C ## ## HISCORE: 001000 ## ## Score : 001000 ## ## ## ## NEXT ## ## ++--------++ ## ## ## || || ## ## ## || ## || ## #### ## || #### || ## ## || ## || ## ## ++--------++ ## ## ## ## ## ## ## ## ## ## #### ## ## ## #### ## #### #### ## ############## ## ############## ####################

Page 78: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造 ヒント

• 上まで積み上がったらゲームオーバーにする

• y <= 0 でブロックが固定されたら、上まで積み上がっている

• ゲームオーバーになるとどうするか?

• GAME OVER と表示する?

• その後、再度ゲームをスタートするか?プログラムを終了するか?

• 一般に流通しているゲームはどうしているか参考にすると良い?

78

Page 79: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

tetris.c の改造

• ハイスコアを記録・表示してみる

• ハイスコア用の変数が必要

• ハイスコアは画面の適当な場所に表示する

• スコアがハイスコアを超えたらハイスコアを更新する必要がある

• ハイスコアはファイルに保存し、ゲーム開始時に読み込み終了時に保存する必要がある

• fopen, fclose でファイルのオープン、クローズが行える

• fprintf, fscanf で値の読み書きが行える

79

Page 80: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

まとめ

やったこと、やらなかったこと

80

Page 81: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

この授業で扱った事

• C言語の基礎

• 演算、式、変数、制御構造、関数、ポインタ等

• 簡単なプログラムの作成

• 奇数偶数の判定

• 閏年の判定

• 行列の演算

• シーザー暗号

• 等々

Page 82: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

この授業で扱わなかったこと

• 構造体と共用体: struct, union

• 型定義: typedef

• 可変長引数: <stdarg.h>

• va_list, va_start, va_arg, va_end

• 非局所ジャンプ: <setjmp.h>

• シグナル処理: <signal.h>

Page 83: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

参考文献

• [1] B.W.カーニハン/D.M.リッチー著 石田晴久 訳、プログラミング言語C 第2版 ANSI 規格準拠、共立出版(1989)

83

Page 84: C言語入門 - Yamaguchi Uweb.cc.yamaguchi-u.ac.jp/~okadalab/CLangI2015/CLangI2015...C言語入門 第15週 プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ,

おしまい

おつかれさまでした。

来週は試験です。しっかり復習しておきましょう。