情報処理Ⅱ 2006年1月13日(金).

Slides:



Advertisements
Similar presentations
情報処理Ⅱ 第12回 2005 年 01 月 18 日(火). 2 本日学ぶこと 前処理指令 関数プロトタイプ ライブラリ関数の活用 関数は  すでにあるものを使うか?  関数として定義するか?  関数形式マクロとして定義するか?
Advertisements

情報・知能工学系 山本一公 プログラミング演習Ⅱ 第3回 配列(1) 情報・知能工学系 山本一公
情報処理Ⅱ 2006年12月8日(金).
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
応用理工学情報処理 第1回(2015年10月 5日) 月曜日担当 前島展也 Manaba
情報基礎演習B 後半第5回 担当 岩村 TA 谷本君.
数理情報工学演習第一C プログラミング演習 (第3回 ) 2014/04/21
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
第2回ネットワークプログラミング 中村 修.
第6章 2重ループ&配列 2重ループと配列をやります.
プログラミング演習Ⅰ 課題2 10進数と2進数 2回目.
関数 関数とスタック.
第7回 条件による繰り返し.
情報基礎及び演習 プログラミング基礎① 電気・佐藤亮一.
岩村雅一 知能情報工学演習I 第8回(後半第2回) 岩村雅一
ちょっとした練習問題① 配列iroを['R', 'W', 'R', 'R', 'W' , 'W' , 'W']を宣言して、「W」のときの配列の番号をprintfで表示するようなプログラムを記述しなさい。
プログラミング2 関数
関数の定義.
第10回関数 Ⅱ (ローカル変数とスコープ).
情報処理Ⅱ 2008年1月21日(月).
プログラミング 4 記憶の割り付け.
アルゴリズムとプログラミング (Algorithms and Programming)
情報処理Ⅱ 2007年12月3日(月) その2.
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
プログラミング入門2 第11回 情報工学科 篠埜 功.
第7回 条件による繰り返し.
第9回関数Ⅰ (簡単な関数の定義と利用) 戻り値.
岩村雅一 知能情報工学演習I 第10回(後半第4回) 岩村雅一
復習 前回の関数のまとめ(1) 関数はmain()関数または他の関数から呼び出されて実行される.
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
情報処理Ⅱ 第14回 2006年1月23日(月).
情報処理Ⅱ 第2回:2003年10月14日(火).
岩村雅一 知能情報工学演習I 第12回(C言語第6回) 岩村雅一
情報処理Ⅱ 2007年1月19日(金).
C言語 はじめに 2016年 吉田研究室.
岩村雅一 知能情報工学演習I 第9回(後半第3回) 岩村雅一
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
情報処理Ⅱ 第2回 2005年10月14日(金).
情報処理Ⅱ 2005年1月25日(火) レポート課題2の解説.
第5回 プログラミングⅡ 第5回
情報処理Ⅱ 2006年11月24日(金).
情報処理Ⅱ 第7回 2004年11月16日(火).
情報処理Ⅱ 2005年10月28日(金).
コンパイラ 2012年10月11日
プログラミング 4 文字列.
岩村雅一 知能情報工学演習I 第12回(後半第6回) 岩村雅一
プログラミング入門2 第6回 関数 情報工学科 篠埜 功.
全体の流れ 画像ファイルを開き,画像データをメモリ上にロード メモリ上にロードした画像データに処理を加える
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
第12章 乱数という業の深い存在 ~ランダムな値・他~
情報処理Ⅱ 2007年2月2日(金).
プログラミング演習I 2003年6月11日(第9回) 木村巌.
情報処理Ⅱ 第2回 2004年10月12日(火).
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
プログラミング言語論 第九回 理工学部 情報システム工学科 新田直也.
オブジェクト指向言語論 第七回 知能情報学部 新田直也.
情報処理Ⅱ 2005年11月25日(金).
プログラミング言語Ⅰ(実習を含む。), 計算機言語Ⅰ・計算機言語演習Ⅰ, 情報処理言語Ⅰ(実習を含む。)
15.1 文字列処理の基本 15.2 文字列処理用ライブラリ関数
情報処理Ⅱ 第9回:2003年12月16日(火).
第4回 配列.
情報処理Ⅱ 小テスト 2005年2月1日(火).
printf・scanf・変数・四則演算
復習 いろいろな変数型(2) char 1バイト → 英数字1文字を入れるのにぴったり アスキーコード → 付録 int
情報処理Ⅱ 第3回 2004年10月19日(火).
第5回 配列.
プログラミング演習I 補講用課題
岩村雅一 知能情報工学演習I 第7回(後半第1回) 岩村雅一
岩村雅一 知能情報工学演習I 第9回(C言語第3回) 岩村雅一
Presentation transcript:

