くりかえし命令と配列変数

プログラマーからひとこと

この章では、FOR~NEXT文について学びます。

FOR~NEXT文は、それがあるだけでプログラムリストを読むのがぐっと難しくなるというおそろしい命令です。
プログラムした人は意味があって使っているしその意味もわかっているのですが、そのリストを読むほうはたまったものじゃありません。

それでも使うのはなぜかといえば、とてもベンリだからです。
これがあるだけでプログラムの手間はものすごく少なくなります。
あんがい悪くないですね。プラマイでいえばプラスじゃないでしょうか。

さらにこの章では、DIM命令、いわゆる配列変数についても学びます。
配列変数というものはパッと頭で理解するのがなかなかむずかしく、プログラムをおぼえはじめた人はみんなひっかかるポイントです。
正直わたしも何度か「こんなものなけりゃいいのに」と思いました。
「なんの役にたつんだ?」とも思いました。
「なくていいじゃん」とも思いました。
でも、そういうものが意外とけっこう役にたつということは、ここまでこの講座を読んできた人なら知っているはずです。
くやしいことにこれが本当に役にたつのです。

この章では、できるだけじっくりと配列変数のことをおぼえていきます。
あんまりじっくりすぎて途中でめんどくさくなるかもしれませんが、カベをのりこえるためだと思ってじっくり読んでみてください。

FOR~NEXT命令

インテリ
「くりかえし命令」と言ってどんな命令を想像するかな?

ワンパク
GOTOで作る無限ループなんか、「くりかえし」になるんじゃねえか?
0001#. @MUGEN
0002#. PRINT”クリカエシ”
0003#. GOTO @MUGEN

インテリ
たしかに何度もくりかえしているね。じゃあ、無限ループじゃなく10回くり返したら途中でループをやめる、とするとどうすればいいかな?

ワンパク
ムリじゃねえの?

神崎
ず、ずいぶんアキラメが早いね。ええと、変数を使って、ループのたびに変数の中身を変えて、IF~THEN文で変数によって別のラベルまで……

ワンパク
ウォオー! 話を聞いてるだけでめんどクセエうえに、言ってるイミもよくわかんねえぜ!

インテリ
なかなか難しいよね。そこで役に立つのがFORフォーNEXTネクスト命令なんだ。
まずこのプログラムを見てごらん。

0001#. FOR A=1 TO 10
0002#. PRINT”クリカエシ”
0003#. NEXT
ワンパク
ほとんどゼンブとっかえてるじゃねえか! とりあえずRUNしてみるか。

画面
神崎
ちゃんとクリカエシを10回書いたところで終わったね。

ワンパク
3行のプログラムにしちゃナカナカやるじゃねえか。どうやらクワシク話をきかなきゃならねェようだな!

インテリ
英語で「FORフォー」は「~から」、「TOトゥ」は「~まで」という意味になるね。
FOR A=1 TO 10は「A=1から10まで」と読んでもいいだろう。
そして「NEXTネクスト」は「次にいく」というところかな。「次のくりかえしを始める」って考えればこれはわかるよね。

ワンパク
NEXTの方はだいたいワカッたぜ。しかしFORの方、「A=1から10まで」ってのはイミわからねェな。フツウ「から10まで」じゃねえのか?

神崎
あれ? たしかBASICでイコール記号を使うのは変数のときだけだから……?

インテリ
よくおぼえていたね。そう、このは変数なんだ。

ワンパク
なんでココで変数が出てくんだ……?
話が見えてこねェぞ! ワカるようにセツメイしやがれ!

インテリ
ジッサイにプログラムで見てもらうのが早いかな? ちょっと書きかえてみよう。

0001#. FOR A=1 TO 10
0002#. PRINT”クリカエシ”;A
0003#. NEXT
インテリ
これをRUNするとこうなるね。

画面
神崎
1から10まで、くりかえすたびに変数がふえている、のかな?

インテリ
そう考えてマチガイじゃないね。これがFORTOのむずかしいトコロなんだけど、「A=1から始めて、変数10になるまで、変数を1ふやしながらくりかえす」というのがFOR A=1 TO 10の正しいイミなんだ。

ワンパク
ズイブンいろいろなコトがはぶいて書いてあんだな、FORTO文にはよォ! わかりづれェ!

インテリ
そのまま書いても長い命令になって、打ちづらいだろうしね。これくらいがちょうどいいんじゃないかな。

ワンパク
おっと待てよ、オレのギモンがカイケツしてないままだったぜ! なんで変数がかならず出てくんだ? はじめの方で使ったこのプログラムだけは、変数いらねえじゃねえか!
0001#. FOR A=1 TO 10
0002#. PRINT”クリカエシ”
0003#. NEXT

