본문 바로가기

개발이야기

구구단 출력, 이대로 좋은가?

매번 언어를 배울때 "Hello World"의 출력문으로 본격적인 배움을 시작하게 됩니다.

그 후 if문과 for문 등을 마치면 서로 약속 한듯 구구단출력을 하게 되는게 일반적이죠.

구구단 출력은 제어문과 반복문을 알기에 좋은 과제인듯 싶습니다.


그런데 간혹 구구단만을 주장하는 학생들을 보기도 합니다.  출력형태를 바꿔봄으로 자기만의 학습을 꾀하게 되는데 여기서 무척 않좋은 습관을 가지게 된다는 것입니다.

소스가 어떠하든 어떻게든 출력해라

그들의 소스를 보자면 가독성이라곤 보이지도 않는 출력은 제대로이지만 재활용 될 수없는 그런 상태인 것을 줄 곧 보게 됩니다.

저는 이런 문제를 많이 제기하였지만 이미 출력위주에 성향이 깊은 학생에게는 좀 무미건조한 지적일 수 밖에 없겠죠.

실무에도 마찬가지이듯 오로지 출력만 장땡으로 자기만 알 수 있고(또한 알수 없고) 버그 발생이나 요구 사항 변경시 엄청난 보수를 치뤄야할 문제가 도살이는 광경을 보게 되는데(본인 얘기) 이런 일을 대비해 학생때부터 그런 출력위주의 관점을 탈피하였으면 하는 바램입니다.

아 그럼 어떻게 짜야하는데?

출력은 첫번째이지만 스스로가 잘 된 코드인지 검토하고 보수하여 발전시켜야 합니다. 먼저 책의 예제를 잘 따라하면 책의 저자는 고수일 것이기에 고수의 스타일을 익히게 됩니다. 그런 반복을 통해 코드 스타일이 더 고수다워지겠죠. 즉 많이 보고 많이 접해야 코드 품질이 향상될 것이라고 말씀드리는 것입니다.

넌 어떻게 하는데? 보여줘!

알겠습니다. C언어로 본인이 한번 구구단을 출력해보겠습니다. 그리고 쫌 복잡하게 출력을 해보겠습니다.

먼저 본인의 코드는 "왜 내가 지금 구구단을 짜야하지?"라는 생각으로 씩씩거리며 코딩하였기에 품질은 우수 하지 않습니다. 그래도 "배움의 길을 걷는 학생들에게 도움이 되겠지"라는 믿음으로 코딩한 것이기에 본인의 수고를 위로해 주시고 복사해서 과제 제출은 삼가하시길 바랍니다.(전국 대학 과제에 돌거라 예상ㅋ)

먼저 출력을 보여드리겠습니다.


X자 형식으로 출력을 해보았습니다.

코드는 다음과 같습니다.

#include<stdio.h>

//한줄의총문자입력가능한수
#define TotalLineCursor 72

//하나의표시에사용되는문자갯수
#define RoundReturnCount 16

//하나의계산의글자크기지정
#define ReturnLength 5

 

//구구단
#define FirstValueCount 9
#define SecondValueCount 9

//곱하고출력하는함수
void MultiplyAndPrint(int x, int y)
{
        printf("%dX%d=%d",x,y,x*y);
}

//입력받은수만큼줄바꿈
void AddLine(int count)
{

        for(int i=0;i<count;i++)

               printf("\n");

}

 

//입력받은수만큼빈공간삽입

void AddSpace(int count)
{

        for(int i=0;i<count;i++)

               printf(" ");

}

 

//짝수판별

bool IsOdd(int value)
{

        if(value%2==0) return true;

        else return false;
}

 

void main()
{

        //총라인수
        int iLineCount = 0;

        //총계산수
        int iReturnCount = 0;

 

        int iTemp1 = 0;
        int iTemp2 = 0;

 

        for(int i=1 ;i<=FirstValueCount;i++)
        {

               for(int j=1 ;j<=SecondValueCount;j++)
               {

                       iReturnCount++;
 

                       iTemp1 = (iLineCount%RoundReturnCount)+1;
 

                       if(iTemp1 <= RoundReturnCount/2)
                       {
                              if(!IsOdd(iReturnCount))
                              {
                                      AddSpace((iTemp1-1)*ReturnLength);
                              }
                              else
                              {                                     

AddSpace(TotalLineCursor-(iTemp1*ReturnLength)-(iTemp1-1)*ReturnLength);
                              }
                              iTemp2 = iTemp1;
                       }
                       else
                       {
                              if(!IsOdd(iReturnCount))
                              {
                                      AddSpace(iTemp2*ReturnLength);
                              }
                              else
                              {
AddSpace(TotalLineCursor-(iTemp2*ReturnLength)-(iTemp2+1)*ReturnLength);
                              }
                       }

                       MultiplyAndPrint(i,j);

                       if(IsOdd(iReturnCount))
                       {
                              AddLine(1);

                              iLineCount += 1;

                              iTemp2--;
                       }
               }
        }
        getchar();
}

참으로 복잡하죠?

여기서 말씀드리고 싶은 것은 변수의 이름과 자주 사용되는 내용을 분리하였는데 여기 예제는 좀 손볼때가 많은 코드이니 대충 이렇구나만 하고 넘어가 주시길 바랍니다.

보시면 함수에 AddLine와 AddSpace가 있고 매개변수에 따라 반복을 하게 됩니다. 이 함수만으로도 엄청난 복잡성을 줄일 수 있고 표현을 다양하게 할 수 있었다라는 것을 강조하고 싶습니다.

마무리

이런 것 까지 신경쓰기에는 좀더 느리고 신경쓰일테지만 나중에는 더 쉽고 더 빠른 결과를 표현할 수 있습니다.

아름다운 코드가 시간을 단축시킵니다.