情報処理Ⅱ 第13回 2004年01月25日(火) 本日学ぶこと 入力のとり方 ファイル入出力,標準入力・標準出力 記憶域管理関数(mallocなど) 問題 ファイルを入力にとり,先頭に行番号をつけて出力できる? 標準入力(キーボードなど)からの入力に対して,先頭に行番 号を右揃えでつけて出力できる? 2 入力のとり方 プログラム内に書き込む. コマンドライン引数から獲得する. int main(int argc, char *argv[]) 標準入力(キーボード入力)から獲得する. int a = 44, b = 16; scanfを用いる. getcharやfgetsなどを用いる. ファイルをアクセスする. 入力 出力 fopenやfreadなどを用いる. 実行 プログラム 3 入力のとり方:得失(1) プログラム内に書き込む(埋め込む). ハードコーティングとも呼ばれる. 手軽(原始的)であり,他の環境でも実行しやすい. 入力の値の型は,プログラム内で指定できる. 入力の値が変わるたびにコンパイルが必要. 「メリットとデメ リット」のこと.あ る目的を達成す るための手段が 複数あるとき, どれを選ぶかの 判断材料になる. コマンドライン引数から獲得する. 入力の値が変わってもコンパイル不要. 実行時に毎回引数指定が必要.ただしシェルのヒストリ機能を 使えば省力化できる. 入力サイズには(現実的な)制限がある. 入力の値の型は必ず文字列. 4 入力のとり方:得失(2) 標準入力から獲得する. 入力の値が変わってもコンパイル不要. 入力サイズに制限がない. 実行時に毎回入力が必要.ただしシェルのリダイレクション機 能を使えば省力化できる. 入力の値の型は原則として文字または文字列. ファイルをアクセスする. 最も洗練された手法. 標準入力の特長を受け継ぐ. ファイルの内容を変えなければ,同じ入力が得られる. プログラムは複雑になる. 5 入力のとり方:比較 洗練 柔軟 コマンドライン引数 ファイルアクセス 標準入力 静的 動的 (main関数実行前に 入力値が決まる) 埋め込み (実行中に入力値を 与える) 原始的 固定 6 ファイルとは プログラムが終了しても,内容が保持されるデータ構造. 比較:オブジェクトは,auto変数,static変数,ヒープ領域の 変数のいずれも,プログラム終了時には破棄される. コンピュータの電源を切って入れ直しても,保持されていること char配列.ただし,文字列ではない. が多い. 「ストリーム」と呼ばれるバイト列として,読み書き可能. UNIXでは,すべての入出力はファイルを読み書きすることに よって行われる.キーボードや画像でさえも,ファイルシステ ム上のファイルである.(『プログラミング言語C』一部改変) 7 標準入出力関数 操作対象(関数への入力)は,ファイルポインタ. stdio.h で定義されている「ファイル構造体」のポインタ. 型はFILE * ライブラリ関数 fopen : ファイルを開き(プログラムから使えるようにし), ファイルポインタを返す. fgetc : 1文字読み出す. fgets : 指定されたバイト数(文字数)を読み出す. fprintf : printfと同様の形式で,ファイルに出力する. fclose : 開いたファイルを閉じる(プログラムから使えない ようにする). 8 行番号問題1 仕様 コマンドライン引数(複数ある場合は最初のみ)をファイル名と みなして,そのまま出力していく.ただし行の先頭には行番号 をつける. 考え方 fgetcを用いて1文字ずつ読み出す. 「行の先頭」とは,「ファイルの先頭」か「改行文字('\n')の直 後」のいずれか. 「今何行目を読んでいるか」を保存する変数line_countを用 意する. 9 1文字ごとの読み出し(1) while ((c = fgetc(fp)) != EOF) {...} プログラムの 内部状態 fp c = ??? 'a' ファイルabc 'a' 'b' 'c' '\n' FILE 構造体 '\0'がない点に注意 (文字列ではないから) 10 1文字ごとの読み出し(2) while ((c = fgetc(fp)) != EOF) {...} プログラムの 内部状態 fp ファイルabc 'a' 'b' 'c' '\n' FILE 構造体 c = EOF ??? '\n' 11 EOF(1) 「ファイルの終わり(End Of File)」を表す定数. stdio.hで,#define EOF (-1)などと定義されている. unsigned char signed char ASCII (7ビット) -128 127 -1 0 EOF 255 ナル 文字 12 EOF(2) 文字単位で読み書きするとき int型を使用する. • signed char型だと,255をEOFと区別できない. • unsigned char型だと,EOFが来ても255にしてしまう. 読み出してEOFが来たら,そこでおしまいにする. 文字列単位で読み書きするとき char配列またはchar*型を使用する. 13 標準入力と標準出力 標準入力(standard input, stdin) 標準出力(standard output, stdout) 通常はコンソール出力(画面表示) シェルのリダイレクション機能を用いて変更可能. 通常はコンソール入力(キーボード入力) 実行例: find ~ > files 実行例: ./liner < /usr/share/dict/words シェルのパイプ機能を用いて,あるプログラムの標準出力と 別のプログラムの標準入力を接続できる. 実行例: echo '1+2*3' | bc 14 標準入力・標準出力とコンソール 実行環境 (OSなど) 標準入力 コンソール 'a' 'b' 'c' '\n' 実行プログラム '1' ':' ' ' 'a' 'b' 'c' '\n' 標準出力 実行コマンド 入力(エコーバック) 出力 15 標準入力に関するライブラリ関数 int getchar(void); char *gets(char *s); 標準入力から1文字(1バイト)読み込む. 戻り値はunsigned char型の値,もしくは定数EOF. なるべく使わない! 標準入力から1行読み込み,sの指す領域に格納する. 1行が,sの領域サイズよりも大きいとしても,そのまま格納しよ うとする. なるべく使わない! int scanf(const char *format, ...); formatに従って標準入力から入力を読み込み,第2引数以 降が参照する領域に格納する. 読み込みに失敗すれば,入力が進まない. 16 標準出力に関するライブラリ関数 int putchar(int c); char *puts(const char *s); cをunsigned char型に変換した上で,標準出力に(1文 字)出力する. 文字列sと改行文字を標準出力に出力する. int printf(const char *format, ...); formatに従って標準出力に出力する. 17 標準入出力と標準入出力関数 標準入力・標準出力に対する関数は,標準入出力関数およ びstdin, stdoutを用いた関数形式マクロにより定義さ れている(ことが多い). 例: #define getchar() getc(stdin) 18 行番号問題2 仕様 標準入力をそのまま標準出力に出力していく.ただし行の先頭 には行番号を右揃えでつける. 考え方 読むのはgetchar(文字ごと),書くのはprintf(行ごと). すべての入力を終えた時点で,行数が確定し,そこから出力す る. 入力内容を行単位で保存する.(標準入力は後戻りができな い!) • 実行開始時に行数はわからないので, 「記憶域管理関数」を使用する. 19 実行時の領域確保について プログラム実行時(main関数に制御が移る前)に ブロック({...})が実行されるときに static変数のオブジェクトが確保,初期化される. • プログラム終了時に破棄される. auto変数のオブジェクトが確保される. • ブロック終了時に破棄される. スタック領域 記憶域管理関数(malloc, callocなど)を呼び出すと オブジェクトとして使用できる領域が確保される. • freeなどの関数が呼び出されるか, ヒープ領域 プログラム終了時に破棄される. 20 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 バイトの領域 21 malloc使用の注意点 領域の値は不定であるため,必要に応じて初期化する.代 わりにcallocを使用すれば,すべて0に初期化された領域 が得られる. 代入される変数はポインタ変数なので,左辺値になり得る (p++; などとできる). 領域確保に失敗するとNULLを返すので, if ((p = (int *)malloc(sizeof(int) * 10)) == NULL) { エラー処理 } などとするのが一般的. 22 可変長配列 可変長配列の例 実行時にその個数(の上限)がわからないような配列 行番号問題2では,「1行の文字列(文字配列)」と「行ごとの文 字列(文字列配列)」が該当する. 可変長配列をCで取り扱うときは, mallocまたはcallocで初期化し, より大きな領域が必要になったら,reallocを用いるとよい. • 「より大きな領域が必要」かどうかを知るために,確保した 領域サイズを保存する変数(int型)を別途用意する. 23 後始末 ファイルの読み書きを終えたら,fcloseを用いる. 「fopen/fclose」と覚える. fcloseを呼び出す前のファイルの出力内容は,プログラム内 に保持されている(バッファリング)可能性がある. プログラム終了時に,閉じられていないファイルは保存される が,これに頼らない(積極的にfcloseを用いる)ほうがよい. ヒープ領域の内容を解放するには,freeを用いる. 「malloc/free」と覚える. プログラム終了時に,freeされていない領域も破棄される.基 本的に,これに頼ってよい(積極的にはfreeを用いない). 24 まとめ ファイルは,実行プログラムとは異なる生存期間を持つ,バ イト列のデータ構造である. ファイル,標準入力,標準出力にアクセスするためのさまざ まな標準入出力関数が存在する. 実行後のオブジェクト確保には,mallocなどを用いる. 後始末を忘れずに. 25 今後の日程 2月1日:おさらい問題 何でも持ち込み可.相談可.成績には関係ない. 5分復習問題,55分おさらい問題,30分解説 2月8日:試験 75点満点 自筆ノート1冊と,C言語の教科書1冊のみ持込可 26
© Copyright 2024 ExpyDoc