情報処理Ⅱ 2008年1月28日(月).

Slides:



Advertisements
Similar presentations
情報処理Ⅱ 第10回:2004年1月13日(火). 本日のテーマ 標準入出力 標準入力と標準出力 いくつかの標準入出力関数 記憶域管理関数 malloc, free など 実行時に配列領域を確保する手法 落ち穂拾い 入力の与え方 コメントの書き方 制御文 知っておくべき「 C 言語の文法」
Advertisements

プログラミング演習II 2004年11月 30日(第6回) 理学部数学科・木村巌.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
情報処理演習C2 ファイル操作について (2).
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
プログラミング入門2 第10回 動的な領域確保 情報工学科 篠埜 功.
データ構造とアルゴリズム 第10回 mallocとfree
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
基礎プログラミングおよび演習 第9回
第13回 プログラミングⅡ 第13回
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
第8回 プログラミングⅡ 第8回
プログラミング演習II 2004年12月 21日(第8回) 理学部数学科・木村巌.
情報処理Ⅱ 第13回 2006年1月20日(金).
情報処理Ⅱ 2007年12月10日(月).
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
ファイル操作と文字列の利用.
情報処理Ⅱ 第13回 2004年01月25日(火).
10: ファイル入出力 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
情報処理Ⅱ 2007年11月5日(月).
Cプログラミング演習 第6回 ファイル処理と配列.
プログラミング 2 ファイル処理.
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第2回 ファイル処理 情報・知能工学系 山本一公
iioLoadFile()とiioMallocImageBuffer()の補足
情報処理Ⅱ 2008年1月21日(月).
精密工学科プログラミング基礎 第10回資料 (12/18実施)
プログラミング 4 記憶の割り付け.
プログラミング演習I 2003年6月25日(第10回) 木村巌.
2005年度 データ構造とアルゴリズム 第3回 「C言語の復習:再帰的データ構造」
プログラミング入門2 第11回 情報工学科 篠埜 功.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
第11回 プログラミングⅡ 第11回
P n ポインタの基礎 5 q m 5 7 int* p; int 型の変数を指すポインタ int* q; int 型の変数を指すポインタ int n=5, m=7; int 型の変数 int array[3]; int* pArray[3]; p = &n; ポインタにアドレスを代入しているのでOK.
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
精密工学科プログラミング基礎Ⅱ 第4回資料 今回の授業で習得してほしいこと: 文字列の扱い ファイル入出力の方法 コマンドライン引数の使い方
情報処理Ⅱ 第14回 2006年1月23日(月).
第4回 ファイル入出力方法.
情報処理Ⅱ 第2回:2003年10月14日(火).
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
OSが管理している、デフォルトの入出力装置 入力:stdin キーボード 出力:stdout モニタ(コマンドプロンプトの画面)
精密工学科プログラミング基礎Ⅱ 第5回資料 今回の授業で習得してほしいこと: 構造体 (教科書 91 ページ)
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
11: 動的メモリ確保 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング演習I 2003年7月2日(第11回) 木村巌.
ポインタとポインタを用いた関数定義.
ファイルの読み込み, ファイルからのデータの取り出し, ファイルの書き出し
情報処理Ⅱ 第2回 2006年10月13日(金).
第5回 プログラミングⅡ 第5回
情報処理Ⅱ 2006年11月24日(金).
情報処理Ⅱ 第7回 2004年11月16日(火).
情報処理Ⅱ 2007年1月26日(金).
コンパイラ 2012年10月11日
プログラミング 4 文字列.
アルゴリズムとデータ構造 補足資料6-1 「サンプルプログラムcat1.c」
11: 動的メモリ確保 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
情報処理Ⅱ 2006年11月8日(金).
情報処理Ⅱ 2007年2月2日(金).
プログラミング演習I 2003年6月11日(第9回) 木村巌.
情報処理Ⅱ 第2回 2004年10月12日(火).
情報処理Ⅱ 2005年11月25日(金).
プログラミング演習II 2004年11月 16日(第5回) 理学部数学科・木村巌.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
プログラミング演習II 2003年12月10日(第7回) 木村巌.
情報処理Ⅱ 小テスト 2005年2月1日(火).
情報処理Ⅱ 第8回:2003年12月9日(火).
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
Presentation transcript:

