printf - みる会図書館


検索対象: 月刊 C MAGAZINE 1993年6月号
30件見つかりました。

1. 月刊 C MAGAZINE 1993年6月号

List 27 : / * 53 : / * 58 : { questno + 1 , X' y) ; 九九練習プログラム ( kuku. c) * 名前 kuku 一九九練習プログラム 2 : 3 : 4 : 5 : 6 : 7 : 8 : 9 : 10 : 11 : 12 : 13 : 16 : 17 : 20 : 22 : 23 : 24 : 25 : 26 : 28 : 29 : 30 : 31 : 34 : 35 : 36 : 37 : 38 : 39 : 40 : 41 : 42 : 43 : 44 : 45 : 46 : 48 : 49 : 50 : 52 : 54 : 55 : 56 : 57 : 59 : 60 : 61 : 63 : 64 : 66 : 68 : 69 : 71 : 73 : 74 : * 書式 A> KUKU * 解説 一九九を練習する プログラム kuku は、九九の問題をランダムに 2 0 個表示して その正解数と正解率を表示するプログラムである。 * 作者 結城浩 ( C マガジン「 C 言語プログラミングレッスン」 ) Copyright (C) 1993 by Hiroshi Yuki. 14 : #include く stdio. h 〉 15 : #include く stdlib. h 〉 #include く time. h 〉 18 : #define MAX_Q 20 19 : #define MAX_LINE 21 : void main(void); kuku(int questno) : VOid print_result(void) ; VOid int good_answers / * 表示する問題の個数 * / 128 / * 入力行の最大長 * / / * 正答の個数 * / * 関数 main は九九の練習をする。 * 問題を X - Q 回繰り返す。 * 最後に結果を表示する。 32 : void main(void) int i; float rate; / * 現在時刻を使って乱数の「種」を得る * / srand((unsigned int)time(NULL)) ; printf ( " これから九九の問題を Xd 問出します。 *n", MALQ); good_answers for (i = 0 ; i く MAX-Q; i + + ) { kuku(i); rate = good-answers * 100.0 / MAX—Q; printf(" 問題は Xd 問あリました。 }n", MAX-Q); printf("Xd 問は正しく答えられましたが、” , good-answers); printf("Xd 問は間違ってしまいました。 *n", MALQ ー good-answers); printf(" 正答率 % 0. If % % です。 }n" printf( ”お疲れさま。 *n"); rate) : printf("%n ” ) ; * 関数 kuku は九九の問題を一問出し、答えを待つ。 * 正答、誤答の別を表示する。 kuku(int questno) x, y, result; VOid int y = rand ( ) % 9 + 1 ; x = rand ( ) % 9 + 1 ; Char buffer[MAX_LINE] ; if (x * y ー = result) { result = atoi (buffer) : gets(buffer) : printf( ” [ 第 Xd 問 ] Xd X Xd printf( ” }n ” ); printf( ”残念、まちがいです。” ): else { good_answers 十十 ; printf( ”はい、正しいです。” ): C 言語プログラミングレッスン A > lcc Iist6. c このメッセージは「 ' age' という名前が定義 age' undefined age' undefined こんなエラーが表示されます。 と実行して , List 6 をコンパイラにかけると list6. c 17 : list6 . c 16 : C 言語入門講座 89 ログラムが作れるようになりました。今月 りましたのて , だいぶプログラムらしいプ て , ューザから文字列をもらう方法もわか ム「 KUKU 」て、す。変数の使い方も理解し 今月のプログラムは , 九九練習プログラ 九練習プログラム」 ど見た List 5 になります。 List 6 の間違いをすべて直したものは先ほ てくれませんのて、 , 注意してください printf の引数の数はコンパイラはチェックし というひとつの整数しか引数がありません。 age 十 10 数の引数はふたっ必要なのて、す。けれど , の中には % d がふたっ入っていますから , 整 の行に間違いがあるのて、す。そう , 文字列 age 十 10 ) ; 10 年後は %d 歳ですね。 *n", printf(" 今 %d 歳とすると、 実は最後のほうの , がまだあるからて、す。 ンバイラが見つけることのできないエラー たからといって安心してはいけません。コ ところて、 , 工ラーメッセージがなくなっ 事 , 工ラーメッセージはなくなります。 ge の定義を入れてコンパイルし直すと , 無 っている場所が 2 か所あるからて、す。変数 a メッセージがふたつ出たのは , 変数 age を使 をしなくてはならないのて、す。同じ工ラー をしたり参照したりする前に , 変数の定義 きませんね。それと同じように変数に代入 を作らないうちに箱に物を入れることはて、 う前に必ず定義しなくてはなりません。箱 という変数の定義がありません。変数は使 int age ; や , List 6 をよく見てみると , 確かに されていません。」という意味て、す。おやお

2. 月刊 C MAGAZINE 1993年6月号

C 言語プログラミングレッスン 動示数点を使た計算をしています。 と書けばよいて、すね。 ります。画面には 11 と表示されます (Fig. 7 ) 。なお , 変数を定義している行 (int x ; ) 浮動小数点数とはまたずいぶんいかめしい ア、エーション の次に空行が 1 行空いているのは C て、プログ 名前て、すが , 普通の実数と思ってけっこう ラムを書くときの慣習て、す。空行を空けな て、す。変数定義は , 変数の定義 , 代入 , 参照を学んだところ くてもプログラムの動作の上て、は何の支障 float x, y , て、 , 簡単なプログラムを読んて、復習してみ と書きます。 float は「フロート」と読みます もありませんが , プログラムを見やすくす るための工夫て、す。 のて、 , 「浮動小数点数の計算」という代わり 次に List 2 を見てください。今度は何が表 に「フロートの計算」ということがあります。 まず List 1 を見てください。このプログラ ムをコンパイルして実行すると何が表示さ 示されるて、しようか。こて、は , 変数がふ List 3 を実行すると ,Fig. 9 のように 23.5 と れるて、しようか。このプログラムて、は整数 たっ定義されています。整数型の変数 x と y 表示されます。変数への代入を見てくださ 型の変数 x を作り , その変数に 4 を代入し , て、す。 2 * x 十 3 の計算結果を printf て、表示して int x, y , X います。結果はどうて、しよう。 2 * x 十 3 は , を計算する時点て、 x の値は 4 になっています から , 2 * x は 8 , それに 3 を加えて 11 にな 2X ェ十 3 15.0 , Fig. 7 List 1 の実行結果 int X ・ と書いたのと同じことて、す。 x に 15 , y に 32 を代入して , (x 十 y) / 2 を計算すると ( あ , これは平均の計算だ ) , 答えは何にな りますか。答えば 23.5 て、はありません。 C 言 語て、の整数の計算は小数以下が切り捨てら れますから ( 先月号を思い出してください ) , 答えは 23 になります (Fig. 8 ) 。 切り捨てごめんはいやだという方は List 3 こて、は整数て、はなく を見てください List 2 で浮動小数点数を使う 凵 STI ℃をコンバイル LISTI . EXE を実行 凵 STI . EXE の実行結果 1 1 ・ 1 0 1 O @ ・ 1 1 1 List 1 : #include く stdio. h> 2 : 3 : main() 5 : int x; 7 : printf( ” Xd}n ” 8 : 2 * x + 3 ) : Fig. 8 List 2 の実行結果 凵 ST2 ℃をコンバイル LlST2. EXE を実行 凵 ST2. EXE の実行結果 •P ・ 1 1 00 0 1 O @ ・ 1 、 2 1 、′ 3 List List 1 : #include く stdio. h> 2 : 3 : main() 5 : float X, y; 6 : x = 15.0 : 7 : 8 : y ニ 32.0 : printf( ” %0. lf*n ” , (x + y) / 2 ) : 9 : 10 : } 0 0 り 0 よ 、ノ 1 よりっ 0 4 -0 ー 8 9 0 Fig. 9 List 3 の実行結果 凵 ST3. C をコンバイル 凵 ST3. EXE を実行 ーー凵 ST3. EXE の実行結果 ・ 1 1 3 ・ 1 •P 0 1 O @ ・ 1 1 5 、′ 1 、′ 3 1 2 浮動小数点数の使い方 List Fig. 10 List 4 の実行結果 A 〉 lcc list4. c 凵 ST4 ℃をコンノヾイル 11d @link. i わ list4 凵 ST4. EXE を実行 12.340 圓 0 12.340 圓 0 12.3 12.3 1 : #include く stdio. h 〉 3 : main() printf( ” Xf*n ” , 12.34 ) ; 5 : printf("X6f*n ” , 12.34 ) : 6 : printf("X6. Of*n ” , 12.34 ) ; 7 : printf( ” %6. lf%n ” , 12.34 ) : 8 : printf( ” %0. lf*n ” , 12.34 ) ; 9 : 10 : } ず表 せで 示ま / 表位 * は一で / 部第ま 本数数位 示小 ででで数 / 桁桁桁小 CD CO CD ず・ 示もももせ 表とととに にくくく気 通なななを 普少少少桁 凵 ST4. EXE の実行結果 C 言語入門講座 85

3. 月刊 C MAGAZINE 1993年6月号

N mo 祀 数が , 実際には 2 か所に展開されるというこ るような書き方をするべきて、ある。 マクロでの注意点 ということて、 , 評価の途中て、の副作用が とには注意が必要て、ある。いい換えれば , マクロに渡した引数は一度評価されること プログラムの動作に影響をおよばす例とし 最後に , マクロ定義と評価の関係につい て , List 2 のような奇妙なテストプログラム も二度評価されることもある。これはいい 古されたバグの原因て、はあるが , いまだにけ て少々述べておこう。たとえば , 次のよう を作ってみた。 List 2 は List 1 を改造したも っこう見られるものて、もある。たとえば , のて、 , 関数 baz, z 。 t が大域的な変数 i の値を なマクロを定義したとする。 #define isNumber(d) ( ' 0 ' く = (d) ついつい次のように使ってしまって問題が 更新する。そして , 関数 bar はその i の値を返 す。 bar の返した値に応じて fun0 ~ fun2 まて、 発生する。 ご覧になればおわかりになるように これが困るのは , ソースだけを見ている の関数を選択する。したがって , baz, zot と bar が呼ばれる順序の前後関係に応じて , れは引数て、指定した値が 10 進の数字かどう と何が悪いのかが一見して判然としない かをチェックするものて、ある。標準ライプ とて、ある ( ちなみに , ctype. h の中の isdigit fun0 が呼ばれたり , fun2 が呼ばれたりする。 複数の ANSI コンパイラにアクセスて、きる人 ラリ ctype. h の中て、定義される isdigit (c) と機 は , 仮にマクロとして実装されていたとし ても , 引数の評価は一度だけにかぎられる 能上は類似て、ある。 は , ぜひそれぞれて、このソースをコンパイ ことが ANSI て、規定されている ) 。 しかし , この定義て、はマクロに渡した引 ルして , 何が起きるかを試してほしい if (isNumber(*p + 十 )) { 評価と副作用の問題 List もし ,isNumber を関数として実装してい れば , この問題は生じない。関数の実引数 は関数を呼び出すときに一度だけ評価し , あとはその値を使うからて、ある。ただし , 関数を呼び出すとオーバヘッドが大きい場 合もある。マクロて、も , 引数をたかだか一 度だけ評価するように定義すれば間題はな しかし , 補助変数の助けなどを借りない とそれを実現するのが難しい場合も少なく ない ( たまたま , この isNumber て、あれば , テープルを参照するような実装を行えば , 補助変数なして、解決て、きる ) 。 C 十十て、あれば , inline 関数という機能を 利用することて、 , このようなジレンマを解 消することがて、きる。あるいは gcc て、あれ ば , 独自の「式の中にプロックを置いて , ロ ーカル変数を宣言て、きる」という機能を利用 て、きる。どちらも , マクロの実行効率を保 ったまま , 実引数の評価を一度だけに止め ることがて、きる便利な機構て、ある。しかし , 残念ながら ANSIC にはその類の機能はない のて、 , マクロ展開形式を工夫するしかない だろう。 とにかく , 副作用を伴う式を書くときに は要注意て、ある。 1 : # i nc lude く s td i 0. h> 2 : 0 : 4 : 5 : void fun0(int x, int y) printf("fun0:%d %dYn" 7 : 9 : 10 : vo i d f un 1 ( i n t x, i n t y) printf("funl:%d %dYn" 15 : void fun2(int x, int y) 1 6 : { printf( ” fun2:%d %dYn ” 20 : void (**foo(void))(int, static void (*tbl[])(int, 22 : printf("f00Yn"); return tbl; 26 : } 28 : int bar(void) printf("bar%n"); 30 : return i; 32 : } 33 : 34 : i n t baz ( vo i d ) 36 : printf("baz%n"); return 十十 i : 39 : 40 : int zot(void) printf("zot%n"); 43 : return 十十 i : 46 : int main(void) 47 : { 48 : return 0 : int) { fun0, funl, fun2, } : int) ANSI C ー more 135

4. 月刊 C MAGAZINE 1993年6月号

円羽信夫 プログラミング シャッフルクイズ作成プログラム か〃というぐあいだ。で , この、、こいつ , だ 前略。元気か ? 丹羽君よ。 めか″というのが問題で , そこから、、かめ 小生の近況だが , 最近 , シャッフルクイ だいっこ″という元の名前を考え出すとい ズというのに凝っている。こいつは , テレ うのがこのクイズの仕組みだ。まあ , この ビのクイズ番組で見つけたもので , あらか 場合 , 同じ町内会の亀田さんの知人でない じめ , 名前の読みの文字の順番を入れ換え と答えが出んわけだが。 て , 何か別の意味を持つ言葉として作り直 シャッフルクイズの問題を思いつきで作 しておき , そこから元の名前を推理させる るのは難しいので , こいつの問題を簡単に というクイズだ。 作成するためのツールを作ろうと思ってい たとえば , 、、亀田伊都子〃なら、、かめだい る。まずは , 入力した全角ひらがな ( 全角カ つこ〃が元の読みで , シャッフル , つまり タカナでも , 半角カナでもかまわんのだが , 入れ換えて何か別の意味を持つ言葉をでつ , こでは全角ひらがなということにしてお ちあける。まあ , 一例として、、こいつ , だめ List 2 ( その 18 ) イラスト / 山形彰吾 ロバート・佐々木氏は , 私のご近所の方 で , すでに年齢 70 を越え , 現在は現役引退 の身である。氏は , 2 年前の夏まではパソコ ンをワープロとして使う経験はあったもの の , プログラムのなんたるかはまったく知 らなかった人物である。そのロバート氏が , 92 年初頭に C 言語のマスターを決意し , 以 後 , 私 ( 丹羽 ) とミステリアスな C 文通を始め た。その文通は今でも続いている。 さて , 今月も , 同じ町内に住むロバート 氏から郵便局経由で手紙が届いている。さ っそくだが , 見てみることにしよう。 List sO. c ・ー 8 0 1 よワ 00 -4 ・ - トっ :D ー 8 0 ー 1 り 0 00 -4 LO CD ー 8 0 11 ワ 3 00 ・ 4 ・ LO 8 0 1 よワ 3 ワ 0 1 , 1 ー 1 11 1 人 1 ワ 3 っ 0 ワワっ 0 ワ朝ワ朝ワ朝ワ 3 ワ朝ワ 0 00 ワー・ 00 00 00 00 っ 0 り 0 4 ・ -4 ・ 4 ・ 4 ・ -4 ・ -4 ・ -4 ・ -4 ・ 4 ・ -4 ・ strcpy(), s[n]) : strcpy(s[n],s[j]); strcpy(sCj], t); / * s [ n ] と s [ j ] をいれかえる * / perm(n-l) ; strcpy(t,sCn]); strcpy(sCn],sCj]); strcpy(sCj],t); / * s [ n ] と s [ j ] をいれかえる * / 1 : # i ncl ude く s td i 0. h 〉 2 : #include く string. h> 3 : 4 : main() 6 : 7 : 8 : 9 : 20 : char strC256]; char s [ 128 ] [ 2 ] : i n t len , else printf ( " 全角文字で入力してください . > " ) ; gets(str); Ien=strIen(str)/2; / * 全角文字だから 2 で割ると文字数になる * / for (i=0;i<len;i + + ) strncpy(s[i],&str[i*2],2); puts(sCi]); / * 分解した文字が配列にいまく入れられたか確認した * / for (j=0;j<len;j + + ) printf("%s",sCj)); printf("}n"); char strC256]; char s [ 128 ] [ 3 ] ; / * 入力した全角文字を要素ごとに分解したものが入れられる配列 * / i nt len ; i nt i : List s2. c printf(" シャッフル文字列作成プログラム \ n " ) ; printf( ”ー pr i nt f ( " 名前を全角ひらがなで入力してください . 〉 " ) : gets(str); Ien=strIen(str)/2; for (i=0;i<len;i + + ) strncpy(sCi],str + i*2,2); / * 交換する文字要素の配列を設定する * / pr i nt f ( " シャッフル ! Yn" ) : printf("- perm(len-l) : printf(" 終了 \n"); 1 : # i ncl ude く s td i 0. h 〉 2 : #include く string. h 〉 3 : 4 : VO i d pe rm ( i n t n ) 6 : char tC3] ; 7 : / * 全角文字の構成要素を入れかえる時に使う一時的な配列 * / 8 : 9 : 10 : if (n>0) perm(n-l) : for ( j ニ n ー 1 : j 〉ニ 0 ; j 176 C MAGAZINE 1993 6