情報処理Ⅱ 2006年1月13日(金)

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

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

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

前処理指令 (Preprocessing directive) 「プリプロセッサ 指令」ともいう マクロ定義(#define) オブジェクト形式マクロ ⇒「定数」の定義 関数形式マクロ ⇒「関数もどき」の定義 ソースファイルの取り込み(#include) 条件付きコンパイル(#if ... #endif など)

オブジェクト形式マクロ(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行で書かなければならない.ただし, 行末に「\」を置くことで,複数行で書ける. 関数形式マクロの場合,括弧の途中で改行できる. 前処理指令の中でコメント(/* */ もしくは //)を書くと,前処理時に空白文字に置き換えられる.

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

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

他のファイルの取り込み #include <ファイル名> #include "ファイル名" ライブラリ関数などが宣言されているファイルを取り込む(インクルードする). #include "ファイル名" 自作のファイルを取り込む.

ヘッダファイル 定数,構造体や特殊な型,関数プロトタイプや関数形式マクロなどが宣言・定義されているファイル. 慣例として #include <stdlib.h> とすると,/usr/include/stdlib.h を取り込む(ヘッダファイルの所在は処理系依存). ヘッダファイルの中で,他のヘッダファイルをインクルードすることもよく行われる. 慣例として ファイル名を「.h」で終わらせる. 関数は,「宣言」のみして「定義」はしない. 同一ファイルに対する複数回のインクルードがあっても,2回目以降は処理しないようにする.

ヘッダファイルとライブラリ関数 既に定義されている関数や定数を利用するには,あらかじめ,適切なヘッダファイルをインクルードしなければならない. printf なら #include <stdio.h> NULL なら #include <stdlib.h> が一般的. インクルードすべきヘッダファイル名は,manpage で知ることができる. man 3 printf jman 3 printf JM Project (http://www.linux.or.jp/JM/)

サイコロ問題 仕様 ① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ 目の数は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; とすればいい! 擬似乱数のため,何度実行しても同じ目が出る.これを変えるには,適切な値の種を与えればよい.

サイコロ問題の考え方(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(1000*5)」のように使うことも可能

有用なライブラリ関数(1) #include <stdio.h> を必要とするもの int putchar(int c); … 1文字出力 #include <stdlib.h> を必要とするもの int atoi(char *s); … 文字列から整数値への変換 void exit(int status); … プログラムの終了 int rand(void); … 乱数生成 #include <string.h>を必要とするもの size_t strlen(char *s); … 文字列の長さ int strcmp(char *s1, char *s2); … 文字列比較 char *strstr(char *s1, char *s2); … 文字列検索

有用なライブラリ関数(2) #include <ctype.h> を必要とするもの int isdigit(int c); … 文字が数字であるか判定 int tolower(int c); … 大文字を小文字に変換 int toupper(int c); … 小文字を大文字に変換 #include <math.h> を必要とするもの double exp(double x); … eのx乗 double floor(double x); … x以下で最大の整数

まとめ 前処理指令をうまく使えば,読みやすく保守しやすいプログラムを書くことができる. 前処理は,コンパイルの前に行われる.そのため,前処理指令の書式はCの文法と異なる. ライブラリ関数を使うには,#includeを用いて適切なヘッダファイルをインクルードするとともに,その使い方(引数,出力も)をよく理解しておく.

スケジュール 第13回:1月20日(金) 13:10~14:40 第14回:1月23日(月) 14:50~16:20 A104 第13回:1月20日(金) 13:10~14:40 ファイル入出力,標準入出力,mallocなど 第14回:1月23日(月) 14:50~16:20 A104 おさらい問題を実施 再履修で他の授業と重なっている人は,そちらを優先し, 授業後に来てください. (1月27日(金)は出張のため休講) 試験:2月3日(金) 13:10~14:40 Cの書籍1冊および自筆ノート1冊の持込可