情報処理II

情報処理Ⅱ
第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