インテリ
それはもっともかもしれないね。FOR~NEXT文では変数を使うことの方がずっと多いから……としか言えないかな。じっさい、変数を使わないループなら変数のことはムシすればいいんだし、別にモンダイはないだろう?

ワンパク
ウムム……タシカに。

神崎
うっかり別のところで変数を使ってると、FOR命令で変数のナカミが変わっちゃうから、それだけは気をつけないとね。

ワンパク
なんだかマルメこまれた気がしねェでもないが……

インテリ
次はこのFOR~NEXT文と相性のいい、DIM命令について説明するよ!


配列変数

インテリ
まずサイショに、「配列変数はいれつへんすう」について知っておこうか。

ワンパク
イヤなヨカンだな……。漢字が4コ以上つづいたコトバはムズカシいモンと決まってるぜ!

インテリ
まあまあ。いままでにおぼえた変数とたいした違いはないんだよ。

神崎
ホントに?

インテリ
使いかたがトクシュだからとまどうかもしれないけど、変数と同じように使うものだってコトさえ忘れなければ、けっこうカンタンなはずさ。
まず、いつもの変数を考えてみようか。
0001#. APPLE=56
0002#. PRINT”リンコ゛”;APPLE;”コ”
おぼえてるかな? サンプルプログラム1でこんな使いかたをしたよね。

ワンパク
オボエてなくたって、リストを読めばイミはわかるぜ。えーと、"RUN"!
リンコ゛56コ
OK
そうそう、変数APPLEのナカミ、56PRINTするんだゼ!

神崎
(もうわすれてたのか……)

インテリ
これを配列変数に変えてみよう。

0001#. CLEAR:DIM APPLE(1)
0002#. APPLE(0)=56
0003#. PRINT”リンコ゛”;APPLE(0);”コ”
神崎
1行目からさっそく新しい命令が2つ……

インテリ
ああ、そこは今は気にしないでいいトコロだから、2行目から読むようにしてね。

ワンパク
ン? じゃあ変わったのは、変数のウシロに(0)がついただけってコトか? それともAPPLE(0)てのをPRINTすると56とはチガってくんのか?

インテリ
いいや、APPLE(0)のナカミは56でマチガイないよ。

リンコ゛56コ
OK
ワンパク
じゃあナマエ以外ゼンブ同じじゃねェかよ!

インテリ
変数と同じだって言ったじゃないか。こういうものなんだよ。

神崎
うーん……これはワンパク君じゃなくても、フツウの変数でいいじゃないかって思うな。

インテリ
よし、その気持ちをわすれずに、配列変数の使い方その2にいってみよう!
0001#. CLEAR:DIM APPLE(2)
0002#. APPLE(0)=56
0003#. APPLE(1)=32
0004#. PRINT”リンコ゛”;APPLE(0);”コ”
0005#. PRINT”リンコ゛”;APPLE(1);”コ”
やっぱり1行目はムシして読んでね!

ワンパク
テメー……まさか、ソレもこのフツウの変数と同じだって言うんじゃねェだろうな……
0001#. APPLE0=56
0002#. APPLE1=32
0003#. PRINT”リンコ゛”;APPLE0;”コ”
0004#. PRINT”リンコ゛”;APPLE1;”コ”

インテリ
合ってるよワンパク君! ちゃんとわかってるじゃないか。

ワンパク
ウオォー! ガキあつかいもタイガイにしやがれー! 変数のナマエが違うだけじゃねえか!!

インテリ
そうそう、名前くらいのちがいだって思えばいいんだよ。教えやすくてたすかるなあ。

ワンパク
チッ、ここまではテメーのオモワクどおりってワケか。だが、そろそろ配列変数だけができるワザを言わねえと、オレもダマっちゃいないぜ!

インテリ
配列変数ならではって言うと……こういうのはどうかな?
0001#. CLEAR:DIM APPLE(32)
0002#. APPLE(1)=56
0003#. APPLE(2)=32
0004#. APPLE(3)=71
#####.   :
0032#. APPLE(31)=45
0033#. PRINT”1ニチメ リンコ゛”;APPLE(1);”コ”
0034#. PRINT”2ニチメ リンコ゛”;APPLE(2);”コ”
0035#. PRINT”3ニチメ リンコ゛”;APPLE(3);”コ”
#####.   :
0063#. PRINT”31ニチメ リンコ゛”;APPLE(31);”コ”
あんまり長いから途中ははぶいたけど、31日分のリンゴを数えるプログラムなのはわかるよね。

