な , ある人の身長を保存するためのものな さて , あと集めるものはないて、しようか ? 平均の計算方法は知っていますね ? 全 のて、す。 員分の値を合計して , 人数て割る。たとえ 関連のあるもの , まとめて扱ったほうがい ば 3 人の身長をそれぞれ a, b, c とすると , 平 いもの , 離しておいてはいけないものはあ 配リを使って集める ・・・ありました。「名前」て、 りませんか ? 均の身長は , ( a 十 b 十 c ) + 3 となります。 3 人 す。「太郎」 , 「花子」 , 「三郎」という名前と , の身長の数字を標準入力から取るとすると , 変数 height [ 0 ] , height [ 1 ] , height [ 2 ] 関連したものを集めると便利て、すから , プログラムは List 1 のようになります。整数 この三つの変数を集めてやることにします。 の範囲て、計算していますから , 平均 172.3 の は深い関連があります。わかりますね。変 C 言語には変数を集める機構が備わってお 数 height [ 0 ] にはほかの誰て、もない「太郎」 ところが 172 になりしますが , よしとしまし り , そのひとつが配列て、す。配列を使って くんの身長が入ります。「太郎」という名前 と変数 heightC0] ( 正確にはその添字の 0 ) は さて ,List 1 はこれていいのて、すが , どう 問題 1 を解いてみましよう。 いっしょに扱ってしかるべきて、す。だって もやばったい感じがします。そのひとつは , それが List 2 になります。先ほどの三つの 名前と身長は共通のひとりについての情報 変数はなくなり , それをまとめたひとつの 三つの変数 , なのて、すから。 配列 , taro height height [ ] こて 3 名の添字として , hanako height が登場しました。この配列は人の身長を集 #define TARO 0 saburo height にあるような気がします。今は太郎 , 花子 , めたもの , つまりこの配列の要素はすべて #define HANAKO 1 人の身長て、すから , この変数名は妥当て、す 三郎の 3 名の身長が関連するのだから , 三つ #define SABURO 2 として , heightCTARO ID] などとしては の変数を用意するのは自然て、す。けれども ね。太郎やら花子といった個人名は消え , し問題が太郎 , 花子 , 三郎の 3 名だけてな 身長 (height) という共通部分だけが配列変 ダメて、す。これて、は taro height とまったく 数名に反映されているわけて、す。ふむふむ。 変わらなくなってしまうからてす。これて く , 四郎 , 五郎 , 六郎・・・・・と多くの人のデ ータを処理するようになったとしたらどう 身長の平均を求める て、しよう。そのつど , siro height go 「 0 height rokuro height と変数を追加していくのて、しようか ? れはいかにもまずそうて、す。 いまの三つの変数の名前をよく見てくだ さい。すべて height を共通に持っていま す oheight とは英語て、身長のことてす ( ヘイ トてはなくハイトと読んて、ください ) 。この 名前は , 三つの変数がすべて身長を表すこ とを , プログラムを読む人にわかるように つけたものてす。 ん ? いま何かたいせつなことをいった ような気が・・・・。「三つの変数がすべて身長 を表すものてある」 ? そう , そうて、す。 つの変数 taro height, hanako height, sab uro height は , まったく関連のないバラバラ な情報を保存するものて、はありません。み List 1 : #include く stdio. h 〉 2 : #include く stdlib. h> 4 : int taro_height : 5 : i nt hanako—he i ght : 6 : int saburo_height ; 7 : int average_height; 8 : 9 : main() 10 : { 11 : #define BUFFER 256 buffer[BUFFER] ; 12 : Char puts ( ”太郎の身長を入力してください。 14 : gets(buffer) ; taro—height = atOi (buffer) ; puts ( ”花子の身長を入力してください。 18 : gets (buffer) ; 19 : hanako—height = at0i (buffer) : 20 : puts ( " 三郎の身長を入力してください。 22 : gets (buffer) ; 23 : saburo—height = atOi (buffer) : 24 : 25 : (taro—height + hanako—height + saburo—height) / 3 ; 26 : average_he i gh t printf(" 平均身長は Xd です。 }n", average_height) : 28 : } 64 C MAGAZINE 1 2 5
『品磊皿 9 SSeme 0 身長の平均を求める [ 配列編 ] List は話が逆行してしまいます。じゃあ , どう したらいいて、しようか ? 0 構垣体を使って集める いま集めようとしているふたつの情報は 名前と身長て、す。ひとりの名前と身長を近 くにまとめておきたいのて、す。ここて、は C 言 語に備わっているもうひとつの「集める」機 構を使いましよう。そう , 構造体て、す。名 前と身長を集めたひとつの構造体を作りま List 3 をご覧ください。 List 1 に比べたら すいぶん複雑になってしまいましたが , 注 意深く読んて、いただければわかると思いま 、す。身長の配列 height [ ] は姿を消し , 新 たに登場したのが , 配列 person [ ] て、す。 List 3 て、は , 「身長の集まり」を考えるのて、は なく , 「人の集まり」を考えているからて、す。 こて、いう「人」とはなんて、しよ それて、は , う ? それは「名前」と「身長」というふたっ の情報の集まりて、す。これは構造体 PERSO N として表現されています。 集たものを管理する C 言語の配列と構造体を「集める」という観 ところて、 , 「集める」か 点て、見てきました。 らには当然集めたものを管理することが必 要になります。 1 : #include く stdio. h> 2 : #include く stdlib. h> 3 : 4 : #define MAX—PERSON 3 5 : 6 : int height[MAX_PERSON] ; int average—height; 7 : 8 : 9 : main() 10 : { 11 : #define BUFFER 256 buffer[BUFFER] ; 12 : Char 13 : puts ( " 太郎の身長を入力してください。 14 : gets (buffer) ; 15 : heightC0] = atoi (buffer) ; 16 : 17 : puts ( " 花子の身長を入力してください。 18 : gets (buffer) : 19 : height[l] = atoi(buffer) ; 20 : 21 : puts ( " 三郎の身長を入力してください。 22 : gets(buffer) ; 23 : heightC2] ニ atoi (buffer) ; 24 : 25 : average—height = (heightC0] + height[l] + heightC2]) / MAX_PERSON : 26 : printf ( ”平均身長は Xd です。 *n", average_height) ; 28 : } 身長の平均を求める [ 構造体編 ] 1 : #include く stdio. h> 2 : #include く stdlib. h 〉 3 : 4 : #define MAX—PERSON 3 5 : 6 : typedef struct { 7 : Char *name : 8 : int height; 9 : } PERSON ; : 10 : 、 11 : PERSON personCMAX_PERSON] : 12 : ー 13 : : 14 : ・ 15 : ) ; int average—height; ー 17 : : 18 : ー 19 : main() ー 21 : #define BUFFER 256 buffer[BUFFER] ; : 22 : Char : 23 : int i; ー 24 : int sum; : 25 : for (i ニ 0 ; i く MAX_PERSON; i + + ) { ー 26 : printf ( " % s の身長を入力してください。 person[i]. name) ; : 27 : gets(buffer) ; ー 28 : person[i]. height = atoi (buffer) ; ー 29 : List 変名で管理する List 1 て、は各人の身長は , 変数 名前 height に格納されていました。各人の名前と身長 は , C 言語のプログラムの変数名に反映され ていたわけてす。するとどうなるてしよう か。ある人の身長を扱いたいときには , プ ログラマがその人の名前を基にプログラム を書かなければならないことになります。 プログラミングの工ッセンス 65
LlSt 3 ある人の身長を表示したいときには , プロ グラマがわざわざ , printf("%d", 名前 height) ; と書かなければならないのて、す。全員の身 長を扱いたいときには , 全員分の 名前 height を書かなくてはいけません。誰が書くのて、 しよう ? もちろんプログラマが書きます。 プログラマが直接プログラムを書く必要 があることに注意してください。コンパイ ラやコンパイルされてて、きたプログラムは , " 名前 height " という変数名の " 名前 " の部分 が人の名前を表すなんてことは知らないの 0 1 よりムっ 0 一 4- LD れ 0 ロー 8 00 00 00 っ 0 00 00 っ 0 り 0 sum = 0 ; for (i = 0 ; i く MAX_PERSON; i + + ) { sum + = person[i]. height; average_height ニ sum / MAX_PERSON ; printf(" 平均身長は Xd です。 *n", average_height) ; List 配列のような構造体 1 : typedef struct { 2 : int taro; int hanako; 3 : int saburo; 4 : int siro; 5 : 6 : int goro; int rokuro; 8 : } HEIGHT; 9 : 10 : typedef struct { int height0 ; 11 : int heightl; 12 : int height2 ; int height3; 14 : int height4; 15 : int height5; 17 : } HIDOI; 添で管理する List 2 て、は各人の身長は , 配列 height [ 人の番号 ] に格納されていました。配列は添字で管理 するのて、 , ひとりひとりに番号がつけられ ことになります。 ある特定の人の身長を扱いたいときには , やはりプログラマがその人の ( 名前て、はなく ) ムは heightCi] と書かれていれば , i 番目の す。そう , メモリは壮大な配列というわけ 番号を知っていていなくてはなりません。 て、す。 C て、は Ci] と書かずに * i と書きま 身長を扱ってくれるのて、す。これは単純な 花子さんが 1 番だとすれば , 花子さんの身長 す。このときの i はポインタと呼ばれます。 変数を使うより確かに進歩しています。 を表示するためには , ちょっと道草をします ( 誤解の恐れがある メバ名で管理する のて、この段落は C 言語初心者は読んて、はいけ printf ("%d", height [ 1 ] ) ; ません ) 。配列変数も単純変数と同じく名前 と書かなくてはなりません。 List 3 て、は , 各人の身長は , 変数 を持っています。つまり , 単に CiJ と書く 配列を使っていて助かるのは , 全員分の person [ 人の番号 ]. height のて、はなく , height [i] と書いています。 身長を扱うときて、す。先ほどのように , プ に格納されています。この例て、は構造体の これはなぜて、しよう。 ログラマがいちいち書かなくても , 繰り返 配列が使われているのて、 , 添字が登場しま 簡単なことて、す。配列はプログラム中に しの構文を使って , すが , 構造体のところに目をとめると , ひとつだけて、はなく , 複数個ある可能性が for (i 0 ; i く MAX PERSON 人を表す変数 . height あるからて、す。だからそれらを区別するた i 十十 ) { に身長が格納されていることになります。 height [i] を使った計算 めに変数名がついているわけて、す。おっと , もちろん名前は , これはテーマ「分ける」の予告編て、すね , お 楽しみに 人を表す変数 . name とすればいいからて、す。配列の要素は番号 て、すね。 て、管理されているのて、 , その番号を 0 , 1 , 2 , もっとも , C て、は文法違反て、すが単純に [ i ] 今度は , 名前さえもプログラムが扱うこ ・・と変化させてやればよく , それはプロ と書きたくなるときもあります。このとき とがて、きるようになっています。名前が " 花 グラムにもて、きることなのて、す。プログラ の i は添字て、はなく , アドレスと呼ばれま 66 C M AGAZINE 1 的 2 5
子 " て、ある人が 1 番だなんてことは , プログ ラマは知る必要がありません。人の番号を ・・と変化させ ( これは配列の性質 ) , 0 , 1 , 2 , ・ その人の名前を表す person [ i ]. name の値を " 花子 " と比較し , 一致したときの i の値を見 ればプログラムが自分て、花子の番号を得る ことがて、きるのて、す。 配列は添字て、管理し , 構造体はメンバ名 て、管理する。けれども , どちらも関連する データを集めていることには違いありませ こまて、はいいて、しよう。 C 言語の知識 ん。 の再確認て、す。 このことがよくわかっていれば , よく使 われる「構造体の配列」も容易に理解て、きま す。構造体の配列は , メンバ名て、管理する ように集めたデータを , 全体て、は添字て、管 理するようにしたもののことて、す。名前と 身長を持つ PERSON を全体て、は番号ぞ管理 するようにしました。これが間題 1 の解答 , List 3 だったわけて、す。 C を学ぶときに「構 造体」とか「構造体の配列」とかいう , 難しそ うな用語におじけづいたりせず , その言葉 の意味するところをしつかりと理解するよ 配列のような構造体 配列も構造体も「情報を集める」点て、は同 じ役割りを持っていることを学びました。 ただその集めた情報への参照方法はまった く違いました。かたや添字 , かたやメンバ 名て、す。 ちょっといたずらして , 配列のような構 造体を作ってみましよう (List 4 ) 。わかりま すか ? 構造体 HEIGHT は , メンバに各人 の名前を持ち , そのメンバのところにその 人の身長が入るわけて、す。これは使いにく い ! 構造体の特徴て、ある , 関連のある異 種のものを集めるという性質が生かされて いません。 輪をかけてひどいのがその下の構造体 HI DOI て、す。なぜひどいかはわかりますね。 れは配列を使うべきところなのて、す。関連 があるから集めようとしたのはいいけれど , C 言語の「情報を集める」機構の選択を誤った まめ を集めて配列を作りました。関連したデー 造体 PERSON を作りました。また複数の人 前と身長というふたつのデータを集めて構 , こまて、をまとめましよう。ある人の名 例て、した。 を考えましよう。 には C 言語をどのように拡張すればよし、か る」方法がないかどうか , それを実現する ■【研究】配列や構造体以外の「情報を集め そのための機構はあるでしようか ? 配列」を作ってみてください。 C 言語には 登場しました。それでは「構造体のような ・【挑戦】 List 4 に「配列のような構造体」が これを使って間題 1 を解いてみましよう。 数ではなく文字列であるような配列です。 構が用意されています。これは添字が整 ■【調査】 awk 言語には , 連想配列という機 がないかを調べましよう。 ころや , 構造体を使うべきだったところ ムを見直して , 配列を使うべきだったと ・【実践】これまであなたが書いたプログラ ださい。 N の定義がどう変わるかをよく観察してく にしましよう。そのときに構造体 PERSO グラムを , 体重の平均も求められるよう ■【観察】問題 1 の身長の平均を求めるプロ 【練習問題】 す。腕に自信のある方はどうぞ。 戦】と【研究】はけっこう骨のある問題て、 さ , それて、はいつもの練習問題て、す。【挑 た。 は添字て、管理していることも再確認しまし ました。構造体はメンバ名て、管理し , 配列 タは集めたほうが便利になることもわかり 『論、 9 0 今のプログラム : Dos 庸 0 プラウザ それなりに楽しめると思います。いろいろ の作った info プラウザはサプセットて、すが , ださっていることに気がっきました。筆者 するフルセットのⅲ fo プラウザを紹介してく 月号の特集の中て、斎藤靖氏が DOS 上て、動作 プログラムを作っている途中 , 本誌 ' 92 年 3 キストシステムⅲ fo のプラウザて、す。今回の 今月のプログラムは , GNU のハイバーテ ハノヾーテキストとノート いじってみてください うなデータ構造として設計するかになるて、 の設計のポイントは , このノードをどのよ あるヘッダに書いてあります。 inf07•ラウザ ノード間の関係はノードの始めに書いて ものて、す。 複雑な文章を読んだり書いたりするための 分けたもの ( ノード ) の間をわたり歩いて , fo. doc をご覧ください。要は , 文章を細かく 集 , または付録ディスク中のファイル dosin inf 。システムの概略は本誌 ' 92 年 3 月号の特 ノド設計案 1 何も考えすに設計すると・・ ノードは ノード名と文章を持っているのて、 , List 5 の ように作る人がいるかもしれません。構造 体 NODE 1 は名前用に文字列 name を持ち , ノードの中身を全部格納する文字列 text を持 っています。 この設計は , あまり賢くありません。な ぜなら , これて、はノードの中身を全部メモ リ上に取り込んて、しまう必要があるからて、 す。これて、は DOS のような小さなシステム ては , すぐにメモリ不足になってしまいま す。 プログラミングの工ッセンス 67