main - みる会図書館


検索対象: 月刊 C MAGAZINE 1992年12月号
40件見つかりました。

1. 月刊 C MAGAZINE 1992年12月号

のマクロカ OECLARE DYNAMIC と IMPL EMENT DYNAMIC て、す。 List 21 に示すように , DECLARE DYN AMIC をクラスの定義の中に , IMPLEME NT DYNAMIC を定義の外に置きます ( 9 , 14 行目 ) 。 IMPLEMENT のほうは「定義」に なるのて、 , プログラム全体て、 1 か所しか存在 て、きません。 こうして , CMyException クラスが定義て、 きました 0List 21 の関数 f00 の中だけを見て ください。 THROW の引数として , new に よって生成した CMyException のインスタン スを渡しています ( 19 行目 ) 。このメモリ領 域はライプラリによって解放されるのて、 , ューザが delete してはいけません。 f00 の CATCH によって , 例外メッセージ を受け取ることがて、きます。 printf によって , f00 ' s CATCH . 1414 と表示されるて、しよう。 この例て、は , List 4 : 8 : 9 : 11 : 12 : 13 : ) ; 15 : 17 : { 20 : 21 : 22 : 23 : 24 : 25 : 26 : ) 27 : 28 : 29 : { 30 : 31 : 32 : 33 : 34 : 35 : 36 : 38 : } 14 : IMPLEMENT_DYNAMIC(CMyException, CException) / / 実行時クラス名判別のため CMyException(int d) (detail = d; } int detail; 10 : public: DECLARE_DYNAMIC(CMyException) / / 実行時クラス名判別のため class CMyException : public CException { 7 : 〃判別できる情報を付け加えるようにする。 6 : / / DECLARE/IMPLEMENT DYNAMIC の組により , 実行時にクラス名を 5 : / / CException の継承は , このようにする 3 : #include く afx. h> 2 : #define DOS 1 : / / コンパイル : cl / test2. cpp mafxcr. lib ユーサ定義の例外処理 16 : void foo() TRY { THROW(new CMyException(1414)) : return 0 ; END_CATCH printf("main' s CATCH:Xd*n", e->detail) : CATCH(CMyException, e) { foo(); TRY { int END CATCH THROW-LAST(); printf("foo' s CATCH:Xd%n ” , e->detail) : CATCH(CMyException, e) ( 〃 CMyException を THROW する / / CMyException を受け取る / / 例外ハンドラ / / T 駅 OW の可能性あり / / ( 33 行目 ) へ処理を継続 〃上のレベルの例外ハンドラ ところて、 , 関数 f00 は関数 main によって呼 ばれています。そして , main て、も , 例外処 理を記述しています。 f 。。て、起こった例外を main て、も検出して , しかるべきハンドラを 起動しなければなりません。そのために必要 なのが f00 の CATCH の最後の行 ( 23 行目 ) に ある THROW LAST ( ) ; て、す。こうすれ ば , Fig. 18 に示すような流れによって , m ain の CATCH に処理が移ります。結局 , 先 と表示されることになります。つまり , TH ROW LAST によって , ネストした例外処 理を継続することがて、きるわけて、す。 トの挙動を変更することもて、きます。 ログラムを終了させますが , このデフォル abort が呼び出され , メッセージとともにプ 最終的に処分されます。このハンドラて、は , が提供するデフォルトのハンドラによって 受け取られなかった例外は , ライプラリ ほどの表示に続いて , main' s CATCH : 1414 TabIe 6 例外クラス 例外クラス名 CMemoryException CFileException CArchiveException CNotSupportedException CResourceException new のとき , メモリ不足だと生じる例外 ファイル入出力のときに生じる例外 たとえば , ファイルが見つからない , ティスクがいっぱいになったなど アーカイプ作成・展開のときに生じる例外 たとえば , 不正フォーマット , 型の不一致など 非サポート例外 たとえば , 派生クラスで , 基本クラスの機能を制限する場合 リソースの確保に失敗したときに生じる例外 たとえば , ペンやプラシが見つからないとか , メモリ不足て生成できないなど 以上が , MS ー C7 の例外処理機能の概要て、 す。前にも書きましたが , MFC ライプラリ て、は , 例外が生じると , 適当な例外クラス を throw するようになっていますのて、 , 例外 処理の機能を用いれば , ライプラリの外部 て、例外についての処理を記述することがて、 きて , とても便利て、す。 従来て、は , 工ラーハンドラ関数を定義し , その関数へのポインタをライプラリに渡し , 例外やエラーが生じたときに呼び出しても らう , というアプローチて、記述されること が多かったと思います。しかし , この方法 て、は , 多様なエラー処理のために , switch/ case て、分岐しなければならなかったり , ハ ンドラと例外の生じる範囲との対応が , 直 感的につけにくかったりする間題がありま した。 MS ー C7 の例外処理て、は , これらの問 題が解決されていることが , おわかりいた 例外処理のまとめ だけたて、しようか。 62 C MAGAZINE 1992 12

2. 月刊 C MAGAZINE 1992年12月号