神崎
つまり……カッコの中の数字があるからわかりやすいって感じ……?

ワンパク
フザケんじゃねエー! だからソレ、こう書いても同じじゃねえか!
0001#. APPLE1=56
0002#. APPLE2=32
0003#. APPLE3=71
#####.   :
0031#. APPLE31=45
0032#. PRINT”1ニチメ リンコ゛”;APPLE1;”コ”
0033#. PRINT”2ニチメ リンコ゛”;APPLE2;”コ”
0034#. PRINT”3ニチメ リンコ゛”;APPLE3;”コ”
#####.   :
0062#. PRINT”31ニチメ リンコ゛”;APPLE31;”コ”

インテリ
そうだよワンパク君! よくここまでガマンしたね! ここまでは本当に変数といっしょなんだ。これから、配列変数だけの使い方に変えていくよ。

ワンパク
お、おう……? ガマンしたオボエはあんまりねェが、とにかくのぞむトコロだぜ!

0001#. CLEAR:DIM APPLE(32)
0002#. APPLE(1)=56
0003#. APPLE(2)=32
0004#. APPLE(3)=71
#####.   :
0032#. APPLE(31)=45
0033#. FOR DAY=1 TO 31
0034#. PRINT DAY;”ニチメ リンコ゛”;APPLE(DAY);”コ”
0035#. NEXT
ワンパク
!!

インテリ
わかってきたかな。33行目からはおぼえたばかりのFOR~NEXTを使っているね。

神崎
変数DAYから順にふやしながら、31までくりかえすんだよね。

ワンパク
DAYのトキは、1ニチメ リンコ゛”;APPLE(1);”コ”ってコトになる……そしてくりかえしてDAYになったら、2ニチメ リンコ゛”;APPLE(2);”コ”に……!
これが31まで自動でくりかえされるってワケか!

インテリ
これは配列変数じゃないとできないだろう。こういう使い方もできるね。

0033#. INPUT”ナンニチメヲ シラヘ゛マスカ”;DAY
0034#. PRINT DAY;”ニチメ リンコ゛”;APPLE(DAY);”コ”
神崎
INPUTで数字を変数DAYに入れて、34行目で配列変数APPLE(DAY)PRINTするわけだね。
うーん、これを普通の変数でやろうとすると、変数名を入力させて……いやいやそれもダメか……

インテリ
みんなもわかったみたいだね。つまり配列変数は「変数名に変数を使える」ベンリな変数なんだ。

ワンパク
ヘンスウメイをヘンスウにツカえるヘンスウ……

インテリ
ごめんごめん、「変数」というコトバばっかりでわかりづらかったね。こういうふうに、口で説明するのがムズカシいのが配列変数なんだ。だから今回はできるだけジッセン的に説明したよ。

ワンパク
ヘッ、なかなかヤルじゃねえかクソッタレー!

神崎
それ、ほめてるの?


DIM命令、CLEAR命令

インテリ
配列変数についてわかってきたところで、DIM命令もおぼえておこう。

神崎
配列変数を使うときはいつも1行目に書いてあったね。
0001#. CLEAR:DIM APPLE(32)

インテリ
DIM APPLE(32)というのは、これから配列変数をAPPLE(0)APPLE(31)まで用意する、という命令だよ。

神崎
いちいち前もって数を決めておかないといけないの?

インテリ
そう。このことを「配列宣言はいれつせんげん」と言うんだけど、かならず配列宣言するのはちょっとめんどうではあるね。

ワンパク
メンドウなコトなんざやってられるか! イキナリ書けばいいじゃねえか!
0001#. APPLE(31)=1

Subscript out of range (1)
OK
インテリ
というエラーが出るんだよね。

ワンパク
のヤロー! こうすりゃいいんだろ! 負けたキブンだぜ!
0001#. DIM APPLE(32)
0002#. APPLE(31)=1

OK
神崎
使うのはAPPLE(31)までなのに、DIM APPLE(32)と書かなきゃいけないのがフシギなんだけど……。

インテリ
そのDIMだと、用意されるのはAPPLE(0)APPLE(31)だからね。数を数えてみるとわかるよ。

図
ワンパク
……タシカに、32コあるな。しかし言われねえとピンとこねえハナシだぜ!

インテリ
LOCATE命令でもそうだったけど、ゼロから数えるから、頭で考える数より1つズレちゃうんだね。これは気をつけないといけないかな。

神崎
いっそありえないくらい大きく宣言したら?

インテリ
ところが配列のこの数字は、「合計で」32768個までと決まってるんだ。たとえばDIM APPLE(32768)と宣言したあとだと、DIM ORANGE(1)くらいでもエラーになってしまうんだよ。

