티스토리 뷰



C언어를 이제 막 배우기 시작한 병아리 개발자를 위해서 실습을 위한 과제를 내주고 이에 대한 피드백을 코드와 함께 메모로 남깁니다. 코드 실습 환경은 "C언어 배우기를 위한 준비"를 참조하세요.


■ 문제

마방진 출력 프로그램 작성

  1. 프로그램 형태
    - 콘솔 프로그램
    - 프로그램 아규먼트 입력, 화면 출력 형태

  2. 입력
    - 3 ~ 15의 홀수를 받음
    - 오류 입력에 대처해야 함

  3. 출력
    - 입력 오류 발생시 오류 내용과 사용방법을 출력함
    - 정상 입력시 N 마방진을 가로/세로 폭을 맞추어 출력
    - 자체 검증을 위해서 가로, 세로 및 한쪽 대각선 방향의 함께를 출력함




■ 코드와 해설

다른 사람의 코드를 보지 않고 문제 내용만으로 코딩하는 연습이 실력을 키우는 첩경입니다. 

홀수 마방진 작성 프로그램 연습은 2차원 배열을 기반으로 기본적인 알고리즘을 코드로 구현해 보기 위한 연습입니다. 가운데 상단에서 1을 넣고 우측으로 +1, 상단으로 -1으로 이동해서 다음 숫자를 차례로 입력하면 가로, 세로 대각선의 함이 모두 일치하는 마방진을 작성할 수 있다는 것입니다. 우측으로 +1, 상단으로 -1로 이동할 때  셀 범위를 넘어서면 반대편으로 이동하고 이동한 셀에 이미 값이 존재하면 바로 아래로 이동에서 숫자를 입력하면 됩니다.

#include <stdio.h>
#include <stdlib.h> 

#define MAX_MBZ 15

int MBZ[MAX_MBZ+1][MAX_MBZ+1] = { 0, };

void usage()
{
    printf("이 프로그램은 홀수 마방진 프로그램입니다.\n");
    printf("3~15 홀수 숫자만 입력해주세요!\n");
    printf("사용법 : mbz 홀수숫자\n");
    exit(0);
}    

int main( int argc, char* argv[])
{
    int N, x, y, lastnum, number;
    
    if( argc != 2 ) usage();
    N = atoi(argv[1]);
    if (N < 3 || N > 15 || N % 2 == 0) usage();

    x =  (N - 1) / 2;
    y = 0;
    lastnum = N * N;

    for(number = 1; number <= lastnum; number++)
    {
        MBZ[x][y] = number;
        if ( number % N == 0 )
        {
            y++;
        }
        else
        {
            y--;
            x++;
            if (y < 0) 
            {
                y = N - 1;
            }
            if (x >= N)
            {
                x = 0;
            }
        }
    }

    for(y = 0; y <= N; y++)
    {
        for(x = 0; x <= N; x++)
        {
            printf("%3d ", MBZ[x][y]);
            if (x < N && y < N) 
            {
                MBZ[N][y] += MBZ[x][y];
                MBZ[x][N] += MBZ[x][y];
                if (x == y) MBZ[N][N] += MBZ[x][y];
            }
        }
        printf("\n");
    }
}
    • #define : 전처리기(precompile) 문장으로 컴파일러가 빌드하는 시점에 정의한 내용으로 치환(replace)시켜 컴파일 하는 매크로로 최근 표준화 도구에서는 #define 문장 대신에 const를 이용한 상수정의를 사용하는 것으로 권장하기는 하지만 C언어 개발자 들의 유용한 도구이므로 의미와 동작 형태를 명확하게 이해할 필요가 있습니다. 배열을 동적으로 만들지 않고 최대치를 #define으로 정의했습니다. 혹시 값을 변경하더라도 코드 전체를 수정할 필요없이 이 값만 바꾸면 되므로 편리합니다.

    • 배열(MBZ) 선언은 자체 합계 계산을 감안해서 최대치 +1의 크기로 정의합니다. 초기화에서 {0,}로 선언한 것은 배열의 나머지도 모두 0으로 초기화하라는 의미입니다.  {0}로 입력해도 전체 초기화가 이루어 지지만 이 동작은 컴파일러가 처리해주는 것이므로 명확한 초기화는 실행문으로 memset(MBZ, 0, sizeof(MBZ));처럼 기술하는 것입니다. 

    • usage() 함수를 별도로 작성해서 입력 검사 로직을 단순화 시키는 것도 참고할만 합니다.

    • 과제를 주었더니 특이한 알고리즘을 추가했더군요. 이동한 위치에 이미 값이 있으면 바로 아래로 이동한다는 것인데 관찰해 보니 이미 값이 존재해서 바로 아래로 이동하는 경우는 N의 배수일때만이라서 이 경우를 그냥 사전에 필터링한 것이지요. 괜찮은 관찰이기는 한데 이런 분석이 오래 걸리지 않았다면 좋을뻔 했습니다.

    • 자체 검증을 위한 합계를 내는 로직도 단순하지만 많이 사용하므로 익숙하게 할 필요가 있습니다. 


아래는 실행 결과입니다.



댓글
댓글쓰기 폼