情報処理 Ⅱ 第 12 13回 2011 年 1 月 31 17 日 ( 月 )
本日学ぶこと ファイル入出力, 標準入力 標準出力 記憶域管理関数 (malloc など ) 問題 ファイルを入力にとり, 先頭に行番号をつけて出力できる? 行列の積を, ファイルを介して読み書き 計算できる? Wakayama University./line 1:Wakayama 2:University 3 2 1 1 2 3 5 4 3 2 1 0./matrix 22 16 14 8 2
ファイル補足 Cでは, ファイルその他への入出力方法は文法で規定されていない. 代わりに豊富なライブラリ ( 標準入出力ライブラリ ) が規定されている. ストリームは, ファイルやコンソールル ( キーボード入力と画面表示 ) などを統一的に扱うためのものである. テキストストリームとバイナリストリームに分けられる. 前回と今回の授業では, テキストストリームを対象とする. 入出力の途中にナル文字 (' 0') があっても問題なく処理できなければならない. リ pp.455-456 3
line.c 仕様 考え方 コマンドライン引数 ( 複数あればそれぞれ ) をファイル名とみなして, そのまま出力していく. ただし行の先頭には行番号をつける. fgetc を用いて 1 バイトずつ読み出す. 行の先頭 とは, ファイルの先頭 か 改行文字(' n') の直後 のいずれか. 今何行目を読んでいるか を保存する変数 line_countを用意する. line.c 4
1 文字ごとの読み出し (1) while ((c = fgetc(fp))!= EOF) {...} プログラムの内部状態 ファイル abc 'a' 'b' 'c' ' n' これがストリーム FILE fp オブジェクト c =??? ' 0' がない点に注意 ( 文字列ではない ) 5
1 文字ごとの読み出し (2) while ((c = fgetc(fp))!= EOF) {...} 'a'!= EOF は真 プログラムの内部状態 ファイル abc 'a' 'b' 'c' ' n' fp FILE オブジェクト c = 'a'??? 6
1 文字ごとの読み出し (3) while ((c = fgetc(fp))!= EOF) {...} プログラムの内部状態 ファイル abc 'a' 'b' 'c' ' n' fp FILE オブジェクト c = ' n'??? 7
1 文字ごとの読み出し (4) while ((c = fgetc(fp))!= EOF) {...} EOF!= EOF は偽 プログラムの内部状態 ファイル abc 'a' 'b' 'c' ' n' fp FILE オブジェクト c =??? EOF 8
EOF(1) ファイルの終わり(End Of File) を表す定数. stdio.h で,#define EOF ( 1) などと定義されている. unsigned char signed char ASCII (7ビット) 128 11 0 127 255 入 p.189 リ p.457 EOF ナル文字 9
EOF(2), ファイルアクセス 文字 ( バイト ) 単位で読み書きするとき int 型を使用する. signed char 型だと,255をEOFと誤認識する. unsigned char 型だと,EOF を 255 と誤認識する. EOFから255までの 257 種類の値 は,char 型 (signed char 型,unsigned char 型 ) で区別できない! 読み出して EOF が来たら, そこでおしまいにする. ライブラリ関数は fgetc, getchar など 文字列単位で ( 何バイトか一括して ) 読み書きするとき char 配列またはchar* 型を使用する. ライブラリ関数は fgets, fread など リ p.461, p.471, p.462, p.466 10
標準入力と標準出力 標準入力 (standard input, stdin) 通常はコンソール入力 ( キーボード入力 ) 標準出力 (standard output, stdout) 通常はコンソール出力 ( 画面表示 ) シェルのリダイレクション機能を用いて変更可能. 実行例 : find ~ > files 実行例 :./line2 < /usr/share/dict/words stdin,stdoutは FILE * 型の値 ( ファイルポインタ ) として利用可能. ただし代入はできない. シェルのパイプ機能を用いて, あるプログラムの標準出力と別のプログラムの標準入力を接続できる. 実行例 : echo '1+2*3' bc 入 pp.183-186 リ p.480 line2.c 11
標準入力 標準出力とコンソール標準出力とコンソ 実行環境 (OSなど) 'a''b''c' ' n' 標準入力コンソール 実行プログラム '1'':'' ''a''b''c' ' n' $./line2 abc 1: abc $ 標準出力 実行コマンド入力 ( エコーバック ) 出力 入 p.188 12
標準入力に関するライブラリ関数 int getchar(void); 標準入力から 1 文字 (1 バイト ) 読み込む. 戻り値は unsigned char 型の値, もしくは定数 EOF. char *gets gets(char *s); なるべく使わない! 標準入力から 1 行読み込み,s の指す領域に格納する. 1 行が,s の領域サイズよりも大きいとしても, そのまま格納しようとする. なるべく使わない! int scanf(const char *format,...); formatに従って標準入力から入力を読み込み, 第 2 引数以降が参照する領域に格納する. 読み込みに失敗すれば, 入力が進まない. リ pp.471-472, pp.476-477, pp.489-492 13
標準出力に関するライブラリ関数 int putchar(int c); c を unsigned char 型に変換した上で, 標準出力に (1 文字 ) 書き出す. char *puts puts(const char *s); 文字列 s と改行文字を標準出力に書き出す. int printf(const char *format,...); format に従って標準出力に書き出す. printf(str); printf(" n"); puts(str); printf("%s n", str); 文字列に % が含まれているとおかしくなる リ p.474, p.473, pp.485-488 14
標準入出力と標準入出力関数 標準入力 標準出力に対する関数は, 標準入出力関数および stdin, stdout を用いた関数形式マクロにより定義されている ( ことがある ). 例 : #define getchar() getc(stdin) リ pp.470-471 15
実行時の領域確保について プログラム実行時 (main 関数に制御が移る前 ) に 静的変数のオブジェクトが確保, 初期化される. プログラム終了時に破棄される. ブロック ({...}) が実行されるときに 自動変数のオブジェクトが確保される. ブロック終了時に破棄される. スタック領域 記憶域管理関数 (malloc, callocなど ) を呼び出すと オブジェクトとして使用できる領域が確保される. freeなどの関数が呼び出されるか, プログラム終了時に破棄される. ヒープ領域 malloc の語源 :memory allocation( メモリ割り当て ) 入 pp.245-246 16
malloc の使い方 (1) 準備 #include <stdlib.h stdlib.h> int *p; 必ずポインタ型 (intの部分は用途による) p = (int *)malloc malloc(sizeof sizeof(int int)); *pがint 型オブジェクトとして利用可能. p *p sizeof(int) バイトの領域 リ p.235, p.341, p.501 17
malloc の使い方 (2) 準備 #include <stdlib.h stdlib.h> int *p; 必ずポインタ型 (intの部分は用途による) p = (int *)malloc malloc(sizeof sizeof(int int) * 10); p[0],p[1],,p[9] がintの配列であるかのように利用可能. p p[0] p[1] p[9] sizeof(int) * 10 バイトの領域 リ p.235, p.341, p.501 18
malloc 使用の注意点 領域の値は不定であるため, 必要に応じて初期化する. 代わりに calloc を使用すれば, すべて 0 に初期化された領域が得られる. 代入される変数はポインタ変数なので, 左辺値になり得る (p++; などとできる ). 領域確保に失敗すると NULL を返すので, if ((p = (p の型名 )malloc( バイト数 )) == NULL) { エラー処理 } とするのが一般的. 必ずポインタ型 リ p.497 19
行列の動的な確保 typedef struct Matrix { int row, column; double **element; } matrix; matrix *p = (matrix *)malloc(sizeof(matrix)); p->row = 2; p->column = 3; p->element = (double **)malloc malloc(sizeof(double *) * 2); p->element[0] = (double *)malloc malloc(sizeof sizeof(double) * 3); p->element[1] = (double *)malloc malloc(sizeof(double) * 3); p row=2 column=3 0 行 1 行 a 00 a 01 a 02 a 10 a 11 a 12 element a 00 a 01 a 02 a 10 a 11 a 12 matrixfile.c i 行 j 列の成分 (a ij ) は p >element[i][j] >element[i][j] ポインタ変数 p を除き, どの値も malloc で確保された領域内にある 20
記憶域管理関数の得失 メリット 何度呼び出しても, そのたびに異なるメモリ領域から確保する リエントラントな関数を作りやすい 領域サイズは実行時 ( コンパイル時 ) に決まるので, 入力に応じて必要な分だけ確保すればよい メモリ利用の効率化 デメリット 領域が確保できないことによる実行時エラーが起こるかもしれない. 確保した領域をいつ開放する (OSに返す) のか, 考えなければならない. 21
可変長配列 可変長配列の例 実行時にその個数 ( の上限 ) がわからないような配列 matrixfile.c では, メンバ element の指し示す領域 可変長配列を C で取り扱うときは, malloc または calloc で初期化し, より大きな領域が必要になったら,realloc を用いるとよい. リ p.505 22
後始末 ファイルの読み書きを終えたら,fclose を用いる. fopen/fclose をペアで覚える. fcloseを呼び出す前のファイルの出力内容は, プログラム内に保持されている ( バッファリング ) 可能性がある. プログラム終了時に, 閉じられていないファイルは保存されるが, これに頼らない ( 積極的に fclose を用いる ) ほうがよい. ヒープ領域の内容を解放するには,free を用いる. malloc/free をペアで覚える. プログラム終了時に,freeされていない領域も破棄されるが, できれば頼らない ( 可能なら free を用いる ) ほうがよい. リ pp.458-459, p.499 23
まとめ ファイルに情報を保持することと, 変数に値を保持することの違いは何か? どのようなにアクセスに対して, どのような標準入出力関数を使用すればよいか? malloc 系関数を使用すると, 何ができるか? 24
補講について 2 月 1 日 ( 火 )2 限,A103 で補講 おさらい問題 を配布し, 解説する予定です. 小テスト アンケートも実施します. 25