状態を整理 さらに状態を整理すると・・・ LiSt List 1 : #include く stdio. h> 3 : void main(void); 4 : 5 : void main(void) int c, quoted = 0 ; 7 : 8 : while ()c = getchar()) ! = EOF) ( 9 : i f (quoted) ( 10 : 11 : putchar(' *n' ) ; 12 : quoted = 0 : 13 : 14 : else { putchar(c) ; 17 : 18 : 19 : 20 : 21 : 22 : 23 : } 1 : #include く stdio. h> 2 : 3 : void main(void); 4 : 5 : void main(void) int c, quoted = 0 ; 7 : 8 : while ()c = getchar()) ! = EOF) { 9 : if (c ー if (quoted) putchar(' *n' ) ; 11 : quoted = !quoted; else if (quoted) { 14 : putchar (c) : 18 : } else { ' \ ” ' ) quoted = 1 ; 処理」を考えているときは「引用部分の処理」 「たいして変わっていないじゃないか」とお けっこうなことてす。けれど , List 3 の if 文 はちょっとわきに置いておけるのてす。そ はせつかく考えたそのふたつの状態を分け 思いになりますか。けれど , List 5 の初めの れが問題を分けて考えることの利点てす。 if 文をご覧ください。この if 文の役目ははっ る役目をしていません。 きりしています。それは「地の文を読んてい 状態を分け , 間題を分け , そして if 文を使 ほら , 思い出してください。 if 文というの る状態」と「引用部分を読んて、いる状態」を分 ってプログラムを分ける。よろしいてすか。 は大きな問題を分けるためにあるのてした けていることてす。てすから , 初めの if 以降 それては練習問題へまいりましよう。 よね。大きな問題というセンべイをパリン は「地の文の処理」てあり else 以降は「引用部 とふたつに分ける , これが if 文の役割りてし 練習問題 分の処理」と一言て、いうことがてきます。 た。センべイをふたつに分けるように , 大 言て、説明てきるというのは整理されている きな問題を小さい問題に分けてやるのが if 文 さて今月も「プログラミングの工ッセンス」 の役目なのてす。「地の文」と「引用部分」と 証拠てす。 の練習問題をお届けいたします。どうぞ思 List 5 の if 文は一言て説明てきますが , L いうふたつの状態にせつかく気がついたの い切って挑戦してください てすから , if 文もそれを反映させたいものて ist 4 の if 文はそうはいきませんてした。 Lis 【応用】 List 1 で表現した目覚まし時計を拡 t 4 て、は , 初めの i 似降は「引用符 (" ) が入力 す。つまり , パリンと割ったセンべイの片 張して , 目覚まし時計シミュレータを作っ されたときの処理」てあり , else 以降は「引用 方が「地の文」の処理にあたり , もう片方が 符は入力されておらず , 引用部分を読んて、 てみましよう。キーポードからの入力でア 「引用部分」の処理にあたるように if 文を書く ラームオン / オフや時刻設定を行い , 時間が いるときの処理」てした。ほら , 説明がどう のてす。そのときの if の条件が , 変数 quote きたらアラームが鳴るようにするのです。 しても入り組むてしよう。 こが私の不安 d の値というわけてす。 【応用】 List 1 で表現した目覚まし時計で の原因て、した。 , こはたいせつな点なのて、 , もう一度。 は , アラームが鳴っている最中に時刻変更 入り組んだ説明しかてきないと「どこかに ふと思いついたから , なんだかよくわから したら何が起こるでしよう。実際の目覚ま 考え落としがあるんじゃないか」と思ってし ないけれど if 文を使ってみよう , というやり し時計ではどうですか。 List 1 をどのように まうのて、す 0List 5 のように「地の文の処理」 方はよくありません。そうてはなく「私はい 直したら実際の目覚まし時計と同じ動作を 「引用部分の処理」といい切ることがてきれ ま問題を分けて考えているのだ」と意識して するようになるでしようか。 ば気分はスッキリするのてす。 みてください 【疑間】 List 1 と Fig. 1 は同じ目覚まし時計 状態を分けるということは問題を分ける if 文は , 大きな問題を小さな問題に分けて を表現しているでしようか。 ことてす。ある状態についてのことを考え いるのて、す。そのことをはっきりと意識し 【改良】 List 5 の引用部分を抜き出ログ ているとき , ほかの状態のことはとりあえ ていただきたいと思います。 ラムを改良して , C 言語の文字列を扱うよう List 4 の不安を解決するのが List 5 てす。 ず忘れて考えることがてきます。「地の文の 118 C MAGAZINE 1 2 12

3. 月刊 C MAGAZINE 1992年12月号

