- ベストアンサー
C言語基本 2次元配列(for文:条件値について)
はじめまして。C言語の超入門者です。現在、基礎的な事を独学中なのですが、以下(10)(11)の部分の解釈で行き詰まってしまいました。 (1)#include <stdio.h> (2) (3)main() (4){ (5)int x,y; (6)int a[2][4]={ (7){1,2,3,4}, (8){5,6,7,8} (9)}; (10)for(x=0;x<2;x++){ (11)for(y=0;y<4;y++) (12)printf("a[%d][%d]=%d ",x,y,a[x][y]); (13)printf("\n"); (14)} (15)} (6)は、int a[2][4]・・・y方向に2列、x方向に4列 ↑■■■■■■■ ↑■5■6■7■8■ Y ■■■■■■■ 方■1■2■3■4■ 向■■■■■■■ X方向→→ なので (10)行目での条件を x<4 (11)行目での条件を y<2 とすると結果が正しく出ず、 (10)行目での条件を x<2 (11)行目での条件を y<4 と値を逆転させると正しく表示されるのは何故でしょうか? (6)int a[2][4]は、x方向は2列 , y方向は4列 と逆に考えたほうが正解なのでしょうか? 超初心者でも分かる簡潔かつ明快な回答を宜しくお願い致します。
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
どうもかゆいところに手が届いてなさそうなので補足します。 > (10)行目での条件を x<4 > (11)行目での条件を y<2 > とすると結果が正しく出ず、 > > (10)行目での条件を x<2 > (11)行目での条件を y<4 > と値を逆転させると正しく表示されるのは何故でしょうか? あなたの疑問に対する明快な答えは、 「あなたの頭の中の (x, y) とプログラムの (x, y) が食い違って(入れ替わって)いるためです。」 つまり、あなたがyだと思っているのはプログラム上のxに当たり、xだと思っているのが yに当たるるので、値の範囲もxが 0,1 、yは 0,1,2,3 で正常に表示されるのです。 「xは横方向、yは縦方向」 にこだわるなら、ANo.5のように、プログラムのxとyを入れ替え、頭の中にある (x, y) に合わせるのが最も良い解決法でしょう。 もちろん、a[y][x]というアクセスの仕方になります。 無理やり int a[4][2] = { { 1, 5 }, { 2, 6 }, { 3, 7 }, { 4, 8 } }; for ( y = 0 ; y < 2 ; y++ ){ for ( x = 0 ; x < 4 ; x++ ) printf( "a[%d][%d]=%d ", x, y, a[x][y] ); printf( "\n" ); } とできなくはないですが、明らかに配列への格納の順番が不自然ですよね? ですのでC言語の世界では、 a[y][x] とするのが普通だと覚えて下さい。 なお、蛇足ながら頭にイメージするのは ↑■■■■■■■ ↑■5■6■7■8■ Y ■■■■■■■ 方■1■2■3■4■ 向■■■■■■■ X方向→→ ではなく、 X方向→→ Y ■■■■■■■ 方■1■2■3■4■ 向■■■■■■■ ↓■5■6■7■8■ ↓■■■■■■■ とした方がいいでしょうね。 Y方向は改行によって1進むので。
その他の回答 (5)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★回答者 No.2 です。 ちょっと質問の解釈を間違いました。 >↑■■■■■■■ >↑■5■6■7■8■ >Y ■■■■■■■ >方■1■2■3■4■ >向■■■■■■■ > X方向→→ を >int a[2][4]={ > { 1, 2, 3, 4 }, > { 5, 6, 7, 8 }, >}; というデータにして [1][2][3][4] [5][6][7][8] と表示したいのなら回答者 No.3、No.4 さんので正しいです。 >for ( x = 0 ; x < 2 ; x++ ){ > for ( y = 0 ; y < 4 ; y++ ) > printf( "a[%d][%d]=%d ", x, y, a[x][y] ); > printf( "\n" ); >} ↑ これは変数の x、y の意味が逆ですね。だから ↓ for ( y = 0 ; y < 2 ; y++ ){ for ( x = 0 ; x < 4 ; x++ ) printf( "a[%d][%d]=%d ", y, x, a[y][x] ); printf( "\n" ); } と x、y の変数名を入れ替えれば良さそうです。つまり意味を。 >と値を逆転させると正しく表示されるのは何故でしょうか? ↑ 値を逆転させると正しく表示されますか? 変数名を入れ替えれば上手くいきますけど。 内側のループに x(横方向)を 外側のループに y(縦方向)にします。 ※上手く説明できなくて済みませんでした。 ・以上。
お礼
super-dogさん、Oh-Orangeさん、SRitchieさん、ymmasayanさん、早速のご回答有難うございました。 皆様のご解説を見て、60分考えてみました。 しかし、(10)行目 x<□ および (11)行目 y<□ に入る値がどうしても (6)int a[2][4]={ からx<4 および (11)行目 y<2 ではないかと思ってしまうのです。 また、 ymmasayanさんのご説明で >内側のyのループが早く回り(4回)、外側のxのループが2回回ります。 とありましたが、xとyに対する処理は同時に行われている訳ではないのですか? Oh-Orangeさんから BASIC 出身者ですか? と質問されましたが、 私はプログラムのプの字をかじり始めたばかりの者です。 >値を逆転させると正しく表示されますか? >変数名を入れ替えれば上手くいきますけど。 ともご指摘がありましたが、 ------------------------------------------- 私的な『正しく表示される』の意味 (10)for(x=0;x<2;x++){ (11)for(y=0;y<4;y++) でコンパイル後 a[0][0]=1 a[0][1]=2 a[0][2]=3 a[0][3]=4 a[1][0]=5 a[1][1]=6 a[1][2]=7 a[1][3]=8 ------------------------------------------- 私的な『結果が正しく出ず』の意味 (10)for(x=0;x<4;x++){ (11)for(y=0;y<2;y++) でコンパイル後 a[0][0]=1 a[0][1]=2 a[1][0]=5 a[1][1]=6 a[2][0]=6618672 a[2][1]=4226262 a[3][2]=6693692 a[3][1]=0 ------------------------------------------- となることから、冒頭質問のように書きました。 本当に超初心者なので、皆様のご説明を理解できず申し訳ありません。
- ymmasayan
- ベストアンサー率30% (2593/8599)
↑■■■■■■■ ↑■5■6■7■8■ Y ■■■■■■■ 方■1■2■3■4■ 向■■■■■■■ X方向→→ ではなくて ↑■■■■■■■ ↑■5■6■7■8■ 前■■■■■■■ 変■1■2■3■4■ 数■■■■■■■ 後変数→→ です。 (10)for(x=0;x<2;x++){ (11)for(y=0;y<4;y++) (12)printf("a[%d][%d]=%d ",x,y,a[x][y]); から、内側のyのループが早く回り(4回)、外側のxのループが2回回ります。 したがって 1234 5678 と出力されます。 (10)と(11)をひっくり返すことはできません。
お礼
ご回答有難うございました。 失礼ですが、ANo.6 fatbowlerさんの回答下部に新たな質問を致しておりますので、ご指摘の程宜しくお願い致します。
- SRitchie
- ベストアンサー率21% (103/470)
No.1の方の回答で正解ですが、 こう書いた方が分かりやすいかな? for ( y = 0 ; y < 2 ; y++ ){ /* 行のループ */ for ( x = 0 ; x < 4 ; x++ ){ /* カラムのループ */ ・ ・ ・
お礼
ご回答有難うございました。 失礼ですが、ANo.6 fatbowlerさんの回答下部に新たな質問を致しておりますので、ご指摘の程宜しくお願い致します。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★二次元配列について ・int a[2][4] という場合は a[0][0] a[0][1] a[0][2] a[0][3] a[1][0] a[1][1] a[1][2] a[1][3] という順でメモリ内に確保されます。 つまり a[縦方向][横方向] と考えるべきです。 >(6)int a[2][4]は、x方向は2列 , y方向は4列 と逆に考えたほうが正解なのでしょうか? ↑ int a[4][2] なら縦4行×横2列という感じなります。 なので x、y の数を入れ替えると上手く表示されただけです。 ・質問者さんは BASIC 出身者ですか? 多次元の配列の解釈(指定?)が C 言語系と BASIC 系で異なります。 BASIC 系では多次元配列が左→右に次元が大きくなりますが、C 言語系は右→左の順になります。 つまり int a[2][4] を a[横方向][縦方向] とした場合は 5、1 6、2 7、3 8、4 という縦型イメージになります。 ・正しくは int a[2][4] を a[縦方向][横方向] と解釈した方が良さそうです。 その場合は for ( y = 0 ; y < 2 ; y++ ){ for ( x = 0 ; x < 4 ; x++ ){ printf( "a[%d][%d] = %d ", y, x, a[y][x] ); } printf( "\n" ); } となります。 ・今回の場合は for 文の(10)、(11)の行を入れ替えて (11)for ( y = 0 ; y < 4 ; y++ ){ (10) for ( x = 0 ; x < 2 ; x++ ) (12) printf( "a[%d][%d]=%d ", x, y, a[x][y] ); (13) printf( "\n" ); (14)} とすればちゃんとイメージ通りに表示されます。 x、y の数を入れ替えるのではなく。 ・本当はメモリ・イメージと配列のイメージをあわせた方が分かりやすいです。 つまり、メモリの配置より a[横方向][縦方向] よりも a[縦方向][横方向] として アクセスして下さい。 ・以上。
お礼
ご回答有難うございました。 失礼ですが、ANo.6 fatbowlerさんの回答下部に新たな質問を致しておりますので、ご指摘の程宜しくお願い致します。
2次元配列のx方向、y方向は単なる概念なので。。。 >(10)行目での条件を x<4 >(11)行目での条件を y<2 この条件では、(12)でa[3][1]を参照することになるので、 型宣言とあっていません
お礼
ご回答有難うございました。 失礼ですが、ANo.6 fatbowlerさんの回答下部に新たな質問を致しておりますので、ご指摘の程宜しくお願い致します。
お礼
fatbowlerさん、ご回答有難うございます。 正に私が悩んでいた核心を突いて頂き有難うございます。 ご説明頂いた内容をよく噛み砕いて考え直したいと思います。 また、どうしても分からない時にはご回答宜しくお願い致します。
補足
fatbowlerさんはじめ、有識者のご意見を再度お聞きしたくて、新たに質問させて頂きます。 様々なご回答を頂きながら、今更ながら気付いたのですが、for文(2重ループ)に対しての理解も不十分だったようです。 fatbowlerさんの投稿を拝見した後、参考書および有識者のWEBサイトを見て回ったのですが、今回の2重ループは以下のような捉え方をすればいいのかな?と半信半疑の状態ですので、ご指南の程、宜しくお願い致します。 --------------------------------------------------------------- 【今回の質問箇所】 (10)for(x=0;x<2;x++){ (11)for(y=0;y<4;y++) --------------------------------------------------------------- ■現在の2重ループ理解状況■ 【プロセス1】 ★x = 0 の状態で y=0 (結果:a[0][0] = 1) y=1 (結果:a[1][0] = 2) y=2 (結果:a[2][0] = 3) y=3 (結果:a[3][0] = 4) 以上yへの代入を実行しプロセス2へ --------------------------------------------------------------- 【プロセス2】 ★x = 1 の状態で y=0 ⇒ a[0][1] = 5 y=1 ⇒ a[1][1] = 6 y=2 ⇒ a[2][1] = 7 y=3 ⇒ a[3][1] = 8 以上yへの代入を実行し終了 --------------------------------------------------------------- 【イメージ】 ■■■■■ ■4■■8■y[3] ■■■■■ ■3■■7■y[2] ■■■■■ ■2■■6■y[1] ■■■■■ ■1■■5■y[0] ■■■■■ x[0] x[1] --------------------------------------------------------------- 上記内容で正しければ、今回の疑問は皆様のご協力で無事解決となるのですが。どうぞ、宜しくお願い致します。