情報処理Ⅱ 2008年1月28日(月)

本日学ぶこと ファイル入出力,標準入力・標準出力 記憶域管理関数(mallocなど) 問題 ファイルを入力にとり,先頭に行番号をつけて出力できる? 標準入力の内容を行ごとに逆順に出力できる? Wakayama University 1:Wakayama 2:University ./line Wakayama University amayakaW ytisrevinU ./liner

ファイル補足 Cでは,ファイルその他への入出力方法は文法で規定されていない.代わりに豊富なライブラリ(標準入出力ライブラリ)が規定されている. ストリームは,ファイルやコンソール(キーボード入力と画面表示)などを統一的に扱うためのものである. テキストストリームとバイナリストリームに分けられる.前回と今回の授業では,テキストストリームを対象とする. 「バイト列であること」は本質ではないが,とくにバイナリストリームでは,入出力の途中にナル文字('\0')があっても問題なく処理できなければならない. 例えばバイナリストリームを扱うときにfgetsで読み出すと,入力の途中にナル文字が入っていればおかしな動作になり得る.代わりにfreadを用いるべきである. リp.455-456

行番号問題1 仕様 コマンドライン引数(複数ある場合は最初のみ)をファイル名とみなして,そのまま出力していく.ただし行の先頭には行番号をつける. 考え方 fgetcを用いて1バイトずつ読み出す. 「行の先頭」とは,「ファイルの先頭」か「改行文字('\n')の直後」のいずれか. 「今何行目を読んでいるか」を保存する変数line_countを用意する. line.c

1文字ごとの読み出し(1) while ((c = fgetc(fp)) != EOF) {...} 'a' 'b' 'c' '\n' これがストリーム ファイルabc プログラムの 内部状態 'a' 'b' 'c' '\n' FILE オブジェ クト fp '\0'がない点に注意 (文字列ではない) c = ??? 'a'

1文字ごとの読み出し(2) while ((c = fgetc(fp)) != EOF) {...} 'a' 'b' 'c' '\n' プログラムの 内部状態 'a' 'b' 'c' '\n' FILE オブジェ クト fp c = ??? EOF '\n' リp.255

EOF(1) 「ファイルの終わり(End Of File)」を表す定数. stdio.hで,#define EOF (-1)などと定義されている. unsigned char signed char ASCII (7ビット) 入p.189で「EOFを入力」という表現が見られるが, ユーザがEOFに相当する値をコンピュータに送るわけではないし, ファイルにEOFに相当する値が格納されるわけではない. (ただし,MS-DOSなどの環境で,テキストファイルの途中でも特定のバイトコードがあれば, それをファイルの終わりとみなすという使い方はある.) -128 -1 127 255 EOF ナル 文字 入p.189 リp.457

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など リp.461, p.471, p.462, p.466

標準入力と標準出力 標準入力(standard input, stdin) 標準出力(standard output, stdout) 通常はコンソール入力(キーボード入力) 標準出力(standard output, stdout) 通常はコンソール出力(画面表示) シェルのリダイレクション機能を用いて変更可能. 実行例: find ~ > files 実行例: ./liner < /usr/share/dict/words シェルのパイプ機能を用いて,あるプログラムの標準出力と別のプログラムの標準入力を接続できる. 実行例: echo '1+2*3' | bc stdin,stdoutは FILE *型の値(ファイル ポインタ)として利用 可能.ただし代入は できない. 入pp.183-186 リp.480

