情報処理Ⅱ 2007年1月19日(金).

Slides:



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

プログラミング演習 II 2005 年 1 月 19 日(第 9 回) 理学部数学科・木村巌. 前回までの復習 共用体( union type ) 共用体( union type ) 列挙 (enumerated type ) 列挙 (enumerated type ) 構造体、構造体のポインタ、
情報処理Ⅱ 第12回 2005 年 01 月 18 日(火). 2 本日学ぶこと 前処理指令 関数プロトタイプ ライブラリ関数の活用 関数は  すでにあるものを使うか?  関数として定義するか?  関数形式マクロとして定義するか?
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
システムプログラミング 第5回 情報工学科 篠埜 功 ヒアドキュメント レポート課題 main関数の引数 usageメッセージ
第2回ネットワークプログラミング 中村 修.
OSとコマンド OS:コンピュータを使うための基本プログラム コマンド:OS上で使用できる命令 OS本体であるカーネルの内部コマンド
第13回 プログラミングⅡ 第13回
12: コマンドライン引数 C プログラミング入門 総機1 (月1) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング演習II 2004年10月19日(第1回) 理学部数学科・木村巌.
記憶クラス 変数をどのような記憶領域に割り当てるかを指定するのが記憶クラス 記憶クラスには、自動変数、静的変数、外部変数などがある。
第8回 プログラミングⅡ 第8回
第6章 2重ループ&配列 2重ループと配列をやります.
プログラミング演習II 2004年12月 21日(第8回) 理学部数学科・木村巌.
情報処理Ⅱ 第13回 2006年1月20日(金).
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
情報処理Ⅱ 2006年1月13日(金).
関数 関数とスタック.
情報処理Ⅱ 第13回 2004年01月25日(火).
10: ファイル入出力 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
プログラミング2 関数
プログラミング 2 ファイル処理.
プログラミング論 ファイル入出力
Cプログラミング演習.
第10回関数 Ⅱ (ローカル変数とスコープ).
情報・知能工学系 山本一公 プログラミング演習Ⅱ 第2回 ファイル処理 情報・知能工学系 山本一公
情報処理Ⅱ 2008年1月21日(月).
プログラミング 4 記憶の割り付け.
プログラミング演習I 2003年6月25日(第10回) 木村巌.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第9回関数Ⅰ (簡単な関数の定義と利用) 戻り値.
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 プログラミングⅡ 第7回
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
プログラミング論 ファイル入出力
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
第14章 ファイル操作 14.1 ファイルへの書き込み 14.2 ファイルからの読み込み 14.3 ファイルへの追加書き込み
情報処理Ⅱ 第14回 2006年1月23日(月).
第4回 ファイル入出力方法.
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
配列変数とポインタ 静的確保と動的確保 ポインタ配列 2次元配列 時間計測 第1回レポートの課題
疑似乱数, モンテカルロ法によるシミュレーション
システムプログラミング 第7回、8回 ファイルシステム関連の システムコール
C言語 はじめに 2016年 吉田研究室.
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
プログラミング演習I 2003年7月2日(第11回) 木村巌.
ファイルの読み込み, ファイルからのデータの取り出し, ファイルの書き出し
情報処理Ⅱ 2005年1月25日(火) レポート課題2の解説.
第5回 プログラミングⅡ 第5回
情報処理Ⅱ 2006年11月24日(金).
情報処理Ⅱ 第7回 2004年11月16日(火).
情報処理Ⅱ 2007年1月26日(金).
プログラミング 4 文字列.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
情報処理Ⅱ 2007年2月2日(金).
プログラミング演習I 2003年6月11日(第9回) 木村巌.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
情報処理Ⅱ 2005年11月25日(金).
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
情報処理Ⅱ 第9回:2003年12月16日(火).
第4回 配列.
情報処理Ⅱ 小テスト 2005年2月1日(火).
第5回 配列.
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
12: コマンドライン引数 C プログラミング入門 基幹2 (月4) Linux にログインし、以下の講義ページ を開いておくこと
Presentation transcript:

情報処理Ⅱ 2007年1月19日(金)

本日学ぶこと 前処理指令 マクロ 問題 サイコロを何度も振って,全ての目が最低1回出るまで,何回振らなければならないか? 最小6回,上限なし(∞回?) 欲しいのは現実的な値 100面のサイコロだったら?