ワンパク
ヤッカイだな、まったく! まあホドホドに使うくらいならダイジョウブなんだろ?
0001#. DIM APPLE(300)
0002#. APPLE(31)=1

RUN
Duplicate definition (1, DIM)
OK
ワンパク
!? な、ナンだ? 300個テイドでエラーは出ねェハズだぞ!

インテリ
そう感じるのもモットモだね。でもこれは配列変数の「二重定義」になっちゃうんだ。

ワンパク
???

インテリ
たとえば、こう書くのはよくないって、なんとなく思うんじゃないかな?
0001#. DIM APPLE(32)
0002#. APPLE(31)=1
0003#. DIM APPLE(300)

神崎
まあ……いちどナカミをに決めたAPPLE(31)が3行目でどうなっちゃうのか、不安になるね。

インテリ
だから、プチコンでは同じ配列変数の名前で2度DIMするとエラーになるようになってるんだ。
そこでさっきのワンパク君だけど……

ワンパク
オレは最初に……
0001#. DIM APPLE(32)
って書いてRUNして、次に
0001#. DIM APPLE(300)
にしてRUNしたが……、まさか、ソレか?

インテリ
プログラムが終わっても変数の情報は消えないから、それでもエラーになっちゃうんだ。

ワンパク
そんなコト言われてもどうすりゃいいってんだ! これハマリじゃねえか!

インテリ
だいじょうぶ。変数の情報が残ってるのがモンダイなんだから、これをリセットすればいいんだ。
0001#. CLEAR
0002#. DIM APPLE(300)

神崎
インテリ君がかならず1行目に書いていた、CLEARクリア命令だね!

インテリ
日本語では「かたづける」と言えばいいかな。こう書くだけで、変数はぜんぶリセットされるんだ。

ワンパク
めんどクセェことをはぶくとだ、プログラムにDIM命令を書くトキは、かならず前にCLEARを書いときゃいいってことだな?

神崎
ワンパク君のまとめ方はランボウだけど、今回はボクもサンセイかな。

インテリ
そうそう、CLEARを使うならプログラムのはじめの方がオススメだってことも言っておかないとね。あんまり途中で使うと、ダイジな変数もいっしょにクリアされちゃうかもしれないよ。

ワンパク
チッ、なにかとメンドウだぜ!
しかしまあワリと今回はジュウジツしたな。デカいヤマを乗りこえたって感じだゼ!

インテリ
あ、でもその前にもう1つ、おぼえておきたいコトが……

ワンパク
マジでか。


DATA命令・READ命令

インテリ
配列変数の説明に使ったこのプログラムだけど……
0001#. CLEAR:DIM APPLE(32)
0002#. APPLE(1)=56
0003#. APPLE(2)=32
0004#. APPLE(3)=71
#####.   :
0032#. APPLE(31)=45
0033#. FOR DAY=1 TO 31
0034#. PRINT DAY;”ニチメ リンコ゛”;APPLE(DAY);”コ”
0035#. NEXT
いま見直しても、2~32行目がずいぶん長いって思うよね。

神崎
でもコロンで2行や3行をまとめても、まだけっこう長いしなあ。

インテリ
こういうデータをまとめたいときに役にたつのがDATAデータREADリードのコンビなのさ。
まずはDATAの使い方を先に見てみよう!
0002#. DATA 56,32,71,40,64,73,61,10,45,80
0003#. DATA 25,71,63,54,98,23,14,66,58,47
0004#. DATA 94,36,31,26,45,71,24,76,66,58,46

神崎
ホントにデータって感じだね。

ワンパク
やってるコトは「」で区切りながらリンゴの数を順に並べてるだけ……みたいだな。

神崎
リンゴの数の種類は全部で31。4行目だけ1つ飛び出してるけど、これはいいの?

インテリ
DATA文はかなり自由だから、1行に何個データがあってもいいんだ。2行目では10個、3行目も10個、4行目では11個。プログラムしていて見やすければそれが一番だと思うよ。

ワンパク
だがイマんとこ、ただ数をズラッと書いてるだけじゃねえか! DATAの使いミチにはほど遠いゼ!

インテリ
そこがポイントだね。DATA命令はそのままだと何のイミもないんだ。そこでREAD命令の出番になるよ。

神崎
READリード、日本語で言えば「読む」だね。

インテリ
いちばんカンタンなREAD命令の使いかたはこうかな。
0005#. READ APPLE
さっきのDATA文の後にこう書くと、最初のデータ56が変数APPLEに入るよ!

ワンパク
31コあるデータなのに、入る数字は最初の1つだけかよ。どういうこった!

