関数 - みる会図書館


検索対象: 月刊 C MAGAZINE 1991年8月号
121件見つかりました。

1. 月刊 C MAGAZINE 1991年8月号

容 , 条件などのステートメントは , パーツ 上て、マウスをタブルクリックすることて、記 述て、きる。ステートメントには , コメント も書くことがて、きる。 画面上段のメニューバーには , 、、 Undo" チャートの実行〃 , ヾ画面表示′′ , システ や , る。 ム〃 ステートメント数といった項目が表示 る。環境〃て、は , 現在のチャートデータ数 み , 保存 , 印刷 , といった処理が選択てき 、、システムクて、は , チャートの読み込 、、環境〃といった項目が表示されてい 148 C MAGAZINE 1991 8 ミングは命令を置き換えていけばよい。 FOR ルゴリズムがしつかりしていればプログラ ムは基礎的な数値処理のものてあろう。ア これらを利用して記述されるアルゴリズ て、同時に開くことがて、きる。 て、きる ( TabIe 2 ) 。ューザファイルは 3 本ま スクリーンの制御には拡張コマンドが利用 数が用意されている ( TabIe 1 ) 。ファイルや 演算 , 文字列操作などのための組み込み関 処理の記述に当たっては , 基礎的な数学 ある。 は 1 バイト文字を 40 個まて、扱うことが可能て、 7 桁 , 小数部 5 桁の有効桁数を持ち , 文字型 が変数のみ使用て、きる。数値型は , 整数部 変数が利用て、きる。配列は 2 次元まて、のもの FLAG て、は , 数値型 , 変数型の定数および FLA の機能 ロジックを完成させることがぞきるだろう。 れらの手順を繰り返すことにより , 目的の にシュミレートすることも可能て、ある。 などの入出力は , 実際の媒体以外に画面上 スすることがて、きる。ファイルやプリンタ またこのとき指定した変数の内容をトレー て、実行中のステップはグリーンて、表示され , を選択することて、確認て、きる。チャート上 作成した処理内容は , 、、チャートの実行〃 十分足りる量て、ある。 なっているが , 小規模のロジックて、あれば される。チャートデータ数の最大値は 100 と TabIe 1 F G で使用可能な組み込み関数 カテゴリ 変換関数 文字列関数 数学関数 関数 SIN CHR ASC STR VAL SAPCE MID MOD ABS INT SQRT ARCTAN TAN COS 意 味 TabIe 2 F G で使用可能な拡張コマンド カテゴリ ファイルコマンド スクリーンコマンド 参照変数名入力コマンド 説明文読み込みコマンド コマンド @OPEN @FILE @CLOSE @PATH @SCRNCLR @MOVEPOSX @MOVEPOSY @BEEP @SCRIPT @ⅲ @Dn ラジアンに対する正弦値を返す ラジアンに対する余弦値を返す ラジアンに対する正接値を返す ラジアンに対する逆正弦値を返す 平方根を返す 小数値を切り捨て ( 整数化 ) 絶対値を返す 剰余を返す 文字列から指定された桁数の文字列の抜き出し 指定された桁数の空白を返す 文字型の数値表記を数値に変換 数値を文字型に変換 1 バイト文字をキャラクタコードに変換 キャラクタコードから文字を得る 意 参照変数名の入力行変数コマンド 参照変数名の入力行変数コマンド 説明文のファイルからの読み込み ピープ音 表示位置の移動 ( 縦位置 ) 表示位置の移動 ( 桁位置 ) 画面の消去 ノヾスの指定 ファイルの使用終了 入出力ファイルを指定する ファイルの使用の宣言

2. 月刊 C MAGAZINE 1991年8月号

