情報処理Ⅱ 2008年1月28日(月) 本日学ぶこと ファイル入出力,標準入力・標準出力 記憶域管理関数(mallocなど) 問題 ファイルを入力にとり,先頭に行番号をつけて出力できる? 標準入力の内容を行ごとに逆順に出力できる? Wakayama University ./line Wakayama University ./liner 1:Wakayama 2:University amayakaW ytisrevinU 2 ファイル補足 Cでは,ファイルその他への入出力方法は文法で規定されて いない.代わりに豊富なライブラリ(標準入出力ライブラリ)が 規定されている. ストリームは,ファイルやコンソール(キーボード入力と画面 表示)などを統一的に扱うためのものである. リp.455-456 テキストストリームとバイナリストリームに分けられる.前回と今 回の授業では,テキストストリームを対象とする. 「バイト列であること」は本質ではないが,とくにバイナリスト リームでは,入出力の途中にナル文字('\0')があっても問題 なく処理できなければならない. 3 行番号問題1 仕様 コマンドライン引数(複数ある場合は最初のみ)をファイル名と みなして,そのまま出力していく.ただし行の先頭には行番号 をつける. 考え方 line.c fgetcを用いて1バイトずつ読み出す. 「行の先頭」とは,「ファイルの先頭」か「改行文字('\n')の直 後」のいずれか. 「今何行目を読んでいるか」を保存する変数line_countを用 意する. 4 1文字ごとの読み出し(1) while ((c = fgetc(fp)) != EOF) {...} プログラムの 内部状態 fp これがストリーム ファイルabc 'a' 'b' 'c' '\n' FILE オブジェ クト c = ??? 'a' '\0'がない点に注意 (文字列ではない) 5 1文字ごとの読み出し(2) while ((c = fgetc(fp)) != EOF) {...} プログラムの 内部状態 fp ファイルabc 'a' 'b' 'c' '\n' FILE オブジェ クト c = EOF ??? '\n' リp.255 6 EOF(1) 「ファイルの終わり(End Of File)」を表す定数. stdio.hで,#define EOF (-1)などと定義されている. unsigned char signed char ASCII (7ビット) -128 入p.189 リp.457 127 -1 0 EOF 255 ナル 文字 7 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 8 標準入力と標準出力 標準入力(standard input, stdin) 標準出力(standard output, stdout) 通常はコンソール出力(画面表示) シェルのリダイレクション機能を用いて変更可能. 通常はコンソール入力(キーボード入力) stdin,stdoutは FILE *型の値(ファイル ポインタ)として利用 可能.ただし代入は できない. 実行例: find ~ > files 実行例: ./liner < /usr/share/dict/words シェルのパイプ機能を用いて,あるプログラムの標準出力と 別のプログラムの標準入力を接続できる. 実行例: echo '1+2*3' | bc 入pp.183-186 リp.480 9 標準入力・標準出力とコンソール 実行環境 (OSなど) 標準入力 コンソール 'a' 'b' 'c' '\n' 実行プログラム '1' ':' ' ' 'a' 'b' 'c' '\n' $ ./liner abc 1: abc $ 標準出力 実行コマンド 入力(エコーバック) 出力 入p.188 10 標準入力に関するライブラリ関数 int getchar(void); char *gets(char *s); 標準入力から1文字(1バイト)読み込む. 戻り値はunsigned char型の値,もしくは定数EOF. なるべく使わない! 標準入力から1行読み込み,sの指す領域に格納する. 1行が,sの領域サイズよりも大きいとしても,そのまま格納しよ うとする. なるべく使わない! int scanf(const char *format, ...); formatに従って標準入力から入力を読み込み,第2引数以 降が参照する領域に格納する. 読み込みに失敗すれば,入力が進まない. リp.471-472, pp.476-477, pp.489-492 11 標準出力に関するライブラリ関数 int putchar(int c); char *puts(const char *s); cをunsigned char型に変換した上で,標準出力に(1文 字)書き出す. 文字列sと改行文字を標準出力に書き出す. int printf(const char *format, ...); formatに従って標準出力に書き出す. リp.474, p.473, pp.485-488 12 標準入出力と標準入出力関数 標準入力・標準出力に対する関数は,標準入出力関数およ びstdin, stdoutを用いた関数形式マクロにより定義さ れている(ことがある). 例: #define getchar() getc(stdin) リpp.470-471 13 行番号問題2 仕様 標準入力から入力をとり,各行の文字列を逆順にして標準出 力に書き出す. 考え方 liner.c 読むのはgetchar,書くのはputchar. 1行を読んでから,逆順に出力する. 行単位で,1行の入力内容を保持する. • 標準入力は後戻りができない! • 実行開始時に字数はわからないので, 「記憶域管理関数」を使用する. 14 liner.cの概要 定義した型 struct Line, line:1行の文字列の情報 • 「本体(具体的な中身,コンテンツ)」と「確保した要素数」と 「格納されている要素数」をメンバに持つ. 定義した関数 init_line: 1行構造体を作成する enlarge_line: 1行構造体の本体容量を拡張する free_line: 1行構造体を開放する get_line: 1行読み出す print_reverse: 逆順に出力する 15 実行時の領域確保について プログラム実行時(main関数に制御が移る前)に ブロック({...})が実行されるときに static変数のオブジェクトが確保,初期化される. • プログラム終了時に破棄される. auto変数のオブジェクトが確保される. • ブロック終了時に破棄される. スタック領域 記憶域管理関数(malloc, callocなど)を呼び出すと オブジェクトとして使用できる領域が確保される. • freeなどの関数が呼び出されるか, ヒープ領域 プログラム終了時に破棄される. 入pp.245-246 16 mallocの基本的な使い方 準備 p ⇒ p ⇒ #include <stdlib.h> int *p; 必ずポインタ型 (intの部分は用途による) = (int *)malloc(sizeof(int)); *p がint型変数として利用可能. = (int *)malloc(sizeof(int) * 10); p[0], ..., p[9] がint型変数として利用可能. p p[0] p[1] … p[9] sizeof(int) *10 バイトの領域 リp.235, p.341, p.501 17 malloc使用の注意点 領域の値は不定であるため,必要に応じて初期化する.代 わりにcallocを使用すれば,すべて0に初期化された領域 が得られる. 代入される変数はポインタ変数なので,左辺値になり得る (p++; などとできる). 領域確保に失敗するとNULLを返すので, if ((p = (int *)malloc(sizeof(int) * 10)) == NULL) { エラー処理 } などとするのが一般的. リp.497 18 可変長配列 可変長配列の例 可変長配列をCで取り扱うときは, リp.505 実行時にその個数(の上限)がわからないような配列 行番号問題2では,「1行の本体(具体的な中身)を格納する領 域」が該当する. mallocまたはcallocで初期化し, より大きな領域が必要になったら,reallocを用いるとよい. 19 後始末 ファイルの読み書きを終えたら,fcloseを用いる. 「fopen/fclose」をペアで覚える. fcloseを呼び出す前のファイルの出力内容は,プログラム内 に保持されている(バッファリング)可能性がある. プログラム終了時に,閉じられていないファイルは保存される が,これに頼らない(積極的にfcloseを用いる)ほうがよい. ヒープ領域の内容を解放するには,freeを用いる. 「malloc/free」をペアで覚える. プログラム終了時に,freeされていない領域も破棄されるが, できれば頼らない(可能ならfreeを用いる)ほうがよい. リpp.458-459, p.499 20 まとめ ファイルは,実行プログラムとは異なる生存期間を持つ,バ イト列のデータ構造である. ファイル,標準入力,標準出力にアクセスするためのさまざ まな標準入出力関数が存在する. 実行後のオブジェクト確保には,mallocなどを用いる. 後始末を忘れずに. 21 プログラミング講義を終えて(1) 授業内容の関連 難しかったテーマを復習するときは,関連する(一つ前や後の) テーマを見直すのもよい. 構造体 入出力 ライブラリ関数 再帰呼び出し その他の型 前処理指令 関数 変数の有効範囲 制御文 演算子 ポインタ 記憶域管理関数 識別子 算術型・型変換 配列・文字列 22 プログラミング講義を終えて(2) 2年以降で身につけてほしいこと 自在にCでプログラミングできる能力 • 特に,ファイル処理,文字列処理,リストとツリー,スタックと キュー 「先人の知恵」を学び活用する能力 • ライブラリ関数,先生・先輩のノウハウ プログラムを設計する能力 • 与えられた課題に対して,何をすべきかを自主的に決め, プログラムコードや文章で表現すること • 「データ構造」や「関数」として適切なものを定めれば, スムーズに実装できる 入pp.301-302 23 今後の日程 1月30日(水):おさらい問題 何でも参照可.周りと相談可.成績には関係ない. 3分復習問題,40分おさらい問題,45分解説 2月4日(月):試験 80点満点 自筆ノート1冊の参照を認める 教科書・書籍,印刷資料等は参照不可 24
© Copyright 2024 ExpyDoc