標準入力・標準出力とコンソール 実行環境 (OSなど) 標準入力 実行プログラム コンソール 'a' 'b' 'c' '\n' 'a' $ ./liner abc 1: abc $ 'a' 'b' 'c' '\n' '1' ':' ' ' 標準出力 実行コマンド 入力(エコーバック) 出力 入p.188

標準入力に関するライブラリ関数 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引数以降が参照する領域に格納する. 読み込みに失敗すれば,入力が進まない. なるべく使わない! なるべく使わない! リp.471-472, pp.476-477, pp.489-492

標準出力に関するライブラリ関数 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に従って標準出力に書き出す. 「標準出力に書き出す」の主語は,それぞれのライブラリ関数である. 「画面に表示する」ではない. ただし,「画面に表示される」というのは,利用するプログラマの観点とした表現であり,これは差支えない(利用する状況にも夜が). 「書き出す」「読み出す」はそれぞれ,「書き込む」「読み込む」と表現されることもある. リp.474, p.473, pp.485-488

標準入出力と標準入出力関数 標準入力・標準出力に対する関数は,標準入出力関数およびstdin, stdoutを用いた関数形式マクロにより定義されている(ことがある). 例: #define getchar() getc(stdin) 第2回レポート課題の for (k = 0; k < face_byte; k++) { putchar(((i == x && j == y) ? face_set_bold : face_set)[face_byte * c + k]); } は fwrite(((i == x && j == y) ? face_set_bold : face_set) + face_byte * c, 1, face_byte, stdout); に置き換えられる. リpp.470-471

行番号問題2 仕様 考え方 標準入力から入力をとり,各行の文字列を逆順にして標準出力に書き出す. 読むのはgetchar,書くのはputchar. 1行を読んでから,逆順に出力する. 行単位で,1行の入力内容を保持する. 標準入力は後戻りができない! 実行開始時に字数はわからないので, 「記憶域管理関数」を使用する. 「標準入力から入力し」と書いてはいけない. 一般に,入力「する」のはプログラムではないから. 一方,「出力する」と書くのは,その主語はプログラムなので,問題ない. ただし「標準出力に出力する」と表記すると,「出力」が2箇所出現してくどいので, 「標準出力に書き出す」とここでは書いた. なお,「画面に表示する」という表現がよく見られるが,これも,画面に表示「する」のは プログラムではないので,その意味では不適切であるが,古くから用いられ,また オンラインマニュアルの日本語訳でもよく見かけるので,「表示する」と書いて 試験で減点するようなことはしない. liner.c

liner.cの概要 定義した型 定義した関数 struct Line, line:1行の文字列の情報 「本体(具体的な中身,コンテンツ)」と「確保した要素数」と「格納されている要素数」をメンバに持つ. 定義した関数 init_line: 1行構造体を作成する enlarge_line: 1行構造体の本体容量を拡張する free_line: 1行構造体を開放する get_line: 1行読み出す print_reverse: 逆順に出力する

実行時の領域確保について プログラム実行時(main関数に制御が移る前)に ブロック({...})が実行されるときに static変数のオブジェクトが確保,初期化される. プログラム終了時に破棄される. ブロック({...})が実行されるときに auto変数のオブジェクトが確保される. ブロック終了時に破棄される. 記憶域管理関数(malloc, callocなど)を呼び出すと オブジェクトとして使用できる領域が確保される. freeなどの関数が呼び出されるか, プログラム終了時に破棄される. スタック領域 mallocは,リストやツリーのプログラムをCで書くときに必要になる. 例えば,ノード(節点)を自己参照構造体で定義し,新たなノードを作るときに,mallocなどでその構造体オブジェクトを生成させる. ヒープ領域 入pp.245-246

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 バイトの領域 リp.235, p.341, p.501

malloc使用の注意点 領域の値は不定であるため,必要に応じて初期化する.代わりにcallocを使用すれば,すべて0に初期化された領域が得られる. 代入される変数はポインタ変数なので,左辺値になり得る(p++; などとできる). 領域確保に失敗するとNULLを返すので, if ((p = (int *)malloc(sizeof(int) * 10))        == NULL) { エラー処理 } などとするのが一般的. リp.497