前処理とコンパイル(1) 前処理・コンパイル・アセンブル・リンクの各処理は通常,コンパイラ(ccなど)が一手に引き受ける. ソースファイル (前処理前) ソースファイル (前処理後) 前処理 コンパイル アセンブル オブジェクト ファイル 実行ファイル リンク 前処理・コンパイル・アセンブル・リンクの各処理は通常,コンパイラ(ccなど)が一手に引き受ける.

前処理とコンパイル(2) 前処理は, 前処理のコマンド(プリプロセッサ)は,cpp 狭義には,「コンパイルに先立って行われる処理」であり,したがってコンパイルとは別 広義には,ccでコンパイルすれば自動的に処理してくれる,という意味でコンパイル作業の一部 前処理のコマンド(プリプロセッサ)は,cpp Cの前処理以外にも使用可能

前処理指令 (Preprocessing directive) 「プリプロセッサ 指令」ともいう マクロ定義(#define) オブジェクト形式マクロ ⇒「定数」の定義 関数形式マクロ ⇒「関数もどき」の定義 マクロとは…コンピュータ関連の作業において,複数の機能や意味をまとめて扱えるようにしたもの ソースファイルの取り込み(#include) ⇒12月8日参照 条件付きコンパイル(#if ... #endif など) 「マクロとは」の説明は, http://d.hatena.ne.jp/keyword/%A5%DE%A5%AF%A5%ED による.

要素数は,コンパイル時に評価可能な定数式なので,問題なし オブジェクト形式マクロ(1) 語の置き換えを行う. #define 置換対象 置換内容 #define WORD_SIZE 6 と記述すると,それ以降 int a[WORD_SIZE]; は int a[6]; と同じ意味になる. プログラム修正により変わり得る定数値があるときに,よく用いられる. 配列の上限値,他と区別する値など. うまく使うことで,定数値を変えるときのプログラム修正箇所を少なくできる. 要素数は,コンパイル時に評価可能な定数式なので,問題なし 列挙型のほうがいいかも

オブジェクト形式マクロ(2) 注意点 前提: #define WORD_SIZE 6+1 単純に置き換える. int a[WORD_SIZE * 2]; は,int a[6+1 * 2]; に置き換えられる(意図した動作ではない). ⇒ #define WORD_SIZE (6+1) とすればよい. 語のみを置き換える. print_WORD_SIZE() のような「語の一部」や,printf("WORD_SIZE"); のような「文字列中の語」は,置き換えない.

オブジェクト形式マクロ(3) 注意点(続き) 予約語も置換可能. #define char signed char は文法上問題ないが,よい書き方ではない. typedef signed char schar; とすべきである. 置換内容のない名前も定義できる. #define DEBUG 末尾にセミコロンをつけない. #define WORD_SIZE 6; は(たいていの場合)間違い.

関数形式マクロ(1) オブジェクト形式マクロとほぼ同じ書式. 置換対象に「(…)」をつける. #define pint(x) printf("%d\n",x) に対して,pint(a+1); は printf("%d\n", a+1); に置き換えられる. 複数の引数をとることもできる.そのときは,置換対象の各引数をカンマで区切る. カッコ内に何も書かなければ,引数なしの関数形式マクロが定義される.

関数形式マクロ(2) 注意点 単純に置き換える. #define mul(x, y) x*y に対して, z=mul(6+1,2); としたとき,z=14ではなくz=8となる. ⇒ #define mul(x, y) ((x)*(y)) のように, 置換対象の引数と,評価式全体にカッコをつける. 置換内容の中に,引数を2箇所以上書くことができる. その回数だけ置換される. #define triple(x) ((x)+(x)+(x)) に対してb=triple(++a); と書くと,b=((++a)+(++a)+(++a)); となる.

関数形式マクロ(3) 置換内容の中で「#引数」と書くと,引数を文字列にできる. #define pint(x) printf(#x " = %d\n", x) に対して,pint(a+1); は printf("a+1" " = %d\n", a+1); に置き換えられる. 通常の関数定義では,変数名を 引数にとってその文字列を得る ことはできない. 「文字列リテラルの連結」により,これは printf("a+1 = %d\n", a+1); と同じとなる.

関数か関数形式マクロか 関数…「機能」を正確に表現したいとき マクロ…「機能」を簡便に表現したいとき 例:int square_int(int x) { return x * x; } 引数や戻り値の型に制約される. 関数呼び出しのオーバーヘッドがある. ローカル変数や制御文を活用できる. 実引数が++aなどのときも,その評価は一度だけ. マクロ…「機能」を簡便に表現したいとき 例:#define square_int(x) ((x) * (x)) 引数や評価式に型はない. (狭義の)コンパイル前に展開され,オーバーヘッドは少ない. ローカル変数や制御文は使用しにくい. (マクロ利用側の)引数は,置換内容の回数だけ評価される.

# define pint( x ) printf ( #x " = %d\n" , x ) 前処理指令と空白・コメント ...不可 ...必須 # define pint( x ) printf ( #x " = %d\n" , x ) ...任意 一つの前処理指令は,1行で書かなければならない.ただし, 行末に「\」を置くことで,複数行で書ける. 関数形式マクロの場合,括弧の途中で改行できる. 前処理指令の中でコメント(/* */ もしくは //)を書くと,前処理時に空白文字に置き換えられる.

サイコロ問題 仕様 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ 目の数は6つ.ただし変更の可能性あり. サイコロの目は1~6のいずれかとする. 出た目はその都度出力する. 全ての目が出たら,何回振ったかを出力し,終了する. ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪

サイコロ問題の考え方(1) サイコロの振り方 ライブラリ関数のrandを用いる あらかじめ #include <stdlib.h> int a = rand(); により,aにはint型の値が一つ代入される.この値は,ある範囲の中でどの値も等しい確率で選ばれる(一様乱数). int spot = rand() % 6; で,spot には 0~5 のいずれかが代入される. int spot = rand() % 6 + 1; とすればいい! 擬似乱数のため,何度実行しても同じ目が出る.これを変えるには,ライブラリ関数のsrandを呼び出して,適切な値の種を与えればよい.

サイコロ問題の考え方(2) 「全ての目が出る」とは? int spot_counter[SPOT_MAX + 1]; 目ごとに出た回数 特定の目がまだ出ていないかの判定は, if (spot_counter[spot] == 0) 全ての目が出たかを,この配列変数だけで判定することはできるが,非効率 int counter_unfound = SPOT_MAX; まだ出ていない目がいくつあるか 一つずつ減らしていき,0になれば「全ての目が出た」

サイコロ問題で定義したマクロ #define SPOT_MAX 6 目の数を表す,オブジェクト形式マクロ ここ以外で「6」と書かない.これにより,目の数が変わるようなプログラムにも対処しやすい. #define cast_dice(spot_max) (rand() % (spot_max) + 1) サイコロを1回振って,出た目を返す,関数形式マクロ 呼び出し元では int spot = cast_dice(SPOT_MAX); であり,これは int spot = (rand() % (SPOT_MAX) + 1); になる. 「cast_dice(100*5)」のように使うことも可能

条件付きコンパイル(1) #if 定数式 … #endif 定数式が真のときに「…」を残し,そうでなければ「…」を捨てる. 定数式の評価や「…」の取捨は,前処理時(≠実行時)に行われる.

条件付きコンパイル(2) 「#if 定数式」に代えて,「#ifdef 名前」や 「#ifndef 名前」も利用可能. 「#else」や「#elif 定数式」も記述可能. 条件付きコンパイルは入れ子にできる. 条件付きコンパイル 参考: Cのif文 #if 条件式1 … #elif 条件式2 #else #endif if (条件式1) { … } else if (条件式2) { } else { }

ヘッダファイルで条件付きコンパイル ある環境の /usr/include/stdio.h より #ifndef _STDIO_H #define _STDIO_H 1 … #endif /* !_STDIO_H */ この記述により,複数のファイルに #include <stdio.h> があっても問題なく動作する. ヘッダファイルの中で,別のヘッダファイルをインクルードすることがある. _STDIO_H を定義して「…」を獲得するのは,1回だけ.

次に学ぶこと ファイル入出力 問題 これまでそのプログラムを何回実行したか,記録できる? ソースファイルの先頭に,右揃えで行番号をつけて出力できる?

ファイルとは 補助記憶装置に保存する単位となる,データの集まり. プログラムが終了しても,内容が保持されるデータ構造. バイト列とは? (比較)変数の値はメモリ上にあるため,プログラム終了時に破棄される. コンピュータの電源を切って入れ直しても,保持されていることが多い. ストリームと呼ばれるバイト列として,読み書き可能. バイト列とは? char配列で表現できるデータ構造. '\0' で終わるものではなく,途中に '\0' があってもいいという点が,文字列と異なる.

実行回数管理プログラム 仕様 考え方 ./count を実行すると,count.txt というファイルに実行回数が保存される.

ファイルポインタ Cでファイルを操作するには,ファイルポインタを使用する. FILE オブジェクト fp stdio.h で定義されているFILE型のポインタ. 例: FILE *fp; FILE オブジェクト fp

ファイル操作のライブラリ関数(1) FILE *fopen(char *path, char *mode); ファイルを開き(プログラムから使えるようにし),ファイルポインタを返す. 第1引数はファイル名(「パス名」ともいう). 第2引数が "r" なら,読み込み専用で開く. 第2引数が "w" なら,書き込み専用で開く. char *fgets(char *s, int size, FILE *stream); 「size-1バイト」,「改行文字まで」,「ファイルの終わりまで」のうち最小のバイト数を読み込んで,s が指し示す配列領域に格納し,最後に '\0' をつける.

ファイル操作のライブラリ関数(2) int fprintf(FILE *stream, const char *format, ...); 比較: int printf(const char *format, ...); int fclose(FILE *fp); 開いたファイルを閉じる(プログラムから使えないようにする).

ifとfopenの組み合わせ コード例 if ((fp = fopen("count.txt", "w")) == NULL) { printf("failed to open file: count.txt\n"); return 1; } ファイルを開くことができなければ,メッセージを出力して,関数の処理を終える.開ければ,fpにファイル構造体のポインタが代入され,あとのファイル処理で利用できる. カッコの対応に注意. × if (fp=fopen(ファイル名, "w"))==NULL) × if (fp=fopen(ファイル名, "w")==NULL) この例では,「fpへの代入」と「if文」を分けて書いてもよい.しかし「代入」と「while文」を同時に書く(分けると保守性を損なう)ことが多いので,この記述に慣れてほしい.

