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