情報処理Ⅱ 2007年1月26日(金) 本日学ぶこと ファイル入出力,標準入力・標準出力 記憶域管理関数(mallocなど) 問題 ファイルを入力にとり,先頭に行番号をつけて出力できる? 標準入力(キーボードなど)からの入力に対して,先頭に行番 号を右揃えでつけて出力できる? 2 ファイルとは(復習) 補助記憶装置に保存する単位となる,データの集まり. プログラムが終了しても,内容が保持されるデータ構造. (比較)変数の値はメモリ上にあるため,プログラム終了時に破 棄される. コンピュータの電源を切って入れ直しても,保持されていること が多い. ストリームと呼ばれるバイト列として,読み書き可能. バイト列とは? char配列で表現できるデータ構造. '\0' で終わるものではなく,途中に '\0' があってもいい という点が,文字列と異なる. 3 ファイル操作のライブラリ関数(復習) 操作対象(関数への入力)は,ファイルポインタ. stdio.h で定義されているFILE型のポインタ. 例: FILE *fp; ライブラリ関数 fopen : ファイルを開き(プログラムから使えるようにし), ファイルポインタを返す. fgets : 指定されたバイト数(文字数)を読み出す. fprintf : printfと同様の形式で,ファイルに出力する. fclose : 開いたファイルを閉じる(プログラムから使えない ようにする). fgetc : 1バイト(1文字)読み出す. 4 行番号問題1 仕様 コマンドライン引数(複数ある場合は最初のみ)をファイル名と みなして,そのまま出力していく.ただし行の先頭には行番号 をつける. 考え方 fgetcを用いて1バイトずつ読み出す. 「行の先頭」とは,「ファイルの先頭」か「改行文字('\n')の直 後」のいずれか. 「今何行目を読んでいるか」を保存する変数line_countを用 意する. 5 1文字ごとの読み出し(1) while ((c = fgetc(fp)) != EOF) {...} プログラムの 内部状態 fp これがストリーム ファイルabc 'a' 'b' 'c' '\n' FILE オブジェ クト c = ??? 'a' '\0'がない点に注意 (文字列ではない) 6 1文字ごとの読み出し(2) while ((c = fgetc(fp)) != EOF) {...} プログラムの 内部状態 fp ファイルabc 'a' 'b' 'c' '\n' FILE オブジェ クト c = EOF ??? '\n' 7 EOF(1) 「ファイルの終わり(End Of File)」を表す定数. stdio.hで,#define EOF (-1)などと定義されている. unsigned char signed char ASCII (7ビット) -128 127 -1 0 EOF 255 ヌル 文字 8 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など 9 標準入力と標準出力 標準入力(standard input, stdin) 標準出力(standard output, stdout) 通常はコンソール出力(画面表示) シェルのリダイレクション機能を用いて変更可能. 通常はコンソール入力(キーボード入力) 実行例: find ~ > files 実行例: ./liner < /usr/share/dict/words シェルのパイプ機能を用いて,あるプログラムの標準出力と 別のプログラムの標準入力を接続できる. 実行例: echo '1+2*3' | bc 10 標準入力・標準出力とコンソール 実行環境 (OSなど) 標準入力 コンソール 'a' 'b' 'c' '\n' 実行プログラム '1' ':' ' ' 'a' 'b' 'c' '\n' $ ./liner abc 1: abc $ 標準出力 実行コマンド 入力(エコーバック) 出力 11 標準入力に関するライブラリ関数 int getchar(void); char *gets(char *s); 標準入力から1文字(1バイト)読み込む. 戻り値はunsigned char型の値,もしくは定数EOF. なるべく使わない! 標準入力から1行読み込み,sの指す領域に格納する. 1行が,sの領域サイズよりも大きいとしても,そのまま格納しよ うとする. なるべく使わない! int scanf(const char *format, ...); formatに従って標準入力から入力を読み込み,第2引数以 降が参照する領域に格納する. 読み込みに失敗すれば,入力が進まない. 12 標準出力に関するライブラリ関数 int putchar(int c); char *puts(const char *s); cをunsigned char型に変換した上で,標準出力に(1文 字)書き出す. 文字列sと改行文字を標準出力に書き出す. int printf(const char *format, ...); formatに従って標準出力に書き出す. 13 標準入出力と標準入出力関数 標準入力・標準出力に対する関数は,標準入出力関数およ びstdin, stdoutを用いた関数形式マクロにより定義さ れている(ことがある). 例: #define getchar() getc(stdin) 14 行番号問題2 仕様 標準入力から入力をとり,そのまま標準出力に書き出す. ただし行の先頭には行番号を右揃えでつける. 考え方 読むのはgetchar(文字ごと),書くのはprintf(行ごと). すべての入力を終えた時点で,行数が確定し,そこから出力す る. 入力内容を行単位で保存する. • 標準入力は後戻りができない! • 実行開始時に行数はわからないので, 「記憶域管理関数」を使用する. 15 liner.cの概要(1) 定義した構造体 line:1行の文字列の情報 line_array:行単位で分割した入力の情報 いずれも,「本体(具体的な中身,コンテンツ)」と「確保した要 素数」と「格納されている要素数」をメンバに持つ. 定義した関数 get_line_array:入力を読み出す get_line:1行読み出す put_lines:行番号を付けて出力する get_digit_width:桁数を求める 16 liner.cの概要(2) 「右揃え」の出力方法 printf("%*d: ", width, i); • iの値を,width文字分の右揃えで出力する. • width=3, i=10なら," 10: "が出力される. • 「*」を用いて,実行時に桁数を指定できる. ライブラリ関数printfの補足 様々な変換規則を持つ. 可変引数関数である. ファイルへ出力はfprintf, 文字列に書き出すのはsprintf 17 実行時の領域確保について プログラム実行時(main関数に制御が移る前)に ブロック({...})が実行されるときに static変数のオブジェクトが確保,初期化される. • プログラム終了時に破棄される. auto変数のオブジェクトが確保される. • ブロック終了時に破棄される. スタック領域 記憶域管理関数(malloc, callocなど)を呼び出すと オブジェクトとして使用できる領域が確保される. • freeなどの関数が呼び出されるか, ヒープ領域 プログラム終了時に破棄される. 18 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 バイトの領域 19 malloc使用の注意点 領域の値は不定であるため,必要に応じて初期化する.代 わりにcallocを使用すれば,すべて0に初期化された領域 が得られる. 代入される変数はポインタ変数なので,左辺値になり得る (p++; などとできる). 領域確保に失敗するとNULLを返すので, if ((p = (int *)malloc(sizeof(int) * 10)) == NULL) { エラー処理 } などとするのが一般的. 20 可変長配列 可変長配列の例 実行時にその個数(の上限)がわからないような配列 行番号問題2では,「1行の文字列」と「標準入力より獲得する 入力(文字列の配列)」が該当する. 可変長配列をCで取り扱うときは, mallocまたはcallocで初期化し, より大きな領域が必要になったら,reallocを用いるとよい. 21 後始末 ファイルの読み書きを終えたら,fcloseを用いる. 「fopen/fclose」をペアで覚える. fcloseを呼び出す前のファイルの出力内容は,プログラム内 に保持されている(バッファリング)可能性がある. プログラム終了時に,閉じられていないファイルは保存される が,これに頼らない(積極的にfcloseを用いる)ほうがよい. ヒープ領域の内容を解放するには,freeを用いる. 「malloc/free」をペアで覚える. プログラム終了時に,freeされていない領域も破棄される.基 本的に,これに頼ってよい(積極的にはfreeを用いない). 22 まとめ ファイルは,実行プログラムとは異なる生存期間を持つ,バ イト列のデータ構造である. ファイル,標準入力,標準出力にアクセスするためのさまざ まな標準入出力関数が存在する. 実行後のオブジェクト確保には,mallocなどを用いる. 後始末を忘れずに. 23 プログラミング講義を終えて(1) 授業内容の関連 難しかったテーマを復習するときは,関連する(一つ前や後の) テーマを見直すのもよい. 構造体 入出力 ライブラリ関数 再帰呼び出し その他の型 前処理指令 関数 変数の有効範囲 制御文 演算子 ポインタ 記憶域管理関数 識別子 算術型・型変換 配列・文字列 24 プログラミング講義を終えて(2) 2年以降で身につけてほしいこと 自在にCでプログラミングできる能力 • 特に,ファイル処理,文字列処理,リストとツリー,スタックと キュー 「先人の知恵」を学び活用する能力 • ライブラリ関数,先生・先輩のノウハウ プログラムを設計する能力 • 与えられた課題に対して,何をすべきかを自主的に決め, プログラムコードや文章で表現すること 25 今後の日程 1月31日(水):金曜の授業だが,当科目は実施しない. 2月2日(金):おさらい問題 11月8日に補講実施済のため. 何でも持ち込み可.相談可.成績には関係ない. 5分復習問題,40分おさらい問題,45分解説 2月9日(金):試験 80点満点 自筆ノート1冊と,C言語の教科書1冊の持込可 26
© Copyright 2024 ExpyDoc