質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

Q&A

2回答

1789閲覧

c言語でオセロを作ろうとしているのですが、理由のわからないsegmentation faultが出てしまいます

wawawazezeze

総合スコア0

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

プログラミング言語

プログラミング言語はパソコン上で実行することができるソースコードを記述する為に扱う言語の総称です。

0グッド

0クリップ

投稿2021/01/26 17:31

前提・実現したいこと

c言語でオセロを作ろうとしているのですが、標準入力でxに1か8を代入するとsegmentation faultと出てしまい、オセロの1,8行めに石が置けないです。解決法をご教授いただけないでしょうか。

発生している問題・エラーメッセージ

Black's turn Input cell (x y) 2 5 White's turn Input cell (x y) 1 4 zsh: segmentation fault

該当のソースコード

c言語

1#include<stdio.h> 2#include<stdlib.h> 3#include "view_othello.h" // 描画関係のヘッダー 4 5/* 6 コンパイル: 7 gcc -I/usr/X11R6/include -Wall -c -o myothello.o myothello.c 8 gcc -I/usr/X11R6/include -Wall -c -o view_othello.o view_othello.c 9 gcc -I/usr/X11R6/include -Wall -L/usr/X11R6/lib -lX11 -o myothello myothello.o view_othello.o 10*/ 11 12/**** 13view_othello.h の中で以下のように定義されている. 14 15#define EMPTY (-1) 16#define WHITE (0) 17#define BLACK (1) 18 19struct othello{// オセロ用構造体 20 int n; // ボードのサイズ 21 int score[2]; // スコア記録用配列(必要に応じて利用) 22 int pass_flag[2]; // パスしたかどうかを記録する配列(必要に応じて利用) 23 int **board; // オセロのボード 24}; 25 26今回は,オセロのボードを二次元配列(board)で表現する. 27例えば,(1,5) のマスに白い石を置きたい場合は 28board[0][4] = WHITE とすれば良い. 29******/ 30 31void myothello(int *step, /* 現在のステップ数(初期値は0) */ 32 struct othello *o /* オセロのボードなどの情報を含む構造体 */ 33 ){ 34 int x, y; /* どこのマスに置くのか記録する変数 35 行方向を x,列方向を y とする */ 36 int color; /* 黒と白,どちらのターンか記録する変数 */ 37 if( *step % 2 == 0 ){ /* 偶数ステップのときは黒の番 */ 38 color = BLACK; 39 printf( "Black's turn\n" ); 40 } else { /* 奇数ステップのときは白の番 */ 41 color = WHITE; 42 printf( "White's turn\n" ); 43 } 44 45 int i,j; 46 int finish = 0; /* 終了処理用 */ 47 48 RE: 49 /* 被っていたら正しく入力されるまでやり直させる */ 50 for(i = 0;i < 1;i++) 51 { 52 printf( "Input cell (x y)\n" ); 53 scanf( "%d %d", &x, &y ); 54 x--; y--; /* 配列番号が0番から始まるため. */ 55 56 if(o->board[x][y] == WHITE||o->board[x][y] == BLACK) /* 既に置いてあればやり直し */ 57 { 58 printf("既に石が置かれています。もう一度入力してください。\n"); 59 i--; 60 } 61 } 62 63 int count,s,n,other,count2; 64 int a,b; /* x,yの値を控えておく変数 */ 65 66 a = x; 67 b = y; 68 69 /* 相手の石の色 */ 70 71 if(color == WHITE) 72 { 73 other = BLACK; 74 } 75 else if(color == BLACK) 76 { 77 other = WHITE; 78 } 79 /* 各方向に対してそこに置くと相手の石がひっくり返せるかを確認 */ 80 81 /* 1方向でもひっくり返せればその場所に置ける */ 82 83 /* 置ける方向をカウント */ 84 count = 0; 85 /* そもそも置けるのかカウントで判定 */ 86 count2 = 0; 87 88 /* 置けるマスがあるのか判定する */ 89 for(y = 0; y < (o->n + 1); y++) 90 { 91 for(x = 0; x < (o->n + 1); x++) 92 { 93 for(j = -1; j < 2; j++) 94 { 95 for(i = -1; i < 2; i++) 96 { 97 98 /* 盤面外のマスはチェックしない */ 99 if( 100 x + i >= 0 && 101 x + i < o->n && 102 y + j >= 0 && 103 y + j < o->n 104 ) 105 { 106 /* 真ん中方向はチェックしてもしょうがないので次の方向の確認に移る */ 107 if(i == 0 && j == 0) 108 { 109 continue; 110 } 111 112 /* 隣が相手の色でなければその方向でひっくり返せる石はない */ 113 if(o->board[x + i][y + j] != other) 114 { 115 continue; 116 } 117 } 118 119 /* 置こうとしているマスから遠い方向へ1マスずつ確認 */ 120 for(s = 2; s < o->n; s++) 121 { 122 /* 盤面外のマスはチェックしない */ 123 if( 124 x + i * s >= 0 && 125 x + i * s < o->n && 126 y + j * s >= 0 && 127 y + j * s < o->n 128 ) 129 { 130 131 if(o->board[x + i * s][y + j * s] == EMPTY) 132 { 133 /* 自分の石が見つかる前に空きがある場合 */ 134 /* この方向の石はひっくり返せないので次の方向をチェック */ 135 break; 136 } 137 138 /* その方向に自分の色の石があれば石がひっくり返せる */ 139 if(o->board[x + i * s][y + j * s] == color) 140 { 141 /* 石がひっくり返る方向の数をカウント */ 142 count++; 143 } 144 } 145 } 146 } 147 } 148 /* 置けなかった場合 count2 に記録する */ 149 if(count != 0) 150 { 151 count2++; 152 } 153 } 154 } 155 156 /* 一つもおく場所がなかったらパス */ 157 if(count2 == 0) 158 { 159 printf("置ける場所がないのでパスされました\n"); 160 finish++; 161 color = other; /* 相手の手番に回す */ 162 163 /* 終了処理 */ 164 /* 黒白そちらもパスだったら試合終了 */ 165 if(finish == 2) 166 { 167 printf("対戦終了\n"); 168 169 int count_b = 0; 170 int count_w = 0; 171 172 /* 全マスの探索 */ 173 for(int i = 0; i < o->n; i++) 174 { 175 for(int j = 0; j < o->n; j++) 176 { 177 if(o->board[i][j] == BLACK) 178 { 179 count_b++; 180 } 181 if(o->board[i][j] == WHITE) 182 { 183 count_w++; 184 } 185 } 186 187 /* 結果の表示 */ 188 printf("黒%d石,白%d石\n",count_b,count_w); 189 if(count_b > count_w) 190 { 191 printf("黒の勝利\n"); 192 } 193 else if(count_b < count_w) 194 { 195 printf("白の勝利\n"); 196 } 197 else 198 { 199 printf("引き分け\n"); 200 } 201 202 /* ボードの削除(2次元配列のメモリを解放) */ 203 for( i=0; i<o->n; i++ ) 204 { 205 free( o->board[i] ); 206 } 207 free( o->board ); 208 209 exit(0); /* プログラム終了 */ 210 } 211 212 /* このターン初回のパスであれば続行 */ 213 goto RE; 214 } 215 } 216 217 finish = 0; /* ゲームが続いたらパスの回数はリセット */ 218 219 /* x,yの値を元に戻す */ 220 x = a; 221 y = b; 222 223 /* 置ける方向をカウント */ 224 count = 0; 225 226 /* 全方向に対して挟んだ石をひっくり返す */ 227 for(j = -1; j < 2; j++) 228 { 229 for(i = -1; i < 2; i++) 230 { 231 /* 盤面外のマスはチェックしない */ 232 if( 233 x + i >= 0 && 234 x + i < o->n && 235 y + j >= 0 && 236 y + j < o->n 237 ) 238 { 239 /* 真ん中方向はチェックしてもしょうがないので次の方向の確認に移る */ 240 if(i == 0 && j == 0) 241 { 242 continue; 243 } 244 245 /* 隣が相手の色でなければその方向でひっくり返せる石はない */ 246 if(o->board[x + i][y + j] != other) 247 { 248 continue; 249 } 250 } 251 252 /* 置こうとしているマスから遠い方向へ1マスずつ確認 */ 253 for(s = 2; s < o->n; s++) 254 { 255 /* 盤面外のマスはチェックしない */ 256 if( 257 x + i * s >= 0 && 258 x + i * s < o->n && 259 y + j * s >= 0 && 260 y + j * s < o->n 261 ) 262 { 263 264 if(o->board[x + i * s][y + j * s] == EMPTY) 265 { 266 /* 自分の石が見つかる前に空きがある場合 */ 267 /* この方向の石はひっくり返せないので次の方向をチェック */ 268 break; 269 } 270 271 /* その方向に自分の色の石があれば石がひっくり返せる */ 272 if(o->board[x + i * s][y + j * s] == color) 273 { 274 /* 石がひっくり返る方向の数をカウント */ 275 count++; 276 } 277 } 278 } 279 } 280 } 281 282 if(count == 0) 283 { 284 printf("そこに置くことは出来ません\n"); 285 goto RE; /* 位置の入力前まで戻る */ 286 } 287 288 289 290 /* 色の反転 */ 291 /* 全方向に対して挟んだ石をひっくり返す */ 292 for(j = -1; j < 2; j++){ 293 for(i = -1; i < 2; i++){ 294 295 296 /* 盤面外のマスはチェックしない */ 297 if( 298 x + i >= 0 && 299 x + i < o->n && 300 y + j >= 0 && 301 y + j < o->n 302 ) 303 { 304 /* 真ん中方向はチェックしてもしょうがないので次に進む */ 305 if(i == 0 && j == 0) 306 { 307 continue; 308 } 309 310 /* 隣が相手の色の場合は次に進む */ 311 if(o->board[x + j][y + i] == color) 312 { 313 continue; 314 } 315 } 316 317 /* 遠い方向へ1マスずつ確認 */ 318 for(s = 2; s < o->n; s++) 319 { 320 /* 盤面外のマスは飛ばす */ 321 if( 322 x + i * s >= 0 && 323 x + i * s < o->n && 324 y + j * s >= 0 && 325 y + j * s < o->n 326 ) 327 { 328 329 330 if(o->board[x + i * s][y + j * s] == EMPTY) 331 { 332 /* 自分の石が見つかる前に空きがある場合 */ 333 /* この方向の石はひっくり返せないので次の方向をチェック */ 334 break; 335 } 336 337 /* その方向に自分の色の石があれば石がひっくり返せる */ 338 if(o->board[x + i * s][y + j * s] == color) 339 { 340 /* 石を置く */ 341 o->board[x][y] = color; 342 343 /* 挟んだ石をひっくり返す */ 344 for(n = 1; n < s; n++) 345 { 346 o->board[x + i * n][y + j * n] = color; 347 } 348 } 349 } 350 } 351 } 352 } 353} 354 355int main (int argc, char **argv){ 356 int i; 357 struct view view={512,512,}, *v=&view; /* おまじない (ウィンドウ) */ 358 struct othello othello_instance={8,{2,2},{0,0},NULL}, *o=&othello_instance; /* 8はボードの列(行)数.*/ 359 360 for(i=0; i<argc; i++) 361 { 362 if(*argv[i] == '-') 363 switch(*(argv[i]+1)) 364 { 365 case 'n': 366 o->n = atoi(argv[2]); 367 break; 368 default: 369 printf("OPTION ERROR\n"); 370 break; 371 } 372 } 373 374 /* ボード作成(2次元配列の確保) */ 375 o->board = (int**)malloc( sizeof(int*) * o->n ); 376 for( i=0; i<o->n; i++ ){ 377 o->board[i] = (int*)malloc(sizeof(int) * o->n ); 378 } 379 380 381 view_init( v ); // おまじない (Xウィンドウ) 382 view_loop( v, o ); // 描画(この関数の中で myothello 関数が呼ばれる) 383 384 385 386 view_out( v ); // おまじない (Xウィンドウ) 387 388 // ボードの削除(2次元配列のメモリを解放) 389 for( i=0; i<o->n; i++ ){ 390 free( o->board[i] ); 391 } 392 free( o->board ); 393 394 return 0; 395} 396 397//ここから先はview_othello.hです 398 399#ifndef __VIEW_OTHELLO_h 400#define __VIEW_OTHELLO_h 401#include <stdio.h> 402#include <string.h> 403#include <stdlib.h> 404#include <unistd.h> 405 406#include <X11/Xlib.h> /* X11 Libraly */ 407//#include "/opt/X11/include/X11/Xlib.h" /* X11 Libraly */ 408#include <X11/Xutil.h> 409//#include "/opt/X11/include/X11/Xlib.h" 410 411//////////////////// Othello part 412#define EMPTY (-1) 413#define WHITE (0) 414#define BLACK (1) 415 416struct othello{ 417 int n; 418 int score[2]; 419 int pass_flag[2]; 420 int **board; 421}; 422 423// myothelloのプロトタイプ宣言 424void myothello( int *step, struct othello *o ); 425 426// ボードを初期化する関数 427void init_othello( struct othello *o ); 428 429/////////////////// Visualization part 430/* View */ 431struct view{ 432 int w, h; 433 int screen_number; 434 long event_mask; 435 Display* display; 436 Window parent, window; 437 Pixmap pixmap; 438 GC gc; 439 Colormap cmap; 440 XColor color; 441 XEvent event; 442}; 443 444void view_init( struct view *v ); 445 446 447void view_out( struct view *v ); 448void view_draw( struct view *v, void *a ); 449void view_loop( struct view *v, struct othello *o ); 450#endif 451