工ル江ス・アイジャパン lnformation from C0mpiIer Makers 前回はバーションアップされた LSIC-86 Ver. 3.30 について紹介 LSI C ー 86 Ver. 3.30 は言語仕 様やライプラリが ANSIC 標準規格 に準拠したコンパイラとなってい ます。ただし , ANSIC 標準規格と は多少 , 仕様が異なっている部分 がありますのて、 , 今回は LSI C ー 86 Ver. 3.30 と ANSI C 標準規格との 相違点を示します。また , 則ノヾー ジョンの LSI C ー 86 Ver. 3.1 から の変更点についても示しておきま す。 ANSI C 標準規格との違い 0 ロ ・ LSI C ー 86 て、はキーワード far, near, nonrec, recursive 力防旦カ日 されています ・整数の格上げ (lntegral promo tion) ルールが ANSI の定義とは 若干異なっています ・プリプロセッサはトライグラフ シーケンス ( ? ? と 1 文字て、特殊記号 を表す ) をサポートしていません ・ wchar t および L' … ,, L " …”はサ ポートしていません ・可変パラメータ関数は float, double, long double, 構造体 , 共 用体を返すことがて、きません。 正確には可変パラメータ関数が 返すことがて、きるのは , リター ン値がレジスタに割り当てられ るものだけて、す ・はじめて現れた外部変数や関数 の宣言に extern がついている場 合 , その後の同じ変数や関数の 旦言 , 定義には static と指定して 160 C MAGAZINE 1991 8 もかまいません ・ ANSI 規格て、は INT MAX を越 える定数の型は long になります が , LSI C ー 86 て、は値が UINT MAX より小さいか等しい場合に は unsigned int になります ・浮動小数点定数はすべて long double 型として扱います ライプラリ ・く locale. h > と , その中て、定義さ れているマクロや関数はサポー トしていません ・多バイト文字を扱う関数群 ( mblen ( ) など ) はサポートしてい ません ( 2 ) LSI C ー 86 Ver. 3.1 との違い ロロ ・関数へのポインタ fp を使って関 数を呼び出す場合に , fp ( ) と書く ことがて、きるようになりました。 もちろん , 以前の ( * fp)( ) も許さ れます ・共用体の初期化が可能になりま ・配列や構造体型の自動変数を初 期化て、きるようになりました ・ const/volatile をサポートしまし ・関数と配列に対して単項演算子 、、 & 〃を使用することがて、きるよう になりました。 ・以前は auto と明示した変数は必 ずスタックに割り付けられてい ましたが , このバージョンから は auto 変数もレジスタ割り付け の対象となります。スタックに 割り付けたい場合は volatile を使 ▽ ってください unsigned int, signed int が使用 ・ビットフィールドの型は int, るようになりました らどこにて、も現れることがて、き ・列挙定数は int を書けるところな バル変数やスタティック変数を 定していないときには , グロー ・ #pragma optimize space を指 ルドをサポートしました また , 符号付きのビットフィー 列挙は使用て、きなくなりました。 て、きます。以前のように char や たためなくなりました ・ farstr. lib は doslib. lib に統合され ライプラリ 示的に参照してください の中 <$(LSICOPTS) のように明 変数を参照したいときには , lcc を参照しなくなりました。環境 ・ lcc は環境変数 LSICOPTS など -L に変更されました ーチするディレクトリの指定 ) は -B オプション ( ライプラリをサ イルを探すようになりました レクトリからオプジェクトファ とによって , ライプラリのディ ー I オプションて、 . obj を明示するこ 化を実行しなくなりました れば , r86 はジャンプ命令の最適 ・ lcc に一 O オプションを指定しなけ になりました ルの名前が Isic86. cfg から lcc ・コンフィギュレーションファイ なりました に指定することがて、きるように ・関数に対して far , near を明示的 なりました ワード境界に割り付けるように LSI C -86 Ver. 3.30 ・浮動小数点数を表示て、きない printf/scanf 系関数を含んだラ イプラリファイル intlib. lib を追 加しました。これにともない浮 動小数点数を表示て、きる関数は mathlib. lib から doslib. lib に移 動しました ・いくつかのライプラリ関数は▽ er. 3.1 とは仕様が変更されています のて、注意が必要て、す バージョンアップサー ピスについて すて、に LSI C ー 86 をご購入のお 客様はバージョンアップサービス を受けられます。 バージョンアップサービス料金 は 8 , 000 円て、す。登録ューザにはバ ージョンアップ案内のダイレクト メールを送らせていただきます。 バージョンアップに関する詳しい 内容はダイレクトメールをご覧く ださい なお , 旧バージョンをご使用に なっているお客様て、 , まだューザ 登録カードを返送されていない方 , またはユーザ登録をされた後て、住 所が変更になったお客様て , まだ 新しい住所をご連絡いただいてい ない方にはバージョンアップに関 するご案内がお届けてきない場合 があります。まだ住所変更の連絡 をされていない方は , 住所変更の 届け ( シリアル番号 , 旧住所 , 新住 所 ) とともに , バージョンアップ案 内の送付希望と明記して , 弊社ま て、ご連絡ください。 また , まだューザ登録をなさっ ていないお客様はお早めに登録カ ードを弊社まて返送してください。 ▽

3. 月刊 C MAGAZINE 1991年8月号

