2019/02/06
sponsored link
for文と配列
for文の使い方はなんとなく掴めましたでしょうか?配列とfor文を組み合わせると非常に効果的な使い方ができます。というよりむしろ、for文というのは配列を回す為にあると言っても過言ではありません。
この非常に有用な「配列をfor文で回す」という感覚を身につける為に、前々回に配列を使って作ったScoresクラスを改造したいと思います。
Scoresクラスはこんなのでした。
Scores.java
public class Scores{ public static void main(String[] args){ int[] scores = new int[]{80,65,70,95}; System.out.println("Aさんの点数:" + scores[0] + "点"); System.out.println("Bさんの点数:" + scores[1] + "点"); System.out.println("Cさんの点数:" + scores[2] + "点"); System.out.println("Dさんの点数:" + scores[3] + "点"); } }
「System.out.println(“○さんの点数:” + scores[○] + “点”);」というようによく似た処理が4回繰り返されています。ここをfor文を使ってスマートに書き換えましょう。
前回の2のn乗を計算するプログラムでは「answer = answer * 2;」を繰り返すだけだったのですが、この場合、繰り返しとは言うものの一回一回微妙に違いますよね?
名前も違うし、scores[ ]の連番も違います。繰り返しの1回目はscores[0]を、2回目はscores[1]を・・、と配列の連番を進めながら繰り返すようにします。
for文で回す?
まずは名前の方もfor文で回す為に、配列にします。どうせならAさんBさんじゃなくて、青木さんと飯田さんと上田さんと江藤さんにしておきます。別に誰でもいいんですが。。
Scores.java
public class Scores{ public static void main(String[] args){ String[] names = new String[]{"青木","飯田","上田","江藤"}; int[] scores = new int[]{80,65,70,95}; System.out.println(names[0] + "さんの点数:" + scores[0] + "点"); System.out.println(names[1] + "さんの点数:" + scores[1] + "点"); System.out.println(names[2] + "さんの点数:" + scores[2] + "点"); System.out.println(names[3] + "さんの点数:" + scores[3] + "点"); } }
さあ、これをfor文で書き換えると、
Scores.java
public class Scores{ public static void main(String[] args){ String[] names = new String[]{"青木","飯田","上田","江藤"}; int[] scores = new int[]{80,65,70,95}; for(int i=0; i< names.length; i++){ System.out.println(names[i] + "さんの点数:" + scores[i] + "点"); } } }
こうなります。
for文の( )の中の初期設定パートで宣言・初期化した「i」を実行文の中でも使うことで、ブロック内実行の1回目は配列の通し番号0番、2回目は通し番号1番・・、と言う風に配列を回しながら繰返しを実行できるわけです。
それとfor文の( )の中の実行条件のパートが「i < names.length」こんなことになってますが、
配列名.length
で、その配列の要素数を返します(「返す」というのは「評価する」と同じことで、その値に置き換わるというようなニュアンスです)。
つまり、
names.length
は、配列namesの要素数を返すので、「4」に置き換わります。そんなややこしい書き方しなくても「4」と書く方が早いようにも思いますが、配列を回す時は絶対「.length」を使うようにした方がいいです。
これで配列namesと配列scoresを通し番号0番から3番まで一つづつ進めながら4回繰り返して実行するfor文になりました。(「names.length」と「scores.length」が両方4なので動作自体はこれで問題ないですが、例としてはあまりよくなかったです申し訳ない・・。)
この配列を回す書き方を見ると、for文の繰り返しの基本形が、
for(int i=1; i<=5; i++)
ではなく、
for(int i=0; i<5; i++)
にするのかよく分かるのではないでしょうか?iを1から始めてしまうと、配列の通し番号も1から始めてしまうことになりますからね。
for文の入れ子とスコープ
最後にちょっとした応用問題。
for文の中にfor文が入っているやつです。配列は使ってないので今回の内容とは少しズレた問題かも知れませんが、ここまでの入門講座の内容をちゃんと理解できていたら、絶対読めるはずです。
ForInFor.java
public class ForInFor{ public static void main(String[] args){ for(int i=1; i<=9; i++){ String a = ""; for(int j=1; j<=9; j++){ a += i * j + " "; } System.out.println(a); } } }
さてこのプログラムを実行すると、何が出力されるでしょうか??ポイントは入れ子になっているfor文のブロック(どこを繰り返すのか?)をよく見ることと、ころころ変わっていく「i」と「j」の値を常に追いかけて把握しておくことです。「i」が1、「j」が1とかメモしながら読んだらよく分かると思います。あと、変数aはStringですのでそこのところ注意して読んで下さい。
「a += i * j + ” “」は、
「a = a + (i * j + ” “)」の省略形ですよ。「i * j」が数値として計算されてから文字列に変換されて連結されます。ちなみにi*jの後に足している「” “」これはスペースです。
答えが分かったらぜひ、実行して答え合わせをしてみてください。
このプログラムを読めた人は、次のを見て下さい。
ForInFor.java
public class ForInFor{
public static void main(String[] args){
String a = "";
for(int i=1; i<=9; i++){
for(int j=1; j<=9; j++){
a += i * j + " ";
}
System.out.println(a);
}
}
}
「String a = "";」の位置が、for文のブロックの中から外に変わっただけなのですが、これだと思ったように出力されません。
このプログラムの実行結果を見れば、for文のブロック内で宣言された変数と、ブロックの外で宣言された変数の動きの違いがよく分かると思います。
for文のブロック内で宣言された変数は、そのブロック内でしか存在できません。なので一度そのブロックを抜けると消えてしまいます。
for文の繰り返しでもう一度そのブロック内が実行されたら、宣言&初期化からやり直しになるので、前周の値は持ち越しません。逆にブロックの外側で宣言された変数はそのブロックを抜けてもまだ値を保持していますので、こんなこと(上記の下側のプログラムの実行結果)になるんです。
この、変数を宣言する場所によって処理内容が変わってしまう仕組みはfor文に限ったことではありません。変数は、宣言された場所より内側のブロック内では生きていますが、宣言されたブロックの外側では存在できません。
変数の有効範囲(生きている範囲)をスコープと言います。宣言する場所によってその変数のスコープが決まりますので、自分で思った通りに変数を使おうと思ったらどこで宣言したらいいかをよく考えないといけません。
なんか難しい感じですが、やっているうちに分かってきますので宣言する場所を意識することだけは忘れないようにして下さい。
次はメソッドについてやります。メソッドは覚えることも多くてややこしいですが、その分メソッドを使いこなせればいろんなことができるようになりますので頑張りましょう。
今だけ→転職できなければ全額返金の「エンジニア転職保証コース」
絶対エンジニアになる!→テックエキスパート
フリーランスエンジニアの収入例を見てみる→レバテックフリーランス
コメント
参考にさせてもらっているのですが、
2つ目のForInForについての質問なのですが
一行目が1 2 3・・・
となるのは理解できるのですが
二行目が1 2 3・・・
となる理由がわかりません
なぜなのですか?
by 超初心者 2016/12/12 00:56
>超初心者さん
よく読んで、スコープについて理解すれば分かると思います。
by Nobuo@管理人 2016/12/12 09:08
ありがとうございます理解できました
変数の値が残るから
1 2 3・・・9 に付け足すということですね!
ありがとうございます
by 超初心者 2016/12/16 23:27
学習に利用させてもらっています。
疑問に感じた点があるのですが、最後の項の応用問題で変数の宣言と初期化の行を移動させると実行結果がおかしくなりましたが、
これはスコープが変化したからではなく、外側のfor文のブロックに変数aを空で上書きする代入がなくなったせいではないのですか?
試しにa = “”;という行を外側のfor分のブロックに追加すると正しく表示されました。
by ユーザー 2017/03/13 18:16
私も上の「ユーザー」さんに同意見です
スコープの変化、というのとは関係がないような気がします
by 新人 2018/11/13 19:14
>外側のfor文のブロックに変数aを空で上書きする代入がなくなったせいではないのですか?
あれは変数の値(文字)を上書きしているわけではなく、その都度新しい変数を宣言しています。もちろんおっしゃるやり方でも同じ動きになります。結果は同じですが変数がどこで宣言されてどこで書き換えれれて、どこで無効化されるのか双方について考えればより深くスコープについて理解できるかと思います。
by Nobuo@管理人 2018/11/13 22:40
1つ目のForInFor.javaを使って、
「最初のfor文の外で、println等で変数aを使ってみる」
とかならスコープについて分かりやすいのかなと思いました。
ループの中で宣言したaは、ループ抜けた後は使用できない事が分かると思います。
by ひろし 2019/08/20 20:55
応用問題、ぜんっぜんわからん(笑)
by 匿名 2021/12/28 18:26