c언어로 지뢰찾기를 만드는데 계속 존재하지 않는 영역에 접근됩니다.

조회수 1039회
//#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define LAND_MAIN 10    
#define SAFE 11

void find_land_main(int map[][10], int x, int y)
{
    int count = 0;
    int ro;
    if (x >= 0 && x<10 && y >= 0 && y<5) //8방탐색
    {
        for (int Y = y - 1; Y <= y + 1; Y++)
        {
            for (int X = x - 1; X <= x + 1; X++)
            {
                if (X >= 0 && X < 5 && X >= 0 && X < 10)
                {
                    if (map[Y][X] == LAND_MAIN)
                        count++;
                }
            }
        }

        if (count > 0)
        {
            map[y][x] = count;
            return;
        }
        else
        {
            map[y][x] = SAFE;
            for (int Y = y - 1; Y <= y + 1; Y++) //그리기
            {
                for (int X = x - 1; X <= x + 1; X++)
                {
                    if (X >= 0 && X < 5 && X >= 0 && X < 10)
                    {
                        if (map[Y][X] < 1)
                        {
                            map[Y][X] = SAFE;
                        }
                    }
                }
            }

            if (x > 1 && x < 8 && y > 1 && y < 3) //8방의 8방탐색
            {

                find_land_main(map, x - 1, y);
                find_land_main(map, x, y - 1);
                find_land_main(map, x + 1, y);
                find_land_main(map, x, y + 1);
                find_land_main(map, x - 1, y - 1);
                find_land_main(map, x + 1, y + 1);
                find_land_main(map, x - 1, y + 1);
                find_land_main(map, x + 1, y - 1);
            }
        }
    }
}

void main()
{
    int map[5][10] = { 0 };
    int x, y,wincount = 0;
    srand(time(NULL));
    for (int i = 0; i < 5; i++)
    {
        x = (rand() % 10);
        y = (rand() % 5);
        map[y][x] = LAND_MAIN;
    }

    while (1)
    {
        system("cls");
        for (int Y = 0; Y < 5; Y++)
        {
            for (int X = 0; X < 10; X++)
            {
                if (map[Y][X] == SAFE)
                    printf("□");
                else if (map[Y][X] == 0 /*|| map[Y][X] == LAND_MAIN*/)
                    printf("■");
                else if(map[Y][X] == LAND_MAIN)
                    printf("※");
                else if (map[Y][X] > 0 && map[Y][X] < SAFE)
                    printf(" %d", map[Y][X]);
            }
            printf("\n");
        }
        while (1)
        {
            printf("좌표를 입력하세요 \n");
            printf("X :");
            scanf("%d", &x);
            printf("Y :");
            scanf("%d", &y);
            if (x < 10 && x >= 0 && y<5 && y >= 0)
            {
                break;
            }
            printf("다시입력 \n");
        }
        if (map[y][x] != LAND_MAIN)
        {
            find_land_main(map, x, y);
        }
        else if (map[y][x] == LAND_MAIN)
        {
            printf("\n 앗! 지뢰입니다. -GAME OVER- \n");
            system("pause");
            return;
        }
        //승리체크
        for (int Y = 0; Y < 5; Y++)
        {
            for (int X = 0; X < 10; X++)
            {
                if (map[y][X] == 0)
                {
                    wincount++;
                }
            }
        }
        if (wincount > 0)
            wincount = 0;
        else
            printf("\n 지뢰찾기 승리! - Win - \n");
    }
}

위처럼 코드를 작성했고 우선 임시로 지뢰들이 보이도록 해놨습니다.

좌표를 입력받으면 첫 8방 검색에서는 오류가 나지 않는데, 8방의 8방 검색으로 재귀함수를 써서 들어가면 스텍오버플로우 오류가 뜹니다. 코드의 어느부분이 문제인건지 아무리 디버깅 해봐도 모르겠네요 c언어 처음 배우는데 뭔가 제가 모르는 부분에서 오류가 있는 것 같기도하고.. 뭐가 문제일까요...

  • (•́ ✖ •̀)
    알 수 없는 사용자
  • 답변을 달긴 했는데 안맞는 답변이라서 지웠습니다. 엽토군 2020.8.19 14:33
  • 그래도 감사합니다 덕분에 효율적으로 코드를 정리해서 해결방법을 찾을 수 있었습니다. 알 수 없는 사용자 2020.8.19 22:34

1 답변

  • 답찾았습니다. 혹시 미래에 검색하시는 분이 계실까봐 남겨둡니다.

                if (x > 1 && x < 8 && y > 1 && y < 3) //8방의 8방탐색
                {
    
                    find_land_main(map, x - 1, y);
                    find_land_main(map, x, y - 1);
                    find_land_main(map, x + 1, y);
                    find_land_main(map, x, y + 1);
                    find_land_main(map, x - 1, y - 1);
                    find_land_main(map, x + 1, y + 1);
                    find_land_main(map, x - 1, y + 1);
                    find_land_main(map, x + 1, y - 1);
                }
    

    문제가 일어나는 부분은 위의 코드 입니다. 저는 클릭한지점의 8방만을 검색하는것이 아니라 만약 클릭한지점과, 8방 모두 지뢰가 없다면, 현재 클릭한 지점의 8방들을 다시 기준으로 놓고 그 8방에 지뢰가 없는것인지를 계속 탐색하여 지뢰가 있는 부분까지 확장시키는 코드를 짜고 싶었습니다.

    그런데 위에 적어놨다시피 스택오버플로우 오류가 납니다. 디버깅해본 결과 없는 공간에 접근하는것이 아닌 순수하게 메모리가 오버플로우된 결과였습니다(재귀함수에서 빠져나오지 못하거나, 무의미하게 반복이 많이 도는 경우).

    문제점을 살펴보니, find_land_main(map, x - 1, y); 에서 재귀를 끝낸 후 find_land_main(map, x, y - 1);로 넘어가도 그 재귀함수 내에서 또 find_land_main(map, x - 1, y); 가 걸리게됩니다. 그러니 이미 갔다온곳을 또 갔다오는 셈이 되겠네요. 이러니 오버플로우될 수 밖에요.

    해결방법은 간단했습니다 그냥 다녀 온 길에 전부 SAFE(디파인된 값)을 넣어주고 0, 즉 아무것도 아닌 자리만 탐색하도록 if 조건문을 걸면 됩니다.

답변을 하려면 로그인이 필요합니다.

프로그래머스 커뮤니티는 개발자들을 위한 Q&A 서비스입니다. 로그인해야 답변을 작성하실 수 있습니다.

(ಠ_ಠ)
(ಠ‿ಠ)