lnformation from Compiler Makers らこのエラーを修正できるのか教 えてください。 1 : A Stack は関数がコールされたと きに , 値が格納されるメモリ領域 てす。全ての関数の引数と関数コ ールのリターンアドレスは , 関数 がコールされたときに stack に置か れます。それに関数内て、宣言され たスタティックて、ない変数も stack に置かれます。 19 : { CPU のスタックポインタレジス 22 : } タ ( SP ) は , これらの値に適応させる ために調整されます。関数が実行 されるときに , 関数の引数が stack から引き出されるのてす。関数が 実行を終えると , 関数リターンア ドレスは , 関数コールの次のアド レスに戻るために使用されます。 36 : } つまり , stack にある値は LAST- IN, FAST- OUT の規則に従って 引き出されます。 stack overflow のメッセージの 意味は , プログラムが宣言したロ ーカル変数が , stack に格納て、きる 範囲を越えていることを意味しま 1 : 19 : { 22 : } 数を static 宣言することを考慮して こうすると , 変数は関 ください 数に対してプライベートになりま す ( プログラムの他の部分には見え ません ) 。変数はグローバル変数と してプログラムのヒープに格納さ れます。 他の方法としては , 関数の初め にヒープに変数を割り当てるため に malloc を使い , 関数が終了する 前に free を使って変数を解放する こともて、きます ( しかし , この方法 ては , 関数が頻繁にコールされた 場合に , 不必要にヒープが細分化 されます ) 。大きなローカル変数を 扱う場合は , ヒープスペースを割 り当てることがいちばんよい方法 てす。関数内て、定義された配列が ある場合は , 配列をベース型のポ インタとしてメモリを割り当てて ください ( 関数がリターンする前に スペースの解放を行ってくださ い ) 。関数の外て、 , 配列をグローバ ル変数としても宣言てきますが , よいプログラムとはいえません。 こうするとプログラムの stack の代 0 0 ださい の中に Fig. 3 のような行を入れてく 000 バイトにするには , プログラム たとえば , stack のサイズを 10 , みてください バイトて、すから , これを増やして 保しています。デフォルトは 4096 ることにより , stack のサイズを確 スタートアップルーチンて参照す バル変数を , 実行時に main の前の C 十十て、は , stklen というグロー とを考えてください。 Turbo 最後に , stack のサイズを増やす ます。 わりにヒープのスペースを消費し List 1 2 : 3 : 4 : 5 : 6 : 7 : 10 : 12 : 13 : 17 : 18 : 20 : 23 : 26 : 27 : 28 : 29 : 30 : 31 : 32 : 33 : 34 : 35 : #include く iostreame. h> class Primer{ int private: int a: //CIass Primer のインスタンス変数 public: int get ( ) : set(int al); VO i d 〃グローパル変数 a int Primer::get() return a; //C lass Pr i mer のインスタンス変数 a VOid Primer::set(int al) a = a 1 : 24 : VO i d 禧 i n ( ) 十十 : //C lass Pr i mer のインスタンス変数 a / / グローバル変数 a Primer primer; cout くく”グローバル変数 a primer. set( 十十 a) : くく a cout くく "primer のインスタンス変数 cou t くく " グローバル変数 a くく a a くく くく くく primer. get() くく・ \ n ・ Yn ・ : List 2 integer; i nt friend ClassNunber2,• 5 : c lass C lassNumber1 { 3 : c lass ClassNumber2 #include く iostream. h> 6 : 4 : 2 : す。関数を頻繁にコールしている か , または関数のネストが深い場 合が考えられます。 これらの問題には , いくつかの 解決方法があります。まず , どこ て、 ( どの関数内か ? )stack スペース が消費されているか調べてくださ い (Turbo Debugger を使うことも て、きます ) 。 スタンスが必要てない場合は , 変 の実行には変数のフレッシュイン ーシプてあってもそれぞれの関数 ない場合 , またはもし関数はリカ もし , 関数がリカーシプ ( 再帰 ) て ら取り除くことを試みてください つぎに , ローカル変数を stack か 7 : 8 : 9 : 12 : 14 : 15 : 16 : 17 : 18 : 20 : 21 : 23 : 24 : 26 : 28 : 29 : 30 : } int ClassNumber2: :Function2(CIassNumberI& data) int Function2(ClassNumberl&) : public: 13 : class ClassNumber2 { CIassNumber1(int i) {integer=i;} public: void Function1(void) {cout くく "Functionl !Yn";} data. Function1() ; return data. integer; void main() くく test2. Function2(test1) くく響 n ” : cout くく "set integer test2 : ClassNumber2 testl ( 5 ) : ClassNumberl Fig. 3 stack のサイズを 10 , 000 バイトにする lnformation from Compiler Makers extern unsigned stklen ニ 10000 , 159

4. 月刊 C MAGAZINE 1991年8月号