可変長配列 可変長配列の例 可変長配列をCで取り扱うときは, 実行時にその個数(の上限)がわからないような配列 行番号問題2では,「1行の本体(具体的な中身)を格納する領域」が該当する. 可変長配列をCで取り扱うときは, mallocまたはcallocで初期化し, より大きな領域が必要になったら,reallocを用いるとよい. liner.c では,line構造体も,mallocで領域を確保しfreeで開放しているが,これは可変長配列ではない. 実のところ,レポート課題2と同様に,init_line関数の中にstaticをつけたline構造体の変数を定義し,その参照を返すのでも,動作する.ただしliner.cを相当修正しないといけないが. ファイルの1行を読み出す方法については,1行の長さの上限を決めておき,そのサイズ(ナル文字も格納できるように!)のchar配列変数を確保し,そこにfgetsなどで格納することで,mallocやfreeを使わないコードにするのがポピュラーであり,2年前期の演習でもそれで問題ないと思われる.2年後期の情報ネットワーク演習では,長さに制限のない情報を受け取るためのプログラムが必要となる. リp.505

後始末 ファイルの読み書きを終えたら,fcloseを用いる. ヒープ領域の内容を解放するには,freeを用いる. 「fopen/fclose」をペアで覚える. fcloseを呼び出す前のファイルの出力内容は,プログラム内に保持されている(バッファリング)可能性がある. プログラム終了時に,閉じられていないファイルは保存されるが,これに頼らない(積極的にfcloseを用いる)ほうがよい. ヒープ領域の内容を解放するには,freeを用いる. 「malloc/free」をペアで覚える. プログラム終了時に,freeされていない領域も破棄されるが,できれば頼らない(可能ならfreeを用いる)ほうがよい. 反復(whileなど)の中で領域を動的に確保して,1回の(反復内の)処理の中で用済みになれば,freeすべきである. 一つのプログラムの実行中に多数の領域を動的に確保して相互に参照させる(線形リストや木構造をプログラムにするなど)とき,用済みになったらfreeするのは,バグのもとになりやすく,勧められない. リpp.458-459, p.499

まとめ ファイルは,実行プログラムとは異なる生存期間を持つ,バイト列のデータ構造である. ファイル,標準入力,標準出力にアクセスするためのさまざまな標準入出力関数が存在する. 実行後のオブジェクト確保には,mallocなどを用いる. 後始末を忘れずに.

プログラミング講義を終えて(1) 授業内容の関連 難しかったテーマを復習するときは,関連する(一つ前や後の)テーマを見直すのもよい. 構造体 入出力 ライブラリ関数 再帰呼び出し その他の型 前処理指令 関数 変数の有効範囲 (新設) 記憶域管理関数 (名称変更) 算術型⇒算術型・型変換 ファイル入出力⇒入出力 制御文 演算子 ポインタ 記憶域管理関数 識別子 算術型・型変換 配列・文字列

プログラミング講義を終えて(2) 2年以降で身につけてほしいこと 自在にCでプログラミングできる能力 特に,ファイル処理,文字列処理,リストとツリー,スタックとキュー 「先人の知恵」を学び活用する能力 ライブラリ関数,先生・先輩のノウハウ プログラムを設計する能力 与えられた課題に対して,何をすべきかを自主的に決め,プログラムコードや文章で表現すること 「データ構造」や「関数」として適切なものを定めれば, スムーズに実装できる 入pp.301-302

今後の日程 1月30日(水):おさらい問題 2月4日(月):試験 何でも参照可.周りと相談可.成績には関係ない. 3分復習問題,40分おさらい問題,45分解説 2月4日(月):試験 80点満点 自筆ノート1冊の参照を認める 教科書・書籍,印刷資料等は参照不可