C クラミング by ste 第 9 回 ビット and 訓 that 「ビット」を知らずして C 言語を習ったとはいえま せん。今回は , C 言語を通じてコンピュータを「ビ ット」のレベルからながめ直すとともに , 「ビット」 を通じて C 言語の細部をなかめ直しましよう。 16 ビットて、表されます (UNIX なら 32 ビッ Fig. 1 List 1 の実行結果 A>list10 1 2 4 8 32 1 2 8 256 512 1024 2048 4096 8192 16384 ー 32768 ( ※下線部は入力 ) ッ int X ・ と宣言すれば , メモリ上に 16 ビットの領域 コンヒ。ュータのメモリ ( 記憶装置 ) は , 「ビ が確保され , それに x という名前がつきま ット」という小さな小さなスイッチが何百万 す。「オン」のビットを 1 , 「オフ」のビットを 個も並んだものてす。これらのスイッチの オン・オフてコンピュータは考えたり記憶 0 て、表すと , 16 ビットの数は 0000000000000000 ・・・・・ゼロ したりします。 MS-DOS 上の多くの C 言語の int 型 ( 整数 0000000000000001 ・・・ を表す標準の型 ) は , コンピュータ内部て、は 0000000000000010 ・・・ int 型のビットを 0000000000000100 ・・・ ひとつずつ左にシフト 1 : #include く stdi0. h> 2 : main() int x = 1 : 4 : 5 : while (x トの { 6 : printf("%d*n", x) : 7 : x くく = 1 ; 8 : 9 : return 0 : 10 : 11 : } 0000000000001000 ・・・・・・はち LiSt 数は 0100000000000000 一万六千三百八十四 のように , ひとっ左にずれるごとに倍にな 三万二千七百六十七 ります。てすから , て、す。 こういう数の表し方を C 言語にはビットを左にシフトする (shift= 「倍なり (binary) 」というのてす ( ウソにご注 ずらす ) 演算子 < くがあります。 意ください ) 。 無符号の unsigned int 型なら x くく n ; Y とすると , x の各ビットを左に n ビットだけ 1000000000000000 シフトしたものを y に代入します。 三万二千七百六十八 となるのてすが , int 型は x くく n ; X の略記法として 1000000000000000 ・・・マイナス三万二千七百六十八 x くく = n ; という書き方もあります。 のように , 左端のビットだけ負の値になり これを使って , int 型のビットをひとつず ます。これが int 型の最小の数て、す。最大の 0111111111111111 65535 と OxFFFF と一 1 List 1 : #include く stdio. h> 2 : main() if ( 65535 > ー 1 ) 4 : printf( ” 65535 〉ー 1 \ n ” ) : 5 : if (0xFFFF > ー 1 ) 6 : printf( ” 0xFFFF > ー 1 \ n ” ) : 8 : return 0 : 98 C MAGAZINE 1 2 12

4. 月刊 C MAGAZINE 1992年12月号

68k 冫用講坐 GCC で学ぶ X68 ゲーム プロクラミング X68000 版 G 十十でスプライトを扱いましよう 吉野智興 先月までの付録ティスクに X68000 版 G 十十が 収録されました。そこで , 今回から 2 ~ 3 回にわ たって G 十十でスプライトを扱ってみます。 第 13 回 ひとつのスプライトを 画面左から右へ動かす には明らかになるて、しよう ( 今回だけて、もひ 目標 よっとしてフ ) オプジェクト指向で 実は , 私自身は C 十十という言語には、、相 オプジェクトを動かす ? ? 当に素人〃て、す。「 C 十十を知らないて、 G 十十 を移植て、きるの ? 」と思われるて、しようが , G 十十て、スプライトを動かすのは , スプラ イトが別名オプジェクトと呼ばれることが G 十十は C 言語て、記述されているのて、 , 移植 あるのと , 連載がゲームを扱うという点て、 自体は C 言語の知識て、可能なのて、す。て、す 題材としておもしろいなと思ったのて、扱う が , せつかく付録ディスクに収録されたの ことにしました。ただ , 実際にゲームがて、 て、すから ( ' 92 年 8 ・ 9 月号 ) , ここは奮起一発 16 クラスの sp 君は自分て、自分の役目をはた きるほどの処理速度が出せるかは未知数て、 お勉強モードてトライしてみます。 す。 G 十十は , C 十十言語機能を使うとやや して自分て、消えてなくなります。 List 1 のよ 初めに用語についてちょっと説明してお コード生成て、もたっく部分がありますから , うに , オプジェクト指向のプログラム言語 きます。この連載て、は , G 十十 ( GNU による 速度的には不利て、す。 て、は , 変数は自分が何物かを知っていて自 C 十十処理系 ) と C 十十処理系を厳密に区別 しません。ただし , 私の知識の範囲て℃十十 再度 List 1 をご覧ください。ここて、使われ 分が何をするためにあるかも知っているか と G 十十の仕様が異なる部分は厳密に書くよ のようにふるまわせることが可能て、す。 ているというのはクラスの 名前て、す。オプジェクトという抽象概念が うに努力します。 スプライトクラスを C 十十てどのように位置づけられるかは , 私 目標としては List 1 のように , ひとつのス 作ってみましよう が明確化てきるほど C 十十に詳しくないのて、 プライトが画面の左から現れて右から消え C 十十言語の教科書て、は , 「クラスはひと 説明て、きないのて、すが , 少なくとも List 1 に るプログラムを作ります。 つの小さな完成された部品として設計・デ 現れる、、 Sprite16x16" という名前のクラス List 1 は別にふざけているわけて、はあり バッグし , それを階層化していけば大きな は , 自分がスプライトてあることを知って ません。 G 十十つまり C 十十を使えば , 関数 アプリケーションを設計できる」と強調して いて自分の役目が画面を左から右へ動かす main ( ) 自体は何もしない関数て、もスプライ います。上手に設計されたクラスは汎用性 ことだと知っています。というか , 知って トを画面の右から左へ動かすくらいのこと も高く , C 十十の継承を用いることて高度な はて、きます。当然 , これにはウラがあるの いるようにプログラムします。て、すから , アプリケーションが制作可能て、しよう。て、 てすがそれはこの一連の連載が終わるころ 関数 main( ) て、は何もしなくても Sprite16x List 00 1 よ ・ 1 00 1 ↓ 0 っ 0 4 【 0 6 7 8 9 150 C MAGAZINE 1992 12

5. 月刊 C MAGAZINE 1992年12月号

リ The 0 + C ならこうかな こりや駄目だ・・ List LiSt 1 : #include く stdi0. h> 2 : enum A—type { CLASS—A, CLASS—AA } type ; 5 : A() { type = CLASS-A; } void he110 ( ) 8 : 9 : printf( ” A: : he110 ( ) \ n ” ) ; 10 : 11 : friend void cal l—hel 10 ( A * ) ; 12 : 14 : 15 : class AA : public A { 16 : public: AA() : A() { type = CLASS-AA; } 17 : void he110 ( ) 19 : printf( ” AA: : he110 ( ) \ n ” ) : 20 : 21 : 23 : 24 : void cal 1 ー he110 ( A * ap) switch (ap->type) { 26 : case A: :CLASS A: ap- 〉 hello て ) : break; 28 : 29 : case A: :CLASS_AA: ((AA*)ap)- 〉 hello() ; break; 30 : 32 : } 33 : 34 : void main() 36 : A* ap = &a; call—hello(ap) ; 38 : 39 : AA aa; 40 : ap = &aa; call—hello(ap); 41 : 42 : ) 仮想関数のオーバライド 1 : class Base { virtual void a(); 2 : 5 : class Derived : public Base { / / 戻り値の型のみ異なるのでエラー char a(); 6 : / / void a() とは別関数 void a(int) ; 1 : #include く stdio. h> 3 : class A { 4 : public: void he110 ( ) : 5 : 7 : 8 : void A::he110() printf( ” A: : he110 ( ) \ n ” ) : 10 : 12 : 13 : class AA : public A { 14 : public: void he110 ( ) ; 16 : } ; 17 : 18 : void AA::heIlo() 19 : { printf( ” AA: : he110 ( ) \ n ” ) ; 20 : 22 : 23 : void main() 24 : { 25 : 26 : A* ap = : ap->hello() ; 28 : AA aa ; 29 : ap = &aa; ap- 〉 he110() ; 30 : 仮想関数の宣言 1 : class A { virtual void func(); LiSt List 〃仮想関数 後述するように通常と異なる呼び出し方に えば , 正しい関数を呼び出すための煩雑な 仮想関数とは , 基本クラスが先々を見越 なり , 基本クラスへのポインタへ姿を変え 手続きは , すべてコンパイラがめんどうを たあとも , 正しいメンバ関数の呼び出しが この関数は派生クラスでオーバライド 見てくれることになります。 case 文のオン パレードはもういらない されるかもしれないから , いかなる場 保証されます。 基本クラスて仮想関数てある , と宣言さ 合でも正しく派生クラスの関数が呼び このためのキーワードが , 出されるように れたメンバ関数は , 子孫末裔に至るまて仮 virtual てす (List 4)ö宣言の頭にⅵ「 tu 引がついたメ 想関数として認識されます。派生クラスて とコンパイラによろしくお願いするちょっ オーバライドしても , いちいち「 virtual 」を ンバ関数を仮想関数と呼び , 通常のメンバ と特殊な関数てす。つまり , 前述したよう つける必要はありません。もちろんつけて 関数と区別します。クラス宣言の外部て関 に派生クラスのインスタンスへのポインタ も構いません。たとえば , BorIand のクラス 数を定義する場合は , virtual キーワードは が基本クラスへのポインタに姿を変えてし ライプラリては , 派生クラスても怠りなく まったあとても , 正しく派生クラスの関数 つけません。 ⅵ rtual をつけて , 仮想関数てあることをあ を呼び出すためのものてす。仮想関数を使 仮想関数として宣言されたメンバ関数は , C 十十入門講座 123

6. 月刊 C MAGAZINE 1992年12月号

List 14 名称て、 , プログラムサイズを縮小するテク ノロジを指します。 仮想実行コードなんかを使ってしまった ら , X86CPU て、は動作て、きなくなってしま うのてはないかと思われるてしよう。事実 , p ー code だけて、はプログラムは動作しませ ん。実際の動作には p ー code インタブリタが 必要になります。こんどは p-code インタブ リタはどのようにやって手に入れればよい のかが気になると思いますが , その心配も ありません。 p-code インタブリタは , p-co de を使っているプログラムにくつついてい るからて、す。つまり , p ー code 生成オプショ ン ( ー Oq ) を指定してコンパイル / リンクする と , リンカが Makep-code ユーティリティ (MPC. EXE) を呼び出します。 MPC. EXE は , プログラムに p-code イン タブリタを組み込んて、くれるのて、す。した がって , ューザは p ー code か否かを意識する 必要もありませんし , 作成されたプログラ ムは , ふだん見ているプログラムと外観上 は何の変化もないわけて、す。 実際に p ー code が使われているマイクロソ フト社の製品もありますが , 皆さんはそれ が何かわかりますか ? それだけ見分けが つかないのて、す。ちなみに EXCEL や WOR KS に p ー code が使われているようて、す。 これだけの説明て、はよいことずくめの p ー code になりそうなのて、 , 少し注意も書いて おきます。 p-code は , 数個のアセンプラ命 令をひとつにまとめた命令て、す。たとえば , List 15 のようなプログラムを MS ー C7 は Lis t 16 のようなアセンプラブログラムとして生 成します。これが p ー code になると List 17 て、 す。 ADD AX, BX のコードが AddW などと なってしまうのて、 , プログラマは名前つけ 規約を知っておかないとデバッグが厄介に なります。 p ー code の名前つけ規約は公開さ れており , マニュアルにも掲載されている のて、 , それらを見て理解するしかないて、し よう。なお先の例にあげた AddW は , Wor d 型の加算 ( ADD ) を行います。 52 C M AGAZIN E 1992 12 0. 4 1 」「 0 4 「し 4 4 A . っ 0 つ 9 0 8 A , 1 00 0 1 《 A 1 人 1 よ 1 人 00 ・ 1 ・ 1 0. 0. 背 . CD ^ 0 、 0 0 0 = 13 3 和晒Ⅷ 4 Ⅷ 5 切 6 1 人 1 ー - 5 れ四 88882 冊冊鼬 = 冊 a 記 aa 記 5 扣冊 . 調冊 8 鵝朏 8g882 冊 ・ー 4 ・ 1 ・ 1 1 よ ・ 1 ・ 1 N 1 人、ー - ・ 1 1 人・ 1 ・ 1 ・ 1 1 0 ャし . し 0 ・ 1 すしー 1 0 0 , し 0 , し 0 0 0 00 -4 - -0 CD 1 ー 8 9 0 、 10 な 00 4 :. 0 6 叮ー 8 9 01 ・りムっ 0 4 一、 0 叮ー 8 01 り 0 00 4 : レれ 0 叮ー 8 9 01 ・ワ 0 っ 0 -4 ・ 8 0 、 1 戸 0 【 0 -. 0 ′ 0 ロ》一 0 - ト CO 6 6 6 6 6 6 6 6 6 ロー叮ー叮ーローワ・ワー 0 ーー叮ーー 8 8 8 8 8 8 8 8 8 8 9 9 9 0 》 9 9 9 9 9 0 0 、よ 1 よ List サンプルソース List 1 : void main(void) : 2 : 3 : void main (void) register int i = 0 , J 5 : 6 : 7 : 8 : = 10 , k = 20 : List 1 5 のアセンプルリスト 0 加 0 -18 0 00 , 1 00 3 -4 -0 6 7 8 9 0

7. 月刊 C MAGAZINE 1992年12月号

he EVO 瞰 i ① Of a C 十十 Pro rammer とつのことを除いて , ODE の系て、行なった まりこの場合は , 一連の微分方程式をある を出力するかて、す。 のとまったく同じ手続きを実行します。っ 区間にわたって積分するのて、はなく , これ クラスをこのように定義すると , 実際の 処理のほとんどすべてが , オプジェクトの クラスの使い方 内部て行なわれます。 main ( ) ルーチンは単 1 : #include く stream. h> に , オプジェクトを生成して , それの行動 2 : #include く math. h 〉 3 : #include ” OdeI. hpp ” を指示するだけて、す。このリストの例て、は , 4 : 5 : / * 方程式のパラメータをセットする * / オプジェクトのやることは単純て、す。一般 6 : float s = 16.0 : 7 : float 「 = 45.92 ; こういう形のオプジェクト指向のコ 8 : float b = 4.0 ; 9 : ードは , まるて、、尻尾が大を振ってクいるよ 10 : / * 導関数をここに書く * / 11 : うな感じがして , 手続き型のプログラマが 12 : void main(int argc, char** argv) それに慣れるためには , かなりの時間を要 13 : { int n; 14 : します。 float dt, x[3]; 15 : 16 : if ( argc 〉 1 ) 17 : 最後にホリモフィック ・ n = atoi( argv[l] ) ; else なオプジェクト n = 2000 ; 20 : 22 : オプジェクトをしばらく使っていると , 23 : そういうオプジェクトに対する操作の一部 24 : 25 : は , 別のクラスて、も頻繁に使われる , とい 26 : うことに気づきます。事柄のうえて、関連性 28 : 29 : の薄いクラスて、も , て、す。てすから , そう 30 : 31 : いう共通的な操作を別のクラスに入れてお 32 : 33 : いて , 専門化・特化したクラスがそこから 34 : 35 : 継承するようにすれば , ポリモフィックな 36 : (polymorphic, 多態的な ) オプジェクトが実 37 : 38 : 現します〔クラスの場合 , 実際的には , 抽 39 : 40 : 象クラスからの派生のことをく多態化〉と 41 : 42 : 称している〕。 44 : このことを説明するために 一定の微分 45 : 46 : } 方程式にてはなく , 反復方程式に支配され るカオス系を考えてみましよう。そのひとつ の興味深い例は , lkeda アトラクタて、す [ 2 ] 。 x( t + 1 ) g 十 b * ( x( t ) * cos( s ) y( t ) * sin( s ) ) y( t + 1 ) List 6 / * タイムステップのサイズをセットする * / dt = 0.001 ; / * 初期条件をセットする * / xC0] = xC1] = xC2] = / * ルンゲークッタシステムを初期化する * / ODEI lorenz( derivs, 3 , dt ) ; / * 初期条件をセットするり lorenz. initialize( x ) : / * 初期の状態をスピンアップとして捨てる * / lorenz. spinup( 1000 ) ; / * n ステップ実行する * / cout くく lorenz(n) : / / あるいは , 上の行の代わりとして / / for (i : 0 ; i く n; i + + ) / / cout くく + + lorenz ; 0 14 0 反復写像クラス 1 : #ifndef —MAP-I—HPP 2 : #define -MAP-I—HPP 3 : 4 : typedef void (*lterateFunction)(fIoat *inp, float *OutP) ; 5 : 6 : class 期 PI 8 : 9 : 10 : 11 : 12 : 13 : 14 : 15 : 17 : List 7 private: I terateFunct i on I tFun ; int dim, output_rate; float *s; long iter; long steps; publ ic: MAP1(IterateFunction f, int d, int out_rate = 1 ) : ltFun(f)' output—rate(out—rate), dim(d), steps(l), iter( の { s = new float[dim]; ) ( x( t ) * sin( s ) そして a, b, g, m は既知のパラメータて す。この方程式の展開を見るためには , ひ 36 C MAGAZINE 1 2 12

8. 月刊 C MAGAZINE 1992年12月号

日付を読み込み , 表示を行うプログラムて、 れば , もう一度この記事を読み返していた だきたい ある。 まず , 実行例を示そう (Fig. 6 ) 。実行例か 本連載て、は , 読者からの質問にお答えし , らもわかるように , このプログラムは 3 種類 また希望に応じてプログラムの添削も行う。 の入力を受けつける。 こて、は , このプロ 下記必要事項を明記のうえ , フロッヒ。ーデ グラムの中から , 2 点のポイントのみ解説し List 5 を改良し , いったん文字列として読 イスクにて応募していただきたい ( 短い質間 て、あれば , 書面のみて、可 ) 。 み込み , それを数値に変換するプログラム よう。 ・ sscanf なお , 応募いただいたフロッヒ。ーディス を List 6 に示す。 ここて、 sscanf は , scanf の文字列版て、あ クは返却て、きないことや , 個人的な質問に , こて , ANSI て、は atoi が変換に失敗した ときの動作を定義していないことに注意し る。すなわち , scanf が標準入力ストリーム は一切お答えて、きないことをあらかじめご からの入力を行うのに対して , sscanf は文字 ていただきたい 了承されたい buffer に文字列として読み込まれたデータ 列を入力ストリームとみなす。したがって , どんな小さな疑問点て、も結構て、あるのて、 , が , 数値として表現て、きない場合は , num 文字列から書式っきて、 , 数値や文字列など 気後れせずに , 応募していただきたい ( ただ には不定の値が代入される ( 処理系によって を抽出することがて、きるのて、ある。 し , 特殊な題材よりも , 一般性の高い題材 ・ strncmp は 0 を返すと規定しているようだが , そのこ を優先的に取り上げることを , あらかじめ とに依存するプログラムは可搬性がなくな こて、は , 月の名前の照合のために ご了承願いたい ) 。 ってしまう ) 。 strncmp (month[i], mbuf, 3 ) ( 1 ) 氏名・住所・電話番号 ②匿名希望の有無 / ペンネーム したがって , このプログラムは , 無限ル と判定を行っている。 ( 3 ) 質問・相談事項 ( なるべく具体的に ) strncmp は , 無条件に文字列を比較する s ープの可能性こそはなくなったものの , 不 正な入力に対しても『何らかの処理』を行 宛先 trcmp とは異なり , 第 3 引数て、示される先頭 〒 108 東京都港区高輪 2 ー 19 ー 13 ってしまうのだ。真の改良版は示さない の文字数のみを比較する。したがって , No 読者ご自身て、 , 考えていただきたい v て、も Nove て、も November て、も 11 月と判定て、 NS 高輪ビル ソフトバンク ( 株 ) 出版事業部 きるわけだ。 sscan C マガジン編集部 まとめ 数値データを文字列として読み込むのは , 『 Dr. 望洋のプログラミング道場』係 誤入力に対して有効て、あることがわかった。 参考文献 今回の内容は , 「 < 第 1 回 > 標準入出力ラ , こて , この手法を複数の形式の入力に応 イプラリ』 ( 1992 年 8 月号 ) とも関連のある内 [ 1 ] 平林雅英 , TANSI C 言語辞典』 , 技術評 用することがて、きる。 List 7 のプログラムを見ていただきたい。 容て、あった。バックナンバーをお持ちて、あ 侖社 , 1989 読み込んだ数値を処理する 読み込んだ数値を処理する ( 改良版 ? ) 【重要】入力データが正しいという保証 がないかぎり , 入力ストリームから直接 数値データを読み込もうとするべきて、は 一三 List List 1 : #include く stdio. h 〉 2 : 3 : int main(void) int num; 6 : while ( 1 ) ( 7 : 8 : scanf( ” Xd ” , &num) : if (num = 9999 ) break; 10 : 11 : 何らかの処理 12 : 13 : 14 : 15 : } く stdio. h> 1 : #include く stdlib. h 〉 2 : #include 3 : 4 : int main(void) 6 : i nt num ; while ( 1 ) { 8 : buffer[10]; 9 : Char 10 : if (scanf( ” Xs ” , buffer) 11 : if ((num ニ at0i (buffer)) 12 : 13 : 何らかの処理 14 : 15 : 16 : 17 : 18 : } = EOF) break; = 9999 ) break; return ( の ; return ( の ; 140 C MAGAZINE 1992 12

9. 月刊 C MAGAZINE 1992年12月号

たのて、 , 次はプログラムて、表現してみまし 使って状態を表現する 変 8 : #define EXIT—STATE Li st 2 : 3 : 4 : 5 : 6 : 9 : 10 : 12 : 13 : 14 : 15 : 17 : 18 : 19 : 20 : 21 : 22 : 23 : 24 : 25 : 26 : 27 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : 36 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 47 : 48 : } 引用部分を抜き出すプログラム ( 変数で状態を表現 ) 1 : #include く stdi0. h 〉 例題 1 はそれほど難しい問題て、はなく , ま た Fig. 4 て、状態遷移図まて、描きましたのて、 , 試しにプログラムを書いてみましよう (List 引用部分を抜き出すプログラム List 3 て、 は , 状態を表すために , state という変数を 用意しました。この変数の値が何になって いるかが現在の状態を表しているのて、す。 また状態の移り変わりは変数 state への代入 て、表されます。 たとえば , if (state = QUOTE STATE) . という条件文は「引用部分を読んて、いる状態 て、あるか」という意味になりますし , state = QUOTE STATE ; という代入文は「引用部分を読んて、いる状態 への状態遷移」を表現していることになりま す 0List 3 と Fig. 4 を見比べて , プログラム と図との対応を理解してください 現在の変数の値が状態を表し , 変数の値 が変化することが状態遷移を表すのて、す。 いいて、すね。変数に値を代入するというの は , 難しくいえばそのプログラムの内部状 態を変化させていることなのて、す。 プロッラムを整理してみる List 3 のプログラムて、はわざと INIT ST ATE やら EXIT STATE やら , 状態をはっ きり分けてみました。しかし , 重要な状態 は NORMAL STATE と QUOTE STATE のふたつだけてす。状態がふたっしかあり ませんから , 現在引用部分かどうかを示す フラグがひとつあればいいということにな ります。・ ・・なるほど , フラグ (flag) という のはそういうものなのてすか。ふたつの状 態を区別するための変数なのてすね。て , そこに目をつけて書いてみたのが List 4 て 3 ) 。 main(void) ; I N IT_STATE #de f i ne NORMAL-STATE 7 : #define QUOTE—STATE main(void) C ; int VOid #define VOid 0 1 2 3 / * はじまりの状態 * / / * 地の文を読んでいる状態 * / / * 引用部分を読んでいる状態 * / / * 終わりの状態 * / int state = INIT STATE; whi le (state ! = EXIT—STATE) ( state ニ NORMAL_STATE; putchar(' *n' ) : else if (c state = EXIT_STATE; if (c ー = EOF) { cas e QUOTE_STATE : break; state = QUOTE—STATE; else if (c state = EXIT_STATE; = EOF) { case NORMAL_STATE: / * すぐ次の状態へ * / s tate = NORMAL_STATE : case INIT_STATE: switch (state) ( c = getchar() ; else { putchar(c) ; break; cas e EXI T_STATE : break; default: fprintf(stderr, break; "lnvalid state%n") ; す。変数 quoted が 0 なら地の文 , 1 なら引用 部分て、す。 List 4 のほうが List 3 よりも字面 上はスッキリしているように見えます。 List 4 はずいぶんスッキリしているように 見えますが , じいっと見ているうちに , 私 は首をかしげたくなりました。「これて、絶対 大丈夫」という確信がなぜか得られないから て、す。 List 3 のほうは起こり得る状態を sw itch て完全に分けているのて , 「すべてを尽 くした」という感じになります。それに対し て List 4 のほうは , 字面上は見やすくなって いるように見えますが , 「本当にすべてを尽 くしているのだろうか」とどうも不安になり ます。またこのプログラムを改良していく ときのことを考えると ,List 3 は必要な cas e の部分だけを直せばよいけれど , List 4 て は全体に目を通す必要があると思います。 いったいどうしててしようか。 List 4 を読ん ていて心に起こる不安感はなんなのてしょ うか。 List 4 が不安感を引きおこすのは , 状態を 意識していないからのように思われます。 List 3 の変数 state の四つの状態を変数 quot ed のふたつの状態に整理したのはたいへん プログラミングの工ッセンス 117

10. 月刊 C MAGAZINE 1992年12月号

kWin 機能を指定して Windows に対応した からといって , プログラムマネージャ登録 時にカッコいいアイコンがつくわけて、もあ りませんし , 引数つきの起動が常識のプロ グラムは , 起動ダイアログからしか起動て、 きません。理由はわかりますね。 QuickWin 機能には , QuickWin 機能を直 接操作するための関数も用意されています (TabIe 10 ) 。 これらの関数は , FILE 関数系と同じく , ストリームや ID て、操作するのて , 非常に簡 単に利用することがて、きます。 List 32 は , List 31 を QuickWin 関数を用いるように変 更したバージョンて、す。 PWB 上でのプログラミングの実 . て、は統合環境 PWB を利用してプログラム を作成してみましよう。 PWB て、プログラム を作成する場合 , コンパイラが動作する環 境が必要て、あることはいうまて、もありませ ん。つまり , ① Windows から利用 ② Windows の DOS プロンプトから利用 ③メモリマネージャから利用 のいずれからかを選ばなくてはならないわ けて、す。デバッグのことを考えると , Wind ows 対応のプログラムを作成する場合には① を , それ以外の場合は②か③の環境て、作成 するのがベストかもしれませんが , 二つの 開発環境の違いは , Windows アプリケーシ ョンのデバッグがダイレクトにて、きるかど うかの違いだけて、すから , ユーザがマシン 環境と相談して自由に決めればよいて、しょ 筆者は①を利用してサンプルを作成しま した。なぜ①を選択したかというと , それ は筆者の日常の開発環境が DOS / v だからて、 す。 DOS / V ューザは高解像度を簡単に入手 て、き , デフォルトが Windows 環境て、す。必 要に応じて DOS 窓を開いて DOS へ移行しま す。一方 , PC ー 9801 ユーザは , デフォルトが DOS 環境て、す。必要に応じて Windows を起 78 C MAGAZINE 1992 12 List 32 万年カレンダー ( QuickWin 関数使用パージョン ) 2 : / / 万年カレンダー Copyright (c) 1992 Masahiko lto. 4 : 5 : #include く io. h 〉 6 : #include く stdio. h> 7 : #include く stdlib. h> 8 : #include く dos. h 〉 9 : 10 : #def ine OPENFLAGS ” w ” 11 : 12 : void main (int argc, char *argv ロ ) : 13 : GregorianCalender(int iYear, int month) : 14 : 15 : static int monthEndC] = { 0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ) : 16 : char wintitle ロ = ”万年カレンダー表示ウインドウ” : 〃 Title for window 17 : FILE *wp; / / ウインドウのポインタ 18 : 19 : void main (int argc, char *argv ロ ) 20 : { char szBufC100] ; 21 : 22 : int iYear, month; 23 : struct dosdat@_t ddate; 24 : 〃 Open information struct _wopeninfo wininfo; 25 : wabout ( " 万年カレンダー for QuickWinYnVersion 1.01#nCopyright (c) 26 : 1992. Masahiko lto AI 1 rights reserved. " ) ; 28 : wininfo. verslon QWI NVER ; 29 : wininfo. title ニ wintitle; 30 ・ wininfo. wbufsize WI NBUFDEF ; 31 / / カレンダ表示ウインドウをオープン 32 叩ニ -fwopen (&wininfo, NULL, OPENFLAGS) : 33 if()p = NULL) 34 35 printf( ” ***ERROR: -fwopen*n" ) : 36 exit ( 1 ) : 38 39 40 41 42 43 : 44 : 45 : 46 : 48 : 49 : 50 : 51 : 52 : 53 : 54 : 55 : 56 : 57 : 58 : 59 : 60 : 61 : 62 : 63 : 64 : 66 : 68 : 69 : 70 : 71 : 72 : 73 : 75 : 76 : 80 : GregorianCalender(int iYear, int month) 〃ウインドウのアクセス条件 if (argc ト 3 ) if (argc = -dos-getdate (&ddate) : iYear = ddate. year; month = ddate. month; else puts ( ” Gregorian PerpetuaI Calender Version 1.00 " ) : puts ( ” Usage: ca year month ” ) ; exit ( 1 ) ; else iYear = atoi (argv 1 ) ; month ニ at0i (argv 2 ) ; —wsetexit ( WINEXITNOPERSIST) ; GregorianCalender (iYear, month) ; printf ( " 年入力 ( 終了は ) 〉〉” ) ; if (gets (szBuf) = NULL) break ; iYear = atoi (szBuf) ; printf ( " 月入力 ( 終了は・ Z ) 〉〉 " ) ; if (gets (szBuf) ニ NULL) break ; month ニ atoi (szBuf) ; wsetfocus (-fileno (wp)); / / カレンダ表示ウインドウをアクティブ化