試したこと

非効率なコードで長くなってしまっていて申し訳ないのですが、void myothello関数の一番最後あたりの/* 色の反転 */以降でsegmentation faultが起きているようなのでそこを見てもらいたいです。

始めの標準入力でxを代入する際、xに1か8を入れたらエラーが起きてしまいます。yには1,8を入れても問題ないです。board[x+i][y+j]のx+iが0以下になってしまっているとかも回避しているので大丈夫だと思ったのですがどうにもダメみたいです。

X11をインストールして,オセロの盤面の画面表示はそれで行ってます。

補足情報(FW/ツールのバージョンなど)

macOS Big Sur 11.1

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

stdio

2021/01/26 20:14

すみません。 ここまでプログラムが長くなってしまいますと、動きを追うのだけで日が暮れそうです。 当たりを付けて頂けると幸いなのです。 もし分からなければ、何度かprintfをしているようなので、そのポイントを教えて頂いてもよろしいですか?
thkana

2021/01/26 23:41 編集

現象とは関係ないけど、 ボードのメモリの解放が2箇所にあるのはよろしくない気がする。
dodox86

2021/01/26 23:58 編集

ご提示のコードはX11(X Window)関連の#include、マクロなど含んでいるようですが、view_init(), view_out()などの質問者さんが定義したであろう関数のコードの提示はありません。このままでは閲覧者が(もしその気になって)再現させようとしても不可能です。もちろん、ご提示のコード部分に問題がある可能性はありますが、それ以外の関数に問題が波及している可能性もあるので、このままでは第三者が再現することは難しいように思います。今のままでは「コードを机上デバッグして、問題点を特定してください」というレベルに感じます。(随分危なっかしいコードに思えなくもないですが) ※私の方で試しにX11関連部分を無効にし、view_init()などをダミーの関数にしてgccでコンパイル、実行ファイルにすることはできましたが、初期値としてどのような盤面になっているべきか、実行時のコマンドラインオプションにどのような値を渡すべきか分からなかったので、再現はできませんでした。view_loop()関数の冒頭ででも盤面データの初期化をしてそうなものですが。 X11/X Windowに依存しないようコードを切り分けると、ご提示のコード部分に問題があるのかどうか、より分かり易くなるのではないでしょうか。
guest