インテリ
いくつもデータを読み込むなら、READのあとに変数を並べて書くね。今回使うのは配列変数だから……
0005#. READ APPLE(1),APPLE(2),APPLE(3)
0006#. READ APPLE(4),APPLE(5),APPLE(6)
#####.   :
こんなふうに10行ほど続けると全部のデータが読み込めるよ。

ワンパク
ゼンゼン長ったらしいゼ、まだまだ使えたもんじゃねェな!

神崎
あれ、待ってよ。配列変数っていうことは……?

インテリ
そう、気がついたようだね。今のREAD文を短くまとめると、こうなるんだ。
0005#. FOR DAY=1 TO 31
0006#. READ APPLE(DAY)
0007#. NEXT

ワンパク
ココでもまたFOR~NEXTか……。オボエたての命令だが、ずいぶんアチコチで使うんだな。

インテリ
特に配列変数やREADにはベンリな命令だからね。31行あった文が6行におさまったのはFOR~NEXT文のおかげだね。

神崎
いままでのプログラムリストを全部書いてみると、こうなるね。
0001#. CLEAR:DIM APPLE(32)
0002#. DATA 56,32,71,40,64,73,61,10,45,80
0003#. DATA 25,71,63,54,98,23,14,66,58,47
0004#. DATA 94,36,31,26,45,71,24,76,66,58,46
0005#. FOR DAY=1 TO 31
0006#. READ APPLE(DAY)
0007#. NEXT
0008#. FOR DAY=1 TO 31
0009#. PRINT DAY;”ニチメ リンコ゛”;APPLE(DAY);”コ”
0010#. NEXT

ワンパク
ウオォ、いつのまにか10行まで短くなってたのか!

インテリ
5~10行目はかぶってるところがあるから、まとめちゃおう。
0001#. CLEAR:DIM APPLE(32)
0002#. FOR DAY=1 TO 31
0003#. READ APPLE(DAY)
0004#. PRINT DAY;”ニチメ リンコ゛”;APPLE(DAY);”コ”
0005#. NEXT
0006#. DATA 56,32,71,40,64,73,61,10,45,80
0007#. DATA 25,71,63,54,98,23,14,66,58,47
0008#. DATA 94,36,31,26,45,71,24,76,66,58,46
こんなふうにDATAはプログラムリストのどこに置いてもいいんだよ。READすると自動的にリストの最初にあるデータをさがして順番に読みこむからね。

ワンパク
オイオイ、8行におさまっちまったぞ!

インテリ
やっていることは同じでも、はじめのころの63行あったプログラムとくらべると、かなりコンパクトになったろう。

博士
あんまり短くしすぎると書いてる自分もこんがらがるので考えものじゃが、目で追えるていどならセイリしてまとめるのは良いことじゃな。こういうのもプログラムのひとつのダイゴミじゃ。

神崎
あ、ハカセ。いつから……?

ワンパク
ジジイの言うこともワカる気がするゼ。ケッキョク配列変数もFOR~NEXTもナシで書いた方がワカりやすさじゃイチバンなんじゃねえか? とか思ったモンだが……

インテリ
今までの話をだいなしにしそうなハツゲンだね。

ワンパク
しかし、BASICの命令をクシして、めんどクセェことをゼンブはぶいたのはロックだゼ! オレのパンクスピリットにもウッタエるモノがあったな!

博士
ワカッてくれたようでうれしいのう。そんなパンクキッズのキミのために、次のサンプルプログラムはサウンドをフィーチャーしてみたぞい。

ワンパク
やってやろうじゃねェかコノヤロー! さっさと見せやがれェ!

神崎
(なんだろうこのテンカイ……)


今回のまとめ

FOR~NEXT命令
FOR (変数)(最初の数) TO (終わる数)
NEXT
最初の数から始めて、変数を1ずつふやしながら、終わる数までFORNEXTまでをくり返します。
配列変数
A((数字)という形の変数が配列変数です。たとえばA(1)A(2)はまったく別のものとして、違う数が中に入ります。
DIM命令
DIM (変数)(数)
配列変数に使う数を決める「配列宣言」をします。たとえばDIM A(10)ならA(0)A(9)まで10個の配列変数が用意されます。
CLEAR命令
CLEAR
変数をリセットします。DIM命令の「二重定義」をしないために、プログラムのはじめのうちに使っておくのがいいでしょう。
READ命令・DATA命令
DATA (データ)(データ)……
変数に入れるデータ(数字など)を「」でくぎって連続で書くことができます。
READ (変数)
変数にDATA文で書いたデータを読みこみます。データはプログラムの中で先にあるものから順に呼びだされます。