180 likes | 301 Views
情報処理 Ⅱ. 2006年11月24日(金). 本日学ぶこと. ポインタを使ったプログラミング 反復語判定の拡張版 対象語は,コマンドライン引数から獲得 文字列走査 ビットパターン出力 int 型, float 型の値に対して出力 ポインタ値の型変換 コマンドラインオプション. これまでの,補足(1). for 文を「 for ループ」, while 文を「 while ループ」と呼ぶことがある. ループ = loop = 糸・ひもなどの輪 for 文で計数に使用する変数を「ループカウンタ」という.. これまでの,補足(2).
E N D
情報処理Ⅱ 2006年11月24日(金)
本日学ぶこと • ポインタを使ったプログラミング • 反復語判定の拡張版 • 対象語は,コマンドライン引数から獲得 • 文字列走査 • ビットパターン出力 • int型,float型の値に対して出力 • ポインタ値の型変換 • コマンドラインオプション
これまでの,補足(1) • for文を「forループ」,while文を「whileループ」と呼ぶことがある. • ループ = loop = 糸・ひもなどの輪 • for文で計数に使用する変数を「ループカウンタ」という.
これまでの,補足(2) • char *p = "abc"; としたとき,「文字列p」と書くことがある. • 文字列が等しいかを比較するときに,演算子 == は使用できない. • char *p = "abc"; char *q = "abc";のとき,p == qは偽(異なるオブジェクトを指し示している)と考える • char p[] = "abc"; char *q = "abc";のとき,p == qは偽(異なるオブジェクトを指し示している) • char p[] = "abc"; char *q = p;のとき,p == qは真(同じオブジェクトを指し示している) • 文字列比較は,ライブラリ関数の strcmpを使用する
反復語判定にコマンドライン引数を • 仕様 • 入力は,コマンドライン引数から獲得する. • コマンドライン引数の各文字列について,反復語(2回以上の繰り返し)になっていれば「Yes」を,そうでなければ「No」を出力する. • 例 • ./iterative2 muumuu MuuMuuMuu MuuM • "muumuu" : Yes • "MuuMuuMuu" : Yes • "MuuM" : No
プログラミングの 前に,ちょっと 検討する習慣を! 反復語判定:アイディア • 反復語は,先頭何文字か(「部分文字列」とここでは言う)の繰り返しである • ①部分文字列の候補を見つけ,②繰り返しになっているかを確認すればよい. • 例1: m u u m u u m u u m u u • 例2: a a b b a a b b • 部分文字列の性質 • その直後の文字が,先頭の文字と一致する. • 反復語の長さは,部分文字列の長さで割り切れる. • ある語に対して,部分文字列(の候補)は複数あり得る.
反復語判定(部分文字列の候補発見) 1文字ずつ見ていく処理を 文字列の「走査(scan)」という • 先頭から1文字ずつ見て,部分文字列の候補を求める. • 部分文字列は p から q - 1 までの文字配列 p q ヌル文字がないので,実は文字列ではない argv[i] 'm' 'u' 'u' 'm' 'u' 'u' '\0'
反復語判定(繰り返しの確認) • 対応する文字を1文字ずつ見て比較する. • r が q まで来たら,文字列の先頭に戻る. • 繰り返しになっていないか,sが文字列の末尾まで来たら終了. p q argv[i] 'm' 'u' 'u' 'm' 'u' 'u' '\0' r s
反復語判定:ポインタ変数の役割 • char *p = argv[i]; • 対象文字列 • char *q; • 部分文字列(の候補)の次の位置を指す. • p から始まり,文字列走査により1ずつ増える. • char *r; • 繰り返し確認用 • p から始まり,反復語であれば,部分文字列を(反復回数-1)回,巡回する • char *s; • 繰り返し確認用 • q から始まり,1ずつ増える.
ビットパターン出力1 • 仕様 • int型の値を,バイト単位で最上位ビットから最下位ビットの順に,2進数で出力する.バイト間には空白文字を置く. • 入力は,プログラム内で指定する. • 例 • 40 ⇒ 00101000 00000000 00000000 00000000 • 応用すれば,任意のアドレスの値を獲得したり,書き換えたりできる.(Cが適度に低水準な理由の一つ!) 40の2進表記 ???
ビットパターン出力1:アイディア • int x = 40; char *p = (char *)&x;とすると,*p, *(p + 1), ..., *(p + sizeof(x) - 1)は,xの「バイトごとの」中身である. • 1バイトのビットパターンを求めるプログラムを活用して,バイトごとに出力すればいい! int x : p p+1 p+2 p+3 char *p : は1バイト はオブジェクト,
p1+1 int *p1 : p3+1 char *p3 : は1バイト ポインタ型のキャストが必要な理由 • int x = 40;としたとき, • int *p1 = &x;としてもうまくいかない. • char *p2 = &x;は,型が合わない. • char *p3 = (char *)&x;とすればうまくいく. int x :
ビットパターン出力2 • 仕様 • int型のほか,float型の値を,バイト単位で最上位ビットから最下位ビットの順に,2進数で出力できるようにする. • 入力は,コマンドラインから指定する.最初の1個の数値のみでよい.数値が指定されなければ,1とする. • 数値の前にオプション(コマンドラインオプション)を指定可能 • -f : float型の値を出力する(float) • -r : バイト単位で逆順に出力する(reverse) • -p : バイトごとにそのアドレスも出力する(pointer) • 「-frp」のように一括指定も可能
ビットパターン出力2(続き) • 実行例 • ./intfloatbit⇒ 00000001 00000000 00000000 00000000 • ./intfloatbit -f 1⇒ 00000000 00000000 10000000 00111111 • ./intfloatbit -f -r 1⇒ 00111111 10000000 00000000 00000000 • ./intfloatbit -pr 1⇒ 0x22eec7:000000000x22eec6:000000000x22eec5:000000000x22eec4:00000001 コマンド名(必ず1つ) コマンドラインオプション(任意個) コマンドパラメータ(任意個) すべて合わせて「実行コマンド」
ビットパターン出力2:構成要素 • コマンドラインオプションの獲得(コマンドライン解析)方法 • intでもfloatでも出力できる方法 • 逆順の出力方法
バイトオーダ • 実行例 • ./intfloatbit 1⇒ 00000001 00000000 00000000 00000000 • ./intfloatbit -r 1⇒ 00000000 00000000 00000000 00000001 • 値が「バイト単位で」メモリにどのように格納されるか(バイトオーダ)は,処理系により異なる. • 最下位バイトから最上位バイトの順に格納していくのを,リトルエンディアンという.演習室のLinux環境も該当する. • 逆に,最上位バイトから最下位バイトの順に格納するのは,ビッグエンディアンという.ネットワークバイトオーダともいう.
この表現形式も,処理系に依存する(Cの規格この表現形式も,処理系に依存する(Cの規格 ではない)が,多くの処理系で採用されている float型のビットパターンの意味 • ./intfloatbit -fr 1⇒ 00111111 10000000 00000000 00000000 • ./intfloatbit -fr 2⇒ 01000000 00000000 00000000 00000000 • ./intfloatbit -fr 3⇒ 01000000 01000000 00000000 00000000 • ./intfloatbit -fr -3⇒ 11000000 01000000 00000000 00000000 符号(1bit) 0なら正 1なら負 仮数部(23bit) 2進数,小数点以下 1を加えれば,実際の仮数になる 指数部(8bit) 底は2,整数値127を引けば 実際の指数になる.
まとめ • int main(int argc, char *argv[])で,コマンドライン引数(文字列の配列)を獲得できる. • argv[0]はコマンド名,argv[argc]はNULL • 残りの文字列をどう扱うかは,プログラム内で決める • 文字列の走査,バイト単位での処理には,char *型のポインタを活用するとよい. • ポインタ値のキャスト(型変換)により,アドレスを変えることなく,任意のポインタ型に変換できる.