情報処理II

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