(余談)入力方法 プログラム内に書き込む. コマンドライン引数から獲得する. 標準入力(キーボード入力)から獲得する. int a = 44, b = 16; コマンドライン引数から獲得する. int main(int argc, char *argv[]) 標準入力(キーボード入力)から獲得する. scanf,getchar,fgetsなど ファイルをアクセスする. fopen,freadなど 入力 出力 実行 プログラム

入力方法の得失(1) プログラム内に書き込む(埋め込む). コマンドライン引数から獲得する. ハードコーディング(hardcode)とも呼ばれる. 手軽(原始的)であり,他の環境でも実行しやすい. 入力の値の型は,プログラム内で指定できる. 入力の値が変わるたびにコンパイルが必要. コマンドライン引数から獲得する. 入力の値が変わってもコンパイル不要. 実行時に毎回引数指定が必要. ただしシェルのヒストリ機能を使えば省力化できる. 入力サイズには(現実的な)制限がある. 入力の値の型は必ず文字列. 「メリットとデメリット」のこと.ある目的を達成するための手段が複数あるとき,どれを選ぶかの判断材料になる.

入力方法の得失(2) 標準入力から獲得する. ファイルをアクセスする. 入力の値が変わってもコンパイル不要. 入力サイズに制限がない. 実行時に毎回入力が必要. ただしシェルのリダイレクション機能を使えば省力化できる. 入力の値の型は原則として文字または文字列. ファイルをアクセスする. 最も洗練された手法. 標準入力の特長を受け継ぐ. ファイルの内容を変えなければ,同じ入力が得られる. プログラムは複雑になる.

入力方法の比較 ファイルアクセス コマンドライン引数 標準入力 埋め込み 洗練 柔軟 静的 動的 原始的 固定 (main関数実行前に 入力値が決まる) 動的 (実行中に入力値を 与える) 埋め込み 原始的 固定

まとめ 前処理指令をうまく使えば,読みやすく保守しやすいプログラムを書くことができる. 前処理は,コンパイルの前に行われる.そのため,前処理指令の書式はCの文法と異なる. ファイル操作により,プログラムの外から情報を受け取ったり,情報を保存したりすることができる.

スケジュール 第13回:1月26日(金) (1月31日(水)は金曜日の授業日だが,授業はしない) 第14回:2月2日(金) ファイル入出力(続き),標準入出力,mallocなど (1月31日(水)は金曜日の授業日だが,授業はしない) 第14回:2月2日(金) おさらい問題を実施 試験:2月9日(金) 13:10~14:40 Cの書籍1冊および自筆ノート1冊の持込可