ページ 11

forループで回した変数について

Posted: 2014年5月13日(火) 21:41
by 3年生
いつもお世話になってます。
本日は4X4ボードゲームというものを作成してる途中に問題が発生したので、お聞きしたいと思います。

コード:

#include<stdio.h>

#define N 4

void search(int a[N][N],int *i,int *j);
int check(int a[N][N]);
int out(int a[N][N]);
void swap(int a[N][N],int *i,int *j);






int main(){
	int as=0,bs=0;
	int *i,*j;
	i=&as;
	j=&bs;
	int a[4][4]={{1,13,3,15},{2,5,7,4},{10,11,12,14},{6,0,8,9}};//ランダムに初期化
	out(a);//出力
	while(1){
		search(a,i,j);//*i,*jは現在の0要素のグリッド
		swap(a,i,j);//この処理によって入れ替えが実行される
		out(a);//出力
		if(check(a)==1){
			break;//すべての要素が条件を満たした時にbreakする
			}
		}
	return 0;
	}

/*空き要素(0)の特定*/
void search(int a[N][N],int *i,int *j){
	for((*i)=0;(*i)<4;(*i)++){
		for((*j)=0;(*j)<4;(*j)++){
			if(a[(*i)][(*j)]==0){
				return;//*i==*j==0からループを回して要素が0の時に関数を終了
				}
			}
		}
	}
		
int check(int a[N][N]){
    int s,t;
    int b[4][4]={{1,13,3,15},{2,5,7,4},{10,11,12,14},{6,0,8,9}};
    for(t=0;t<4;t++){
        for(s=0;s<4;s++){
            if(a[t][s] != b[t][s]){
                return 0;
            }
        }
    }
    return 1;
}

int out(int a[N][N]){
    int s,t;
    for(t=0;t<4;t++){
	for(s=0;s<4;s++){
		printf("%4d",a[t][s]);
            	}
        printf("\n");
    	}
}

void swap(int a[N][N],int *i,int *j)
{
	int x,y,z;
	int as=0;
	printf("入力して下さい:");
	scanf("%d",&z);
	for(x=0;x<=3;x++){
		for(y=0;y<=3;y++){
			printf("%d:%d:in roop\n",x,y);
			if(a[x][y]==z){
				break;
				}
			}
		if(a[x][y]==z){
			printf("%d:%d:out roop\n",x,y);
			break;
		}
	}
	printf("%d:%d:out roop\n",x,y);
        /*配列の処理*/
	if(y==4){
		x++;
		y=0;
		}
	
	printf("%d:%d:after\n",x,y);
	printf("\n");
	
	if(a[x+1][y]==0 || a[x-1][y]==0 || a[x][y+1]==0 || a[x][y-1]==0){
			if(((a[x][y+1]==0)&&(y==3))||((a[x][y-1]==0)&&(y==0))){
					return;
			}	
			as=a[(*i)][(*j)];
			a[(*i)][(*j)]=a[x][y];
			a[x][y]=as;
			}
	}
関数swapでint型変数x,yを使ってscanfで得た値を二次元配列上で検索し、該当したらそのループを抜けるように書いたのですが、出力してみると、目的の値が0列目にあるとき、妙なことになってしまいます。詳しくは以下の出力になります

-------------------------------------------------
b******@imc2o-014:~/soft$ ./fin
1 13 3 15
2 5 7 4
10 11 12 14
6 0 8 9
入力して下さい:6
0:0:in roop
0:1:in roop
0:2:in roop
0:3:in roop
1:0:in roop
1:1:in roop
1:2:in roop
1:3:in roop
2:0:in roop
2:1:in roop
2:2:in roop
2:3:in roop
2:4:out roop
2:4:out roop
3:0:after

1 13 3 15
2 5 7 4
10 11 12 14
0 6 8 9
入力して下さい:


----------------------------------------------------
in roopとついてるものがループ中に出力したx,yです
out roopとなっているものがforループを一つづつ抜けた時のx,yです
afterとなってるものが、適切な処理をした後のx,yです
ここで言う適切な処理は、想定している二次元配列a[4][4]の範疇に収める操作です。
例えば最後のout roopでは2;4になってますがこれは二次元配列では何故か、a[2][4]==a[3][0]というふうに認識されてるようなので、後者の方に変換する必要がありました。
しかし良く考えてみると、for文内でのbreakの条件では、a[2][3]まで進んだ時には該当の値が見つからないため、一旦for文を抜けて一個上のfor文を通過し、a[3][0]==目的の値となり、breakするはずです
なのでしょうがなくこのようなif処理をしましたが、どうも納得がいかないので、どなたか教えてください。よろしくおねがいします。

Re: forループで回した変数について

Posted: 2014年5月13日(火) 21:49
by box
3年生 さんが書きました: 二次元配列では何故か、a[2][4]==a[3][0]というふうに認識されてるようなので
a[2][4]という風に(並列の定義範囲外の添字を使って)アクセスすると、
a[2][3]の「となり」にある(であろう)a[3][0]にアクセスするのは、なぜだかわからない、
ということではなく必然的です。

Re: forループで回した変数について

Posted: 2014年5月13日(火) 22:03
by みけCAT
まずコードのインデントを整えるのがいいと思います。

Re: forループで回した変数について

Posted: 2014年5月13日(火) 22:07
by みけCAT
3年生 さんが書きました:しかし良く考えてみると、for文内でのbreakの条件では、a[2][3]まで進んだ時には該当の値が見つからないため、一旦for文を抜けて一個上のfor文を通過し、a[3][0]==目的の値となり、breakするはずです
「一旦for文を抜け」るということは、y<=3ではなくなったということであり、すなわちこの場合はy==4です。
この状態で80行目に行くと、当然a[x][y]はa[2][4]に相当します。
a[2][4]==a[3][0]だったとすると、a[2][4]==目的の値なので、breakが実行され、73行目に戻らずに85行目に進みます。

Re: forループで回した変数について

Posted: 2014年5月13日(火) 22:15
by 三年生
なるほど、確かにa[3][0]に戻る前にa[2][4]にアクセスする形になっていました・・・・・・
ようやく腑に落ちました。
おふたかたとも、どうもありがとうございました

>インデント
すみません・・・・・・自分が書いたのはmainとsearchだけだったので