新、、ト プログクス門 C プログラマ のための 中島信行 第 1 1 回環境変数の操作 MS ー DOS では , 環境変数か重要な役割を果たしま す。 MS ー C などの C コンノヾイラでも , 環境変数によ りテフォルトの開発環境を設定する処理系も少な くありません。今回は , MS ー DOS ユーサにとって 身近な存在である環境変数について , 少し掘り下 げて解説します。 の実行例て、す。これを見ると , List 1 て、は環 しないバッファ上になければなりません。 / C による環境変数の 境変数 PATH は確かに変更されています 具体的にいうと静的な文字列 , 関数外て、定 変更の不思議 が , 終了後の PATH は元のまま変更されて 義したグローバルな文字列などて、す。 いません。なぜ List 1 て、はこのような現象に C 言語ては通常 , 環境変数を次のふたつの putenv 関数は与えられた引数のポインタ なるのて、しようか。今回はこの理由を明ら 関数て、操作します。 のみを処理し , 文字列の内容はコヒ。ーしま かにして , 環境変数を操作する方法を紹介 char *getenv (constchar * name); せん。そのため , func 関数を抜けてしまう します。 int putenv (const char * name); と putenv 関数て、指し示すようにしていた領 まずはこれらの関数を使用して環境変数 域が消滅してしまい , 誤動作します。 List 1 putenv 関数について PATH に て、も auto 変数を使用しています。しかし , main 関数内の auto 変数は , プログラムが終 ; YUSR 話を始めたばかりて、脱線しますが , ちょ を追加するテストプログラムを List 1 ( 付録 「するまて、消滅しません。したがって , 正常 っと List 2 ( 付録ディスク収録 ) を見てくださ ディスク収録 ) に示します。 Fig. 1 は List 1 に動作しているのて、す。 い。 List 2 は List 1 を一部書き換えたもの MS-DOS 環境変数の Fig. 1 List 1 の実行例 て、 , 環境変数 PATH の変更を func 関数内て、 メモリプロック B : *>path 行うようにしたプログラムて、す。この List 2 PATH = B : \ には間違いがあります。どこが間違ってい それて、は話を元に戻します。 MS-DOS て、 B:*>list1 変更前 : PATH = B : ¥ るかわかりますか ? は , プロセス ( プログラム ) を起動するとき 変更後 : PATH=B•.*;*USR 実は func 関数内のバッファ buf が auto 変数 にふたつのメモリプロックが確保されます。 B.•*>path PATH = B : \ になっているのが誤りて、す。 putenv に与え ひとつは起動するプロセス用のメモリプロ る文字列はプログラムが終了するまて、消滅 ックて、 , もうひとつはそのプロセス用の環 88 C MAGAZINE 1991 8

5. 月刊 C MAGAZINE 1991年8月号

スタートアップ C 十十 4 実力養成講座 cout. width ( 7 ) ; の形式によって実現て、きる。 cout. fill( ℃ ,) ; / / バディング文字℃ ' 口までのまとめ ・ 10 進数表示く dec> cout くく 10 ; cout くく dec くく Oxa : 今回まて、一貫して , C 言語に拡張された機 cout. fill ( ' ' ) ; / / スペースへ戻す ・ 8 進数表示く oct > 能の側面を中心に C 十十を解説してきた。 パディング文字指定の場合 , printf て、は , cout くく OCt くく 10 ; C 十十に追加された機能を以下に示す。 スペースか 0 以外を指定て、きなかったが , ・ 16 進数表示く hex> ・コメントの記述 C 十十て、は , 任意の文字を指定て、きる。 cout くく hex くく 10 ; ・変数の宣言方法 標準入力ストリームて、は , cin に対し演算 ・文字コードくキャスト > ・定数型 子、、 < く〃 ( getfrom ) を用いてデータの入 cout くく (int)c ; ・型変換 ( 型チェックの強化 ) 力を行う。 cin て、は , scanf のような入力フォ ・ 1 文字出力く put(char) > ・キャスト ーマットの書式は指定せず , 入力されたデ cout. put('A') ; ・関数の定義方法 ータを格納する変数の型によって決定され cout くく 'A' ; 〃同様 ・関数のプロトタイプ宣言 ・フィールド幅 <width(int) > ・関数のオーバロード また , scanf< は , 入力データを格納する cout. width ( 7 ) ; / / 7 桁幅指定 ・スコープ ( グローバル ) 演算子 変数のポインタを引数に指定するが , cin て、 cout くく i ・ ・インライン関数 は , 引数を参照型としているため変数名を ・小数点以下桁数く precision (int) > ・参照型 指定する。ただし , 文字列の入力て、は , 入 cout. width(7) : ・ void 型の扱い 力された文字列を格納する領域のポインタ cout. precision ( 4 ) ; / / 小数点以下 4 桁 ・関数へのポインタの扱い を指定する。 cout くく 3.141592 ; ・構造体変数の宣言 : right) > ・右詰めく self(ios : ・共用体の扱い cin < < i < < f く < &s [ 0 ] cout. width ( 7 ) : ・列挙型 1 文字の入力て、は , 関数 get を使用すること cout. self(ios : ・ストリーム入出力 もて、きる。 cout くく 10 ; 今回まては , C に慣れたユーザには退屈な cin. get( cha 「型変数名 ) : cout. unself(ios ・ 部分も多かったて、あろう。しかし , C に欲し 関数 get を使って文字列の人力を行うこと ・左詰めく self(ios : かった機能やプログラミングの際に有効な もて、きる。 cout. width(7) ; 機能が備わっていることを実感していただ cin. get ( P, len, c) : left) : / / 左詰め cout. self(ios : けたのてはないかとも思う。これらの機能 char 型変数のポインタ P cout くく 10 ; によって , C よりもより効率的なプセログラ 人力文字列の最大の長さ len :left) ; / / 解除 cout. unself(ios : 入力文字列の終端子 ミングが可能になるはずて、ある。 ・バディング文字く fill(char) > : right) : / / 右詰め : right) ; / / 解除 : left) > 実 践編 白倉伸一郎・山本浩文 ( ) を使っていたが , C 十十て、は new を使う」 ます onew, delete は花形て、はないかもしれ ませんが , クラス機能が人形浄瑠璃の人形 というような誤解が , 広くまかりとおって だとすれば , new, delete はそれを裏から支 います。いや , 誤解というのはいいすぎか えて操る黒子て、す。今回は new, delete につ もしれませんが , 少なくとも正しい理解と いて解説します。 はいえません。 確かに C 十十の入門書などを見ると , そう プ VS malloc( ) 解説されているものも見受けられます。し かし , それは初心者が混乱しないように 便宜上割り切って書いているだけのことて、 「 C 言語て、は動的なメモリの取得は malloc / n w, delete は黒子 C 十十の数ある拡張機能の中て、も , new, delete はクラスに次いて、大切な機能て、す。に もかかわらず , クラスばかりが脚光を浴び て , new, delete はその陰に隠れがちて、す。 ある程度 C 十十になれた人て、も , しつかりと 理解しないまま使っていることがままあり スタートアップ C 十十 137