回答2

0

字面でみただけでロジックは追ってないけど

C

1 for (j = -1; j < 2; j++) { 2 for (i = -1; i < 2; i++) { 3 //略 4 /* 遠い方向へ1マスずつ確認 */ 5 for (s = 2; s < o->n; s++) { 6 /* 盤面外のマスは飛ばす */ 7 if (x + i * s >= 0 && x + i * s < o->n && y + j * s >= 0 && 8 y + j * s < o->n) { 9 //略 10 /* 挟んだ石をひっくり返す */ 11 for (n = 1; n < s; n++) { 12 o->board[x + i * n][y + j * n] = color; //<-- 13 }

x+in, y+jnは0~o->nに収まるのかしら?

投稿2021/01/26 23:52

thkana

総合スコア7703

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

dodox86

2021/01/27 00:02

> x+i*n, y+j*nは0~o->nに収まるのかしら? 私もインデックスの値の扱いを危なげに思いましたが、assert() を各所に仕掛けておくと引っかかりそうですね。
thkana

2021/01/27 00:08

随所で if (x + i >= 0 && x + i < o->n && y + j >= 0 && y + j < o->n) { とか if (x + i * s >= 0 && x + i * s < o->n && y + j * s >= 0 && y + j * s < o->n) { とかやってて頑張ってるなぁ、と思うんですけどここだけガードしてないんですよね。
guest

0

回答ではないですが。。

C言語のコードを書くなら、デバッグできる環境を整えましょう。
Eclipseや、WindowsならVisualStudioなど。
コードの任意の場所で実行を止め、変数のナカミを見ることができます。そこから1行づつ実行して、コードの流れを見れるようになります
そうすれば、アテズッポでコードを書かなくて済むようになります。

投稿2021/01/26 23:29

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問