自作関数のセグメントエラー

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
べあ

自作関数のセグメントエラー

#1

投稿記事 by べあ » 9年前

(投稿に失敗したみたいなので再投稿します)
自作のcount関数でセグメントエラーが起こっているようです。
このコードは30*30のマスに0か1の値が割り振られていて、1のマスの座標情報を書き出し、
ルールにのっとってマスの値を変えるというのを150回繰り返すものです。

count関数で周りのマスの値が1のものをカウントし、その個数によってあるマスの次のターンの値が決まります。
if文で存在しない配列にアクセスしないように気を付けているのですが、不十分でしょうか?
ご教授お願いいたします。

コード:

#include<stdio.h>

#define xgrid 30
#define ygrid 30

int count(int data[xgrid][ygrid]) {
  int x, y, check;
  check = 0;

  if (x > 0 && y < (ygrid - 1)) {
    if (data[x - 1][y + 1] == 1) {
      check += 1;
    }
  }
  if (x > 0 && y > 0) {
    if (data[x - 1][y - 1] == 1) {
      check += 1;
    }
  }
  if (x > 0) {
    if (data[x - 1][y] == 1) {
      check += 1;
    }
  }
  if (y > 0 && x < (xgrid - 1)) {
    if (data[x + 1][y - 1] == 1) {
      check += 1;
    }
  }
  if (y < (ygrid - 1) && x < (xgrid - 1)) {
    if (data[x + 1][y + 1] == 1) {
      check += 1;
    }
  }
  if (x < (xgrid - 1)) {
    if (data[x + 1][y] == 1) {
      check += 1;
    }
  }
  if (y < (ygrid - 1)) {
    if (data[x][y + 1] == 1) {
      check += 1;
    }
  }
  if (y > 0) {
    if (data[x][y - 1] == 1) {
      check += 1;
    }
  }
  return check;
}

int main(void) {
  int data[xgrid][ygrid];
  int i, x, y, check;

  for(x = 0; x < xgrid; x++) {
    for(y = 0; y < ygrid; y++) {
      data[x][y] = 0;
    }
  }

  data[11][8] = data[15][8] = data[16][8] = data[17][8]
	            = data[10][7] = data[11][7] = data[16][6] = 1;

  for(i = 0; i < 151; i++) {
    for(x = 0; x < xgrid; x++) {
      for(y = 0; y < ygrid; y++) {
        if (data[x][y] == 0) {
          check = count(data);
          if (check == 3) {
            data[x][y] = 1;
          } else {
          printf("%d %d\n", x + 1, y + 1);
          check = count(data);
          if (check < 2 || check > 3) {
            data[x][y] = 0;
          }
          }
        }
      }
    }     
    printf("-1 -1\n\n\n");
    }
  return 0;
}


can110
記事: 27
登録日時: 10年前

Re: 自作関数のセグメントエラー

#2

投稿記事 by can110 » 9年前

count関数内で宣言された未初期化の変数x、yを参照しているのが原因だと思われます。
そもそもcount関数には「どのマスを基準にして」周囲を探すのか引数で指定すべきでは?

ちなみに、以下のように範囲内か判定する関数を用いれば、簡潔に記述できます。

コード:

// 範囲内か
int isRange( int x, int y)
{
	if( (x >= 0) && (x < xgrid) && (y >= 0) && (y < ygrid) ){
		return 1;
	}
	//	printf( "x=%d, y=%d is out of range.\n", x, y);
	return 0;
}

// トーラス補正
void adjustTorus( int *px, int *py)
{
	if(		*px < 0)		*px = xgird-1;
	else if(*px >= xgrid)	*px = 0;
	if(		*py < 0)		*py = ygird-1;
	else if(*py >= ygrid)	*py = 0;
}

int count( int x, int y, int data[][ygrid]) {
	int check = 0;
	// 上下左右1マスずつ走査
	for( xx = x-1; xx <= x+1; xx++){
		for( yy = y-1; yy <= y+1; yy++)
			if( xx == x && yy == y) continue;	// 自身は除く
		//	adjustTorus( &xx, &yy);		// トーラス補正
			if( !isRange( xx, yy)) continue;	// 範囲外
			if( !data[xx][yy]) continue;		// いない
			check++;
		}
	}
	return check;
}
オフトピック
ライフゲームかな?

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 自作関数のセグメントエラー

#3

投稿記事 by みけCAT » 9年前

C言語の場合、count関数内で未初期化の自動変数x, yの値は不定であり、その値を使うとundefined behaviorになります。
undefined behaviorになると、何が起こっても文句は言えません。

C++の場合、count関数内の変数x, yは宣言されたブロックのみで利用できる変数であり、staticもexternもついていないので、
automatic storage durationを持ちます。(N3337 3.7.3)
これらの宣言では初期化子が無く、static storage durationでもthread storage durationでもないので、default-initializeされます。
これらの型はクラスでも配列でもないので、default-initializeは何も行わないことであり、値は不定になります。(N3337 8.5)
べあ さんが書きました:if文で存在しない配列にアクセスしないように気を付けているのですが、不十分でしょうか?
はい。
例えばx=10000, y=-12345のときdata[x - 1]は範囲外ですが、10行目の条件式x > 0 && y < (ygrid - 1)は真であり、範囲外へのアクセスが行われてしまいます。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 自作関数のセグメントエラー

#4

投稿記事 by みけCAT » 9年前

can110 さんが書きました:

コード:

int count( int x, int y, int data[][ygrid]) {
	int check = 0;
	// 上下左右1マスずつ走査
	for( xx = x-1; xx <= x+1; xx++){
		for( yy = y-1; yy <= y+1; yy++)
			if( xx == x && yy == y) continue;	// 自身は除く
		//	adjustTorus( &xx, &yy);		// トーラス補正
			if( !isRange( xx, yy)) continue;	// 範囲外
			if( !data[xx][yy]) continue;		// いない
			check++;
		}
	}
	return check;
}
xx, yyが宣言されていない上、もしも「トーラス補正」のコメントアウトを解除することでxxやyyを書き換えて戻さないようにしてしまうとやばいのではないでしょうか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

box
記事: 2002
登録日時: 14年前

Re: 自作関数のセグメントエラー

#5

投稿記事 by box » 9年前

べあ さんが書きました: ルールにのっとってマスの値を変えるというのを150回繰り返すものです。
本当ですか?
べあ さんが書きました:

コード:

  for(i = 0; i < 151; i++) {
151回実行してますけど。
バグのないプログラムはない。
プログラムは思ったとおりには動かない。書いたとおりに動く。

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

Re: 自作関数のセグメントエラー

#6

投稿記事 by みけCAT » 9年前

オフトピック
ライフゲームなら、更新後のデータを混ぜずに全て更新前のデータに基づいて次の状態を決めないといけないのでは?
でも、そもそもマスの値が0のときしか更新しないようになっているから、(今のところ、少なくとも3個で生成、2個か3個で生存の基本ルールの)ライフゲームではないか。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)

閉鎖

“C言語何でも質問掲示板” へ戻る