6. 月刊 C MAGAZINE 1991年8月号

Fig. 10 関数呼び出しと引数の授受 main 関数 search (atensu, AMAX, 50 ) ; * mar int max int ten Figs 1 1 atensu と mark の関係 sea 「 ch 関数 atensu [ 0 ] atensu [ 1 ] atensu [ 5 ] * (atensu 十 5) * atensu * (atensu 十 1 ) mark mark mark [ 5 ] [ 0 ] [ 1 ] atensu[Ol atensu[l ] atensu[2] atensu[31 atensu [ 4 ] atensu[5] mark max te n *(mark 十 1) * mark *(mark 十 5) りの記述がて、きます。横の並びは同じもの を意味します。 List 7 は前回解説したプログラムて、す。前 回は「『 main 関数は atensu という配列を渡し て ,search 関数はそれを mark という名前て、 受け取る』と取りあえず理解してください こて、『取りあえず』と断わったのは , ポ インタなどの難しい概念との絡みがあるか らて、す」と説明しました。実は search 関数の 頭部は , int search(int *mark, int max, int ten) とも記述て、き , int mark [ ] と書いても , int * mark と書いてもまったく同じ意味を持ち ます oint *mark と書くと , mark が配列て、 なくボインタて、あることがはっきりわかり ます。すなわち Fig. 10 のようなやり取りを 行うわけて、す。 32 行目は , no=search(atensu, AMAX, (0) : となっています。 1 番目の引数 atensu は , 配列 atensu の先頭要素 (atensu [ 0 ] ) へのポ インタて、す ( 配列名が単独て、現れると先頭要 素へのポインタとなるのて、したね ) 。したがっ て , 配列の先頭要素のアドレスが渡されま す。受け取る search 関数側は , これを mark に受け取ります。 mark は atensu [ 0 ] を指 します。よって , *mark は atensu [ 0 ] の ェイリアスとなります。このとき , Fig. 11 の図式が成り並ちます。 search 関数の中て、 は , mark はポインタて、すが , [ ] 演算子を 適用することによって , まるて、配列のよう に振る舞うことがて、きるのてす。 重要 関数間で , 配列は先頭要素へのポイ ンタという形で受け渡しを行う 受け取る側の関数はポインタ変数に , こて、大事なことに注意してください 列のように使うことができる [ ] 演算子を適用することにより , 配 明解 AWC 言語 入門講座 List 5 , List 6 のようなひとつのオプジェク トのポインタの受け渡しも , List 7 のような 配列 ( の先頭要素へのポインタ ) の受け渡し も , 「ポインタ」て、受け渡しを行っている点 て、まったく同じて、あるといえます。 重要 ポインタとして受け取った引数 x は ( 1 ) * 演算子を適用して , ひとつのオプ ジェクトをアクセスする ② [ ] 演算子を適用して , 配列のよう に扱う のいすれも可能である め 明解 AN C 言語入門講座 133 ています。 いほど , 確実に上達していることを意味し とか「なるほど」と感じた回数が多ければ多 「なあーんだ。そういうことだったのか」 となってしまいます ) 。 とも 1 冊の言語解説書があれば「すべてよし」 この世の中が天才だらけてすよ・・・・・・少なく してそれが理解て、きる人ばっかりだったら , っていただけますね ( いきなりすべてを解説 います ) 。級段位制をとっている理由はわか れゆえ「おまじない」などの言葉を使用して 過程を考えた教育的工夫をしております ( そ ったり「種明かし」をしたりといった正しい 「より深く」または「別の角度」から解説を行 以前に「取りあえず」と掲げた対象に対して , と変化していきます。説明する私としては , ぶ過程において , 対象を認識する概念は刻々 にプログラミング ( に限らず学問一般 ) を学 も今回少し厳密に説明しました。このよう 月号て簡単に解説した配列の授受について 算子も少しずつ正体を現してきました。先 の「おまじない」や scanf の引数につける & 演 した ( 説明は十分て、はありませんが ) 。 4 月号 「オプジェクト」という概念て、とらえ直しま 「魔法の箱」として説明していた「変数」を ,

7. 月刊 C MAGAZINE 1991年8月号

スタートアップ C 十十 実力養成講座 C 言語と C 十十④ 今回は , [ 理論編 ] ではポインタと配列や文字列に関する 処理 , 関数へのポインタそして void 型ポインタの扱いを , [ 実践編 ] では new, delete について解説する。 理論編 タによって関数の呼び出しを可能にする。 算を行い , ポインタの指す要素を変化させ ーボンタ る方法て、ある (List 1 ) 。 関数へのポインタを代入するためのポイン タ変数の宣言は以下のようにする。 字列とポインタ データ型 ( * 名前 ) ( 引数の型 ) ; ポインタと配列 C 言語て、も , 関数へのポインタを取り扱う 文字列に対し , ポインタを使っての処理 は char 型の配列に対するポインタと考える ことは可能だが , C 十十が C 言語と異なる点 配列を関数の引数とする場合は , 配列の は , ポインタ変数の宣言時に , 引数の型も ことがて、きる。ただし , 文字列は最後がヌ 先頭ポインタを引数とする。このとき , 配 ル文字 ' \ 0 ' て、終わるため , アドレス計算 必要になったことと , ポインタ変数に関数 列名を記述し関数呼び出しを行う。また , のアドレスを代入する際に , 関数名の前に などによるポインタの操作はポインタの指 受け取り側て、は配列と同じデータ型により , & 〃演算子をつけることて、ある。関数のア す文字がヌル文字まて、を処理する (List 2 ) 。 ポインタとして引数を宣言する。ポインタ ドレスを得る場合 , あらかじめ関数の定義 による配列の参照には 2 通りある。ひとつは 関数へのポインタ ポインタ変数を配列名と同様に扱い , 配列 またはプロトタイプ宣言を行っておかなく 要素の参照を行う。もうひとつは , アドレ 関数へのポインタは , 関数が割り当てら てはならない ポインタを使っての関数の呼び出しは , ス計算を行う。つまりポインタに対し加減 れている記憶域のアドレスてあり , ポイン List ポインタと配列 List 文字列とポインタ 龍崎昌平 1 : main() 3 : int func( char* ) : int len = func( "ABCDE ” ) ; 5 : 7 : int func( char* p) 9 : int while( *p ! = 10 : i 十十 : return i : 1 : main() func( int* ) ; 3 : VOid int a [ 5 ] ・ 4 : func( a ) ; 〃配列の先頭ポインタ 6 : 8 : void func( int* p) for(int i=0 i く 5 : i + + ) 10 : pCi] = 134 C MAGAZINE 1991 8

8. 月刊 C MAGAZINE 1991年8月号

, 新 MS ー DOS プログラミング入門当 C プログラマのための Fig. 8 環境変数表示ユーティリティのコンノヾイル例 lcc envdsp. c LSI C ー 86 Ver 3.20 tcc —w envdsp. c Turbo C 2 .0 / Tu 「 b0 C 十十 1 .0 M S-C 5.1 / 6.0 cl /J /W3 /Zp envdsp. c /link / st : 0X2800 / cp : 0X500 DOS ファンクション OAh バッファつきキーボード入力 TabIe 4 バッファつきキーボード入力 引数 返り値 機能 AH = OAh DS : DX = 入力バッフアへのポインタ INT 21 h なし このファンクションは入力中に DOS のテンプレート機能が使用できる 以下のフォーマットで文字列を入力する DS : DX 入力文字列 CR 実際に入力された CR を除く文字数 ( 1 バイト ) ( 本ファンクションが設定する ) CR を含むバッフア内の最大文字数 ( 1 バイト ) ( ユーサが設定する ) M S-C 5.1 / 6.0 Fig. 9 環境変数工テイタのコンバイル例 cl /J /W3 /Zp envset. c /link / st : 0X2800 / cp : 0X500 Turbo C 2.0 / TurbO C 十十 1 .0 tCC —W envset. C LSI C ー 86 Ver 3 .20 lCC envset. C ①ー fgetenv 関数て、環境変数を取得 ② cgets 関数て、環境変数を編集 ③ fputenv 関数て、環境変数を設定 しているだけて、すから , とくに難しい箇所 はないと思います。なお , 単純に環境変数 領域を取得すると間違える可能性もあるた め , 以下のことをチェックしています。 ①環境変数が 1 個以上定義されていること ②環境変数領域のメモリプロックが 64K バ あること 変数名 = 定義 , 0 , 0 のパターンて、 ③変数名 = 定義 , 0 , 変数名 = 定義 , イト未満て、あること 0 , 通常環境変数領域の終わりは 2 バイトの 00 h て、判定しますが , COMMAND ℃ OM のす べての環境変数が未定義の場合には , ター ミネータは 2 バイトの 00h て、はなく , 最初の 1 バイト目が 00h となります。この状態のメ モリプロックを環境変数領域と判断するの は危険て、す。よって , ①の条件をつけてい ます。起動時に PATH と COMSPEC が DOS により設定されるため , 意識的に環境変数 を削除しないかぎり問題ないて、しよう。 ②は , MS ー DOS て、は環境変数領域が通常 32K バイト以下て、す。したがって , チェック したほうがよいかもしれません。 ③の制限により , 環境変数の定義文字列 に = を含むことがて、きなくなります。 PROMPT コマンド以外て、は環境変数の定義 文字列に = を含むことがて、きないため , と くに支障はないて、しよう。 環境変数工テイタの コンヾイル コンパイルは Fig. 9 のように行います。 Turbo C/C 十十て、は cgets 関数が機種依存す るため , DOS ファンクション 0Ah ( Table 4 ) を呼び出す cgets 関数を作成しています ( ちな みに , 表示を高速にするため cputs 関数を機 種依存させるのはわかるのて、すが , cgets 関 数を機種依存させる意味はどこにあるのて、 しようか ? 不便なだけだと思うのは筆者 だけて、しようか ? ) 。 プログラム自体は DOS のバージョンに依 存しますが , 機種依存する部分はないのて、 , MS-DOS 3.1 , 3.2 上て、動作するはずて、す。 手元にないため確認していませんが , IBM -PC 用の MS-DOS 3.3 て、は誤動作するかも しれません。もし , 誤動作するようて、あれ ば get envseg 関数て、 DOS のバージョンの判 定を MS-DOS 3.1 と同じほうに分岐するよ うに変更してください 動作確認は PC ー 9801 シリーズの MS-DOS 3.3B と FM-TOWNS の MS-DOS 3.1 て、行 っています。 まとめ C 言語て、は親プロセスの環境変数を操作す るライプラリが提供されていません。その ために親プロセスの環境変数を操作て、きな くて困っている方も多いかと思います。今 回紹介した fgetenv 関数と _fputenv 関数を 応用すれば親プロセスの環境変数を操作す ることもそれほど難しくないと思います。 今回は説明を簡単に済ませたため , より詳 しいことを知りたい方は参考文献 1. および 新 MS ー DOS プログラミング入門 3. ( 付録ディスク収録 ) を参照してください 93

9. 月刊 C MAGAZINE 1991年8月号

実力養成講座 4 以下の形式となる (List 3 参照 ) 。 変数 2 = (int * ) 変数 1 ; int * 変数 2 ; void * 変数 1 ; 入する際には明示的な型変換を必要とする。 り void 型ポインタをある型のポインタへ代 は型変換なしに行えるが , 逆の場合 , つま る。このように , void 型ポインタへの代入 領域のポインタを返す場合などに使用され 合や , 関数からの返り値が型のないメモリ きない関数の引数としてポインタを渡す場 て、きる。これは , 引数のデータ型が仮定て、 ポインタて、も型変換 ( キャスト ) なして、代入 void 型のポインタへは , どのような型の 変数 = char 型ポインタ , 変数 = int 型ポインタ , void * 変数 あり , 以下の形式て、宣言する。 ポインタて、も代入することがて、きる変数て る。任意のポインタは , どのデータ型への ス ) を持っポインタ変数を使用する際に用い ポインタにおいても任意のポインタ ( アドレ タイプ宣言時の引数において使用するが , void 型は , 関数の型宣言や関数のプロト 、 void 型ポインタ / / * を省略できる ポインタ変数 ( 引数の並び ) / / C と同様 ( * ポインタ変数 ) ( 引数の並び ) 構造体は , 複数の種類のデータからなる List ァータ型 ァータ型 1 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : } 12 : if( 関数へのポインタ 1 = pf( "ABCD" pf ニ &func ; func( char* ) : int 2 : main() int int int データの集合体て、ある。 C 十十における構造 体の機能 , 使用方法や操作方法は C 言語と同 じて、ある。 C との違いは , 構造体変数の宣言 ( 「 struct タグ名変数名 : 」 ) において , キー ワード struct を省略てきることて、ある。た だ , C 十十て、は , 構造体はあまり使用せず , もつばら「クラス」 ( 次回て、解説する ) を使用 する。 struct tag struct tag tag 変数 4 , 変数 1 , 変数 2 : 変数 3 : / / C 言語 , C + + 構造体て、は , 構造体変数間て、代入を行う ことや構造体変数を関数の引数とすること , 構造体変数を関数からの返り値とすること などがて、きる。 構造体の基本的な使い方は , 構造体の型 定義を行い , 必要な箇所て、定義された構造 体によって変数や配列などを宣言する。構 List 構造体の基本機能 スタートアップ C 十十 造体の型定義て、 , 型を示す名前をタグ名 , 内部のデータをメンパという。 構造体の型定義ては , 記憶域に領域は確 保されず , 変数や配列が定義されることて 領域が割り当てられる。領域が割り当てら れた後に , プログラム内て、変数名を記述す ることて、すべてのメンバがまとめて参照さ れる。個々のメンバを参照するためには , メンバ参照演算子 ! ク ( ヒ。リオド ) を用い る。また , ポインタによりメンバを参照す る場合は , 、、一ゾ演算子を用いる (List 4 ) 。 共用体は , ひとつの記憶領域に複数のデ ータを共有させる場合に用いる機能て、 , 使 用法や操作方法は C 言語と同様て、ある。 C 言語との違いは , 構造体のように変数の 宀言時にキーワード union が省略て、きる点 と , 共用体タグと変数の両方を省略てきる Cha 「 C ; union tag { ことて、ある。 tag y : union tag X ; 各メンバを同じアドレスに割り当てること 共用体タグおよび変数の宣言て、は , 単に を宣言したことになる。 1 : s truct タグ名 ( int no; name[20]; Char 5 : main() / / メンバ / / メンバ 7 : 8 : 9 : 10 : 14 : タグ名 for(int i=0; i く 5 ; i + + ) { タグ名 *S = & 矼 2 ] ; タグ名 tmp = p [ 3 〕 : 0 ー〉 no / / メンバの参照 / / ポインタによる参照 / / 構造体どうしの代入 スタートアップ C 十十 135

10. 月刊 C MAGAZINE 1991年8月号

明解 )IC 言語 入門講座 て , a, b, plus, minus の四つの値が , x, y, wa, sa にコビーされます。このコビーは あくまて、もく一方通行 > 的なものなのて、 , sumdif 関数の中て、いくら wa や sa の値を変更 しても , 呼び出し側には反映されません ( Fig. この問題をクリアするためには , C 言語の 難関のひとって、あるポインタ (pointer) を突 破しなければなりません。今回はポインタ の基本について学習しましよう。 オプジェクトについて 「変数」でなぐオプジェクト」と呼ぼう これまて、変数は「数値などを記憶するため の箱」て、あると説明してきました。それらの 箱はバラバラに存在するわけて、はなく , Fig. 2 に示すように通常はまっすぐなメモリ空間 いうこともあり得ます ) 。大きさはともかく の中の一部として存在します。 今まて、「変数」といってきましたが , 今後 「型」がひとつの性質て、す。前回解説した記 憶寿命もひとつの性質て、す。これはメモリ はオプジェクト (object) という言葉を使用し 上に存在する時間的範囲 = 寿命を指定する ます。どうして「変数」という言葉て、はまず ばう ものて、した。さらに x とか y とかいう名前 = いのかというと , C 言語には値の変更がて、き 識別子もひとつの性質て、す。 ない変数 ( ? ) = オプジェクトなどもあるか アドレス このほかにもいろいろな性質を持ったも らてす。 のがオプジェクトて、す。これまて、は「変数」 さてオプジェクトがバラバラな単独の箱 さてオプジェクトにはいろいろな側面 = と呼んて、いましたが , 単純に「変数」という て、はなく , メモリ上の一部を占めるものて 性質があります 0Fig. 2 て、は int 型の x と float 概念て、はその全貎をつかむことがて、きませ あることがわかりました。メモリ上のどこ 型の y を違う大きさて、表しています ( もちろ ん処理系によってはたまたま同じ大きさと にあるかを表すのがアドレスと呼ばれるも ん。 のてす。アドレスを英和辞典て、調べると「演 Fig. 2 オプジェクトの説明図 説」 , 「住所」 , 「番地」などの訳語がありま す。 C 言語てアドレスというと「番地」のこと て、す。住所て、〇〇番地というように , メモ リ上のオプジェクトの位置を示す番地のこ とをアドレスといいます。 Fig. 1 関数呼び出しと引数 main 関数 sumdif(), b, plus, minus); int y int wa sumdif 関数 int X ~ ~ int sa ※実引数の値の《コピー》を 仮引数として受け取る 重要 「変数」ではなく「オプジェクト」と呼 int X float y ; 重要 アドレスはオプジェクトの格納され ている番地のことである これからの変数の説明図 オプジェクト これまでの変数の説明図 明解 ANSI C 言語入門講座 127