5. 月刊 C MAGAZINE 1993年6月号

リズムに近い性質を持った MST アルゴリズ ムが作れるかもしれません。これを検討し てみましよう。 基本的なアイデアとしては ,Kruskal のア ルゴリズム同様に , とにかく短い辺から順 に選択していこうとするものて、す。しかし , 単に短いものから順につないて、も一筆書き の順路にはなりませんから , 順路として余 計な辺は選択しないように , コントロール しながら選択していくことになります。そ のようすを Fig. 5 に示します。 一筆書きになるための条件を検討するこ とにしましよう。まず一筆書きの性質から , ひとつの節点から伸びる枝はちょうど 2 本に なっているはずて、す。枝が 3 本以上あるこ とは , 「枝別れ」の状態になるからて、す。っ まり , ひとつの節点につながる辺は , 2 本以 下て、あることをチェックしなければなりま 109 : { fo 「 (e List 6 80 : 82 : 90 : 100 : 101 : 10 2 : 103 : 104 : 10 5 : 106 : 1 07 : e く nedges; e 十 + ) { / * 辺 e の両頂点 ( vl , v2 ) が異なるグループに属しているならば * / int vl : edges[e]. vl; int v2 = edges[e]. v2; printf()d : Xd*n" if (selected = n_vertex) { selected + + : / * 辺の長さを足し込む * / d + : edgesCe]. veight; drav-Iine(), xyCvI). x, xyCvl). y, xyCv2). x, xyCv2]. y); / * 辺の頂点を表示する * / vertex-counterCv2] 十十 : vertex-counter[vl] 十十 : / * 辺のカウンタを増やす * / join(group, n-vertex, groupcvl], group[v2]) : / * ニつのグループを併合する * / n-vel 、 tex (groupCvI] ! = g 「 0 叩 [ v2 ] Ⅱ selected : i f (vertex-counter[vl] く 2 & & vertex_counter[v2] く 2 & & return; / * 正常終了 * / せん。 番号という考え方を用いて , 上記の集合操 ログラムて、は , 各集合に対応するグループ ていることに気づきます。前回紹介したプ アルゴリズムて、もまったく同じことを行っ てみると , この後者のチェックは Kruskal の こて、 KruskaI のアルゴリズムを思いだし ことになります。 に属していないかどうかをチェックすれば 辺をつなぐまえに , 両端の節点が同じ集合 をつなぐことを意味します。したがって , のは , 元々同じ集合に属するふたつの節点 て、 , ある辺をつないだために閉路がて、きる る集合をマージ ( 併合 ) していきます。 を 1 本つなぐたびに , 辺の両端点が属してい ていると考えることにします。そして , 辺 す , 初期状態て、各節点は別々の集合に属し 以下のように検査することがて、きます。ま このチェックはめんどうなようて、すが , いくつもて、きることになります。 けません。そうしないと , ばらばらの輪が 閉路 ( 閉じた輪のような順路 ) を作ってはい いといけないのて、 , 最後の 1 本以外の枝は , また , TSP は最終的に 1 本の順路にならな ことにしましよう。 108 : 110 : 1 12 : 113 : 1 18 : 1 19 : 1 2 0 : 121 : 12 2 : 1 2 3 : 12 4 : 125 : 1 2 6 : 12 7 : 128 : 12 9 : 130 : 131 : 132 : 13 3 : 13 4 : 135 : 13 6 : 137 : 138 : 139 : } int set-edges(point- assert( の : nedges for (i = 0 : i く for (j : t xy ロ . こに到達することはありえない * / / * 全ての辺を生成する * / int n-vertex) : j く n-vertex; j 十十 ) { n-vertex & xy Cj ] ) , i n t main(int argc, char *argv[]) edges 〔 nedges). ⅵ edgesCnedges]. v2 edgesCnedges]. veight : distance(&xy[i), nedges 十十 : return nedges; int n_vertex; if (argc く 2 ) { fprintf(stderr, " 使用法 : tsp3 頂点ファイル名 \ n " ) : ex i t ( I) : init-graphics(); = set-xy(xy, argv[l]); n_vertex set-edges(xy, n_vertex) : greedy2(n-vertex) : printf("hit any key (void)getchar() : flush-graphics() : return 0 : 作を行いました。今回は , それを流用する , こて、 , 今まて、説明したことをもとに , ムを List 4 に示します。また参考のために 辺中心の強欲戦略に基づく TSP アルゴリズ 前回説明した Kruskal のアルゴリズムの基本 部分を List 5 に示しました。両者を見比べて いただくとすぐわかるように , 両者はたい へんによく似ています。このため , 前回作 った kruskal. c の骨格を大部分流用すること / * 頂点座標を読み込む * / / * すべての辺を生成する * / / * TSP を求める * / 98 C MAGAZINE 1993 6

6. 月刊 C MAGAZINE 1993年6月号

C 言語プログラミングレッスン atoi (buffer) ・ agel と書きます。等号をふたっ空白を開けずに の代入処理の中て、自動的に浮動小数点数型 並べていることに注意してください。詳し に変換されます。 数学て、は , そういえば今月 くは来月のお楽しみて、す。 のプログラムの中にい、 〃は使われてい と書いて , x に y の値を代入するという意味 にもなりますが , x と y は等しい関係にある ますね。探してみてください 今月は変数について学び , ついて、にキー という意味にもなります。「代入する」とい ササイズの解答 ポードから文字列を入力する方法について う意味なら C 言語と同じて、すが , 「等しい関 も学びました。ちょっと盛りだくさんすぎ 係にある」という意味なら C 言語と意味はま 先ほどの平均年齢を求めるプログラムの ましたか ? ったく違います。わかりますか ? 説明の中て、 , たくさんの小さなサンプル 解答て、す。自分て、解いてみましたか。 「代入する」の場合は , プログラムが出てきましたね。ぜひ皆さん 答えとなるプログラムは何通りも書ける も自分の手て、これらのプログラムを修正し , と思いますが , たとえば List 8 のようになり コンパイルし , 実行してみてください。プ ます。文字型の配列 namel と name2 はふた ログラム言語は粘土のようなものてす。皆 りの人の名前を格納するための変数て、す。 はまったく逆の意味になりますが , 「等しい さんが自分の手て、いろいろこねくり回して それぞれ関数 gets を使ってユーザに入力させ 関係にある」場合には , 上のふたつの式は 初めて習得て、きるのて、す。どうぞいろいろ ます。配列 buffer は年齢をユーザに入力して まったく同じ意味になります。 C 言語の等号 「やってみて」ください。 もらうときに一時的に入力した年齢 ( 文字 ( = ) は「代入する」の意味て、あることをこ さて来月は「もしもの国のアリス」という 列 ) を格納しておくための変数て、す。文字列 て、強調しておきます。 タイトルて、 , i fi について学ぶことにしま としての年齢を数値に変換するのは関数 at 。 それて、は「等しい関係にある」という i て、す。 す。 は C 言語て、は表現て、きないのて、しようか。て、 ふたり分の年齢を数値として格納する変 これまて、作ってきたプログラムの流れは きます , て、きます。それは来月に詳しくお 数は agel と age2 て、す。この変数の型は ( 定義 割り合いに単純て、した。 if 文の使い方を覚え 話しましよう。 を見ればわかりますが ) 浮動小数点数型て、 ると , もっと複雑な処理も自由に書けるよ あ , 書き方だけいっておきますね。 C 言語 す。関数 at 。 i が返す値は整数て、すが , C 言語 うになってきます。どうぞお楽しみに て、 x と y が「等しい関係にある」かどうかを調 この連載についてのご意見 , ご質問など て、は べるときには , がありましたら , 本誌綴込みのアンケート 工クササイズの解答 葉書て、編集部まて、お送りください また , 下記住所宛て、もけっこうて、す。 〒 103 東京都中央区日本橋浜町 3 ー 42 ー 3 ソフトバンクスクウェア ソフトバンク ( 株 ) 出版事業部 C マガジン編集部 「 C 言語プログラミングレッスン」係 パソコン通信をしている方は , 下記まて、 メールを送ってくださってもかまいません。 整理の都合上 , メールの表題は「 C 言語プロ グラミングレッスンについて」としていただ けると助かります。 yohyohl ( 宮田洋一 ) 日経 MIX NIFTY-Serve PAF02236 ( 流王天 ) PCS39500 ( 高森昭安 ) ASCII NET UMF84901 ( 渡辺淳一 ) PC-VAN C 言語入門講座 91 ログラムになってしまうことに注意してく と List 1 : #include く stdio. h> 2 : #include く stdlib. h> 3 : 4 : #define MAX—LINE 5 : 6 : main() nameI[MAX_LINE], name2[MAX_LINE] ; 8 : char bufferCMAX_LINE] : 9 : Char 10 : float agel, age2; 11 : printf ( ”二人の平均年齢を計算します。 %n"); 12 : 13 : printf ( ”一人目の名前を入力してください 14 : gets(namel) : printf(' ' % s さんの年齢を入力してください : 16 : gets(buffer) : 17 : agel = atoi (buffer) : printf ( ”ニ人目の名前を入力してください 20 : gets(name2) : 21 : printf ( " % s さんの年齢を入力してください : 22 : gets(buffer) ; 23 : age2 = at0i (buffer) : 24 : 25 : printf( ” Xs さんと % s さんの平均年齢は % 0. If 歳です。 }n ” , 26 : namel, name2, (agel + age2) / 2 ) ; 128 namel ) ; , name2) :

7. 月刊 C MAGAZINE 1993年6月号

た値は消えてしまうのて、す ( Fig. 5 ) 。代入に よって値が変わるのて、変数という名前がつ いているのて、す。 余談て、すが , 代入したとたん , 変数のそ れまて、の値が消えてしまうというのはコン ピュータの記憶装置 ( メモリ ) の性質そっく りて、すね。そう , 「変数」という考え方は , コンヒ。ュータのメモリの考え方を抽象化し たものなのて、す。名前があって , 値を入れ ることがて、き , 値を入れ直さないかぎり昔 の値を記憶し続け , 新しい値を入れたとた ん昔の値を忘れてしまう・・ これは変数と メモリに共通の性質て、す。メモリには「 x 」の ような名前はありませんが , その代わりに 番地 ( アドレス ) があるのて、す。以上 , 余談 て、した。 値を見る ( 参照 ) Fig. 4 値の代入 C のプログラム あなたのイメージ 4 0 0 0 0 0 0 「箱 x のフタを開けて 4 を入れる」 x は整数型の変数なので 整数 4 を入れることができる 「 x に 4 を代入する」 Fig. 5 ニ度目の代入 4 3 さっき入れた 4 は消えてしまう 変数という箱を作り , 箱に何かを入れま した。今度は , 今その箱に何が入っている かを調べてみましよう。変数の中に入って あたい いるものを , その変数の値といいます。変 さんしよう 数の値を見ることを変数を参照するといい ます。 変数を参照するのは簡単て、す。たとえば , 整数型の変数 x の現在の値を表示するには次 のようにします。 printf("%d*n", x) ; これて、 , 画面には変数 x の値が表示されます (Fig. 6 ) 。 printf ("%d*n", 3 十 4 * 5 ) ; と比較してみてください 変数の値を直接表示させるだけて、はなく , t 算の中に変数を使うこともて、きます。数 学て、 ( 誤り ) 4 2 ェ十 3 とは書けません。「 = 」という記号は , 右辺 という式を書くように , C 言語て、も の値を左辺の変数に代入するという処理を 2 * x 十 3 行うしるし ( 子 ) なのて、す。「 = 」は「イコ とプログラムに書いた場合 , 初めの x = 4 : と書くことがて、きます。数学て、は 2 とェの乗 ール」と読みます。 て、変数 x には 4 が代入され , 次の x 3 : て、 算を 2 工と書きますが , C 言語て、は 2 * x と書 変数 x にはあらためて 3 が代入されることに く約束になっています。 2 * x 十 3 の計算 は「エックスイコール 4 」または , 「 x に 4 なります。そのとき , 初めに代入された 4 と 結果を表示するにはどうしたらよいと思い を代入する」と読みます。 いう値は影も形もなくなってしまいます。 ますか。そうて、す。 変数への代入は何回て、も行うことがて、き 代入した瞬間に , それまて、変数に入ってい printf("%d*n' , 2 * x 十 3 ) ; 84 C MAGAZINE 1993 6 Fig. 6 値の参照 C のプログラム ティスプレイ あなたのイメージ 4 0 0 0 printf("%d*n", x) : 「変数 x の値を整数として表示する」 4 「箱 x のフタを開けて中身を見 , それをディスプレイに表示する」 箱の中身の 4 が消える わけではない す

8. 月刊 C MAGAZINE 1993年6月号

2 と表示する。すなわち , ポインタ変数に * 演算子を適用すると , ポインタ変数が指す ものを間接的に扱えるのて、ある。したがっ て , ptr が x を指すとき , *ptr は x の工イリ アスすなわち別名 ( あだ名 ) といえる。 【重要】ポインタ変数 pt 「が x を指すと き , * pt 「は x の実体そのものを間接的に 表す工イリアスとなる このようすは , Fig. 2 のように考えてもら こて、 , メモリの本体 えればいいだろう。 に x や ptr といった名前のつけられたものが , 通常の変数 ( オプジェクト ) て、あり , その横 に飛び出した箱が , そのオプジェクトに対 して与えられたェイリアスて、ある。 もちろん , ポインタは , 別のオプジェク トを指すようにも変更て、きる ( 別のオプジェ クトの番地を持てる ) のて、 , ptr = &y , Fig. 3 List 2 の実行結果 によって , ptr は y を指し , * ptr は Y 家族の構 成人数ということになるだろう。 ハインタと関数 値渡 int 型は家族の構成人数を持っということ こて、 , 『出産』と『死亡』によ て、あった。 る構成人数の増加・減少を , それぞれ関数 として作成してみたのが List 2 て、ある。 Fig. 3 の実行結果からもわかるように のプログラムは正しくない。これは , C 言語 の関数の受け渡しが , 値渡し (pass by val (e) て、あることによる。すなわち , 関数を呼 び出す際は , 引数として , 変数の「実体」を 渡すのて、はなく , それの持つ「値」を渡すの て、ある。これは , 実引数 (argument/ 渡す側 の引数 ) の値が , 水道の蛇口から出る水て、あ り , 仮引数 (parameter/ 受け取る側の引数 ) は , それを受け取るバケッと思っていただ ければいいだろう。すなわち , 引数の受け 渡しは一方的なものて、あり , 呼び出された 出産と死亡 ( 間違い ) List く stdio. h> 1 : #include 4 : void birth(int num) 10 : void death(int num) 20 : 22 : 23 : 26 : ー出産ー 十十 num; 一死亡ー —num; int main(void) / * x 家は 5 人 * / / * y 家は 3 人 * / / * x 家で出産 * / / * y 家で死亡 * / i nt X i nt y birth(x); death(y); printf()x 家の構成人数ニ %dYn" printf()y 家の構成人数 : %d%n" return ( の ; x 家の構成人数 : 5 y 家の構成人数ニ 3 出産と死亡 LiSt 1 : #include く stdio. h 〉 4 : VOid birth(int *num) 8 : 10 : VOid death(int *num) 1 5 : int main(void) 20 : 22 : 23 : 26 : ー出産ー 十十 *num; 一死亡ー —*num; / * x 家は 5 人 * / / * y 家は 3 人 * / / * x 家で出産 * / / * y 家で死亡 * / i nt X i nt y birth(&x); death(&y) ; printf()x 家の構成人数 : %d%n" printf()y 家の構成人数 = %dYn" return ( 0 ) : 138 C MAGAZINE 1993 6

9. 月刊 C MAGAZINE 1993年6月号

#define MAXLINE 256 char f00 [ 10 ] ; atoi (buffer) ; age という代入を行えば , 整数型の変数 age には と書けば , これは文字型の変数の配列て、す。 char buffer [MAXLINE] ; 型の違いは重要て、あり , その違いは必ず 120 という整数が代入されます。分解して説 と書いてあります。これは , 明すれば , プログラムの字面上に反映されるというこ char buffer [ 256 ] ; 文字の配列 とを知ってください。「どうして型なんても buffer と書くのとまったく同じ効果を持ちます。 atoi (buffer) 整数に変換 のがあるのか」という疑問についてはまた別 つまり , 文字型の変数を 256 個並べた配列を 変数に代入 の機会にお話したいと思っています。 atOi (buffer) ・ age 定義していることになります。ナゾの数字 となります。 ササイズ 256 を変数定義のところに書くのて、はなく , こて、 , 私が意識的に「 " 120 " という文字 いったん MAXLINE という名前に置き換え 列」とか「 120 という整数」というふうに型を させてプログラムを読みやすくしているの 明示していることに注意してください。日 それて、は問題て、す。今日学んだことをフ て、す。 MAX は maximum( マキシマム [ 最 常生活て、は「 120 」といった場合 , 文字列とし ルに使って , 次の問題に挑戦してみましよ 大 ] ) の略のつもり , LINE は line( ライン う。まずは前を読み返さないて、考え , 次に ての 120 なのか , 整数としての 120 なのか , [ 行 ] ) のつもりて、す。 などということは意識しません。しかし , 前のページを読み直して考えてみてくださ C 言語て、プログラムを書く場合 , その区別 ( い。これまて、学んだ知識だけて、解けるはず 文字列を整数に変換する 型の区別 ) は非常に重要て、す。 の問題て、す。がんばってみましよう。自分 いかん , 説明が深みに入り込んて、しまっ 具体的にいいましよう。型の区別はどの の頭て、考えて , 自分の手を動かしてプログ た。 List 5 をもう一度ご覧ください ラムを書き , コンパイルして動作させてみ ようにプログラムの字面に反映されるか , gets (buffer) ; て、す。もしあなたが , という行て、 , プログラムは一時停止して入 120 カ待ちになります。ューザがキーポードか と書けば , これは整数て、す。もしあなたが , ら入力した文字列は変数 buffer に格納されま ” 120 ” す (Fig. 13 ) 。 と書けば , これは文字列て、す。違いはわか 名前を表示するときにはおなじみの関数 りますよね。二重引用符 ( " ) の有無によって printf を使います。整数表示ては % d を使い プログラマは「あっちは整数の 120 て、す。 ました。文字列の表示て、は % s を使います。 っちは文字列の " 120 " て、す。」とコンピュータ 問題は年齢て、す。 10 年後の年齢は , 年齢 に指示を送っていることになります。 に 10 を加えれば求めることがて、きます。け また , 変数定義て、も同じことて、す。もし れども , あなたが , buffer 十 10 ( 誤り ) int f00 , として求められるわけて、はありません。変 と書けば , これは整数型の変数て、すし , 数 buffer は文字の配列て、す。 10 を加えるとい ミスティク う整数の計算をする前に , 変数 buffer に格納 されている " 120 " という文字列を 120 という 整数に変換しなくてはなりません。そのた めに atoi という関数が用意されています。 a toi は ASCII to integer ( ASC Ⅱ文字を整数 に ) という言葉の略て、 , 「アスキートウイ ンテジャー」または「エイ・トウ・アイ」と みます。人によってはローマ字のように「ア トイ」と読む人もいます。 文字型の配列 buffer の中に " 120 " という文 字列が格納されているとき , 関数 atoi を使っ て , 88 C MAGAZINE 1 3 6 【問題】ふたりの名前と年齢を入力する と , その人たちの年齢の平均を表示する プログラムを書いてください 解答は本稿の最後にあります。 ティク 間違い探しのコーナーて、す。 List 6 をじい っと読んて、間違いを探してください ためしに List 6 を LSIC て、コンパイルして みましようか。 List 1 : #include く stdio. h 〉 2 : #include く stdlib. h 〉 3 : 4 : #define MAXLINE 256 6 : main() 8 : Char 9 : 10 : 11 : 12 : 13 : 14 : 15 : buffer[MAXLINE] ; printf ( ”あなたの名前を入力してください。 #n ” ) : gets (buffer) ; printf( ” Xs さん、こんにちは。斐 n ” , buffer) ; printf ( ”年齢を入力してください。 *n ” ): gets(buffer) ; age ニ atoi (buffer) : printf(" 今 Xd 歳とすると、 10 年後は Xd 歳ですね。 }n ” age + 1 の : ニ = ロ

10. 月刊 C MAGAZINE 1993年6月号

入力するのを待っている」状態にあるのて、 と書かれていますね。単に 15 と書かずに 15.0 ず , あなたの名前を入力してください。 す。この状態を入力待ちの状態といいます。 と書いているのは , 「整数て、はなく浮動小数 名前を入力してみましよう。たとえば , と表示されます。表示が終わった後 , カー 点数なのだよ」ということを強調するためて、 不老長寿 す。実は C 言語て、は適切な型の変換というも ソル ( 画面て、チカチカ光っている長方形のマ と入力してリターンキーを最後に押します。 ーク ) は次の行の先頭にきて止まっていると のが行われますのて、 , たとえ , すると , 今度は 田います。いつもならすぐに A > などのプロ X 不老長寿さん、こんにちは。 ンプトが表示されますが , このプログラム と書いたとしても間違いて、はありません。 年齢を入力してください。 て、はいくら侍ってもプロンプトへは戻りま すなわち 15 という整数が , 浮動小数点数に せん。いまプログラムは , 「あなたが名前を と表示され , 同じように入力侍ちに入りま 変換された後に変数 x に代入されるのて、す。 けれどお作法としては , 15 . 0 ; X と書いておくほうが , プログラマの意図が はっきりするのて、よりよいと思います。 こて、注意していただきたいのが , 変数 の名前と型は無関係ということて、す 0List 2 て、は変数 x は整数型て、したが , List 3 て、は同 じ名前の変数 x は浮動小数点数型て、した。変 数の名前を見ただけて、は型を知ることはて、 きません。必ず変数の定義を見るようにし てください。変数の定義には必ず型が書い てあります。それを見て初めて「あ , この変 Fig. 12 配列を作る 数の型は int ( 整数型 ) だ」とか「 char ( 文字型 ) だ」といえるのて、す。変数を見たら変数の定 義を見る癖をつけましよう。 それから浮動小数点数を printf て、表示する ためには , % f を使います。 List 3 て、使われ ている % 0. If は「表示幅を規定しないけれ ど , 小数部分は幅を 1 桁にする」という意味 て、す。たとえば 123.45 という浮動小数点数 を表示する場合 , List 4 のようないろいろの やり方があります (Fig. 10 ) 。 ポードから入力する 舌は変数からちょっとはずれますが , キ ーポードから文字を入力する方法について 説明しておきましよう。 List 5 をご覧くださ い。これはユーザとちょっとした会話をす るプログラムて、す。会話といっても , あな たの名前と年齢を尋ねるだけのことて、すが , 例題としてはこれて、まずは十分て、す。 入力待ち List 5 をコンパイルして動作させると , ま 86 C MAGAZINE 1993 6 15 ; Fig. 1 1 List 5 の実行結果 A>lcc list5. c 11d @link. i A>list5 あなたの名前を入力してください。 不老長寿 不老長寿さん、こんにちは。 年齢を入力してください。 120 今 120 歳とすると、 10 年後は 130 歳ですね。 LIST5 ℃をコンバイル 凵 ST5. EXE を実行 凵 ST5. EXE の実行結果 あなたのイメージ 9 5 個 C のプログラム 0 0 0 char a[5]•, a[2] 「文字を入れる箱を五つ作った」 箱の名前は a [ 0 ] —aC4] てある a[5] はないことに注意 a [ 0 ] a [ 4 ] a[3] 「サイズ 5 の文字型の配列 a を定義」 文字入力のあるプログラム List 1 : #include く stdiO. h> 2 : #include く stdlib. h 〉 3 : 4 : #define MAXLINE 256 5 : 6 : main() buffer[MAXLINE] : 8 : Char int age; 9 : 10 : pr intf ( ”あなたの名前を入力してください。 }n ” ) ; 11 : gets(buffer) : 12 : printf( ” Xs さん、こんにちは。 #n", buffer) : 13 : 14 : printf ( ”年齢を入力してください。 *n ” ): 15 : gets(buffer) ; age = atOi (buffer) : printf( ”今 Xd 歳とすると、 10 年後は Xd 歳ですね。” , age, age + 1 の : 19 : } 1 三ロ