포털:고등학교/과학 계열 전문 교과/정보과학(2015 개정)/데이터와 작업의 모듈화

4. 데이터와 작업의 모듈화

프로그램 작성 과정에서는 문제 상황의 해결에 필요한 데이터(data, 자료)와 작업을 추상적인 단위로 모듈화하여, 데이터들을 구조화하고 추상적인 단위로 작업을 처리하는 것이 매우 편리하다. 가장 간단한 형태의 데이터 모듈화는 배열이나 구조체와 같은 구조들을 사용하는 것으로서, 프로그래밍 언어를 통해서 입력되고 저장되는 데이터들을 보다 편리하게 구조화하여 이용할 수 있도록 해 준다. 함수는 가장 기본적인 작업의 모듈화로서 이해할 수 있는데, 수행해야 할 작업과 그 결괏값을 미리 정의한 후 추상적인 단위로 생각해 프로그램을 작성할 수 있게 해 준다.

배열, 구조체, 함수.

변수는 어떤 값을 저장하고 재사용하기 위해 사용하는 저장 공간의 이름이라고 할 수 있다. 같은 자료형 변수들이 많이 필요한 문제 상황에서는 이름만 다른 변수들을 만들어야한다. 이렇게 만든 변수들을 다루기 위해서는 변수 이름을 개별적으로 사용해야 하기 때문에 비효율적이다. 이때 배열을 사용해 같은 이름으로 참조 번호만 다르게 해서 데이터들을 저장하고 관리하게 된다.

배열은 1차원배열과 다차원 배열로 구분

1차원 배열은 형태: 자료형 이름[개수] 설명: //같은 자료형을 가지는 배열 선언

              기본 코드: int a[10]     설명: //정숫값을 10개 저장하는 a라는 이름의 배열 선언. 

다차원 배열은 2개 이상의 참조 번호를 사용하는 배열. 2차원 배열은 마치 표와 같은 형태로 생각할 수 있는 배열.

                        형태: 자료형 이름[개수1][개수2]  설명: //2차원 배열 선언
                        기본 코드: int a[3][3]           설명: //정숫값을 저장하는 2차원 배열 선언

구조체는 다양한 자료형을 가지는 변수들을 하나로 묶어 먼저 정의하고, 그렇게 정의된 형태를 마치 새로운 자료형처럼 사용 할 수 있음. 서로 다른 자료형들을 묶음 단위로 처리하는 것이 편리한 문제 상황에서는 구조체를 사용해 묶음을 정의하고, 그렇게 정의한 구조를 이용해 데이터들을 저장하고 쉽게 다룰 수있음. 형태: struct 이름 설명: //여러 가지 자료형들을 묶어 원하는 형태로 이름을 붙여 정의함.

{

 자료형 변수1;
 자료형 변수2;
                                      

}; //구조체 정의 마지막에 세미콜론

기본 코드: struct point 설명:

                                   //내부에 정수 x, 정수 y 영역으로 구성되어 있는 point라는 형태의 구조체 선언.

{ 구성되는 형태만 정의한 것이고, 구조체 변수나 구조체 배열을 선언하면

int x;                             그때 정의한 형태로 변수/배열이 만들어진다.   
int y;

};

구조체를 선언하면, 그러한 구조를 가지는 구조체 변수를 선언할 수 있고, 그 구조체 변수의 각 요소에 접근해 읽고 쓰기 위해서는 닷(dot,‘.’) 연산자를 사용한다.

구조체 배열의 사용 구조체의 형태를 먼저 정의해 두었다면, 일반적인 변수처럼 구조체 형태의 변수를 선언하고 사용할 수 있을 뿐만 아니라, 구조체 형태의 배열도 사용할 수 있다.구조체 배열을 사용하면 같은 형태로 데이터들을 묶어 처리하기가 편리하다.

형태: struct 이름 설명: //여러 가지 자료형들을 묶어 원하는 형태로 이름을붙여 정의한다.

{

자료형 변수1;                             
자료형 변수 2;

}; //구조체 정의 마지막에 세미콜론 이름 a[10]; //구조체 배열 생성

기본 코드: struct point 설명://point 형태의 구조체 정의

{

int x;
int y;

}; point p[10]; //point 형태의 구조체 배열 선언

함수의 정의 및 사용 함수는 어떤 상황에 필요한 작업들을 하나로 묶어 먼저 정의하고, 그렇게 정의한 작업을 편리하게 불러 사용할 수 있는 작업 단위로서 모듈화 구조라고 볼 수 있음. 반복적인 작업이 많이 이루어지거나 어떤 목표를 위한 작업들을 추상적으로 생각하면서 간단히 다루고 싶을 때, 그 목표를 위해 필요한 작업들을 묶어 함수로 미리 정의해 두면, 필요할 때 정의해 둔 작업들을 쉽게 불러 사용할 수 있음.

형태: 자료형 함수 이름(변수 1, …) 설명:

{ //여러 가지 필요한 작업들을 묶어 원하는 형태로 이름을 붙여 정의한다.

작업 1…;
작업 2…;
return (값);                                     //함수의 실행 결과를 리턴

}

기본 코드: int f(int a, int b) 설명:

                                                  //2개의 정숫값을 받아 자기가 사용하는 변수인 a, b에 저장하고, 

{ 그 값을 비교해서 두 수의 차(절댓값)를함수를 호출한 곳에 가져다 놓음(돌려놓음) if(a>b) return a-b;

else return b-a;

}


함수의 실행 결과, 함수의 이름, 함수에 넘겨진 값을 받아 저장해서 사용할 변수들, 함수 호출 시 실행할 작업들을 사용하기 전에 미리 정의해 두면, 필요한 상황에 간단히 호출하여 사용할 수 있다. 함수는 크게 4가지 형태로 생각해 볼 수 있는데, 이는 ‘함수의 실행 결과에 따라 함수를 호출한 위치에 가져다 놓는 값이 있는가, 없는가?’와 ‘함수에 전달하는 값이 있는가, 없는가?’의 관점으로 생각할 수 있다.

구분 호출했던 위치에 값을 가져다 놓는지의 여부

                                가져다 놓지 않고 복귀          가져다 놓으며 복귀
                                  void f1( )                         int f2( )
               값을              {                                   {
               전달하지                     …;                        int t;
               않음                printf("123\n");                    t = 123

함수의 return; //생략 가능 return t;//생략 불가 값을 }//호출 위치로 자동 복귀 } 전달 하는지의 여부 void f3(int k) int f4(int k)

                                 {                                {
               값을              …;                                int t = 0;
               전달함            while(k- -)                        while(k--)
                                   printf("123\n");                   t += 123;
                                return; //생략 가능                 return t;//생략 불가
                               }//호출 위치로 자동 복귀           }                           



함수를 정의할 때 사용하는 void는 함수가 호출된 후 복귀할 때 호출했던 위치로 아무런 값을 가져다 놓지 않고 복귀한다는 의미이다. void를 제외한 int, float, char 등은 호출했던 위치에 그 자료형의 값을 가져다 놓으면서 복귀한다는 의미이다. return은 2가지의 의미를 가진다. ‘return;’으로 작성하는 경우에는 함수를 호출했던위치로 복귀하라는 의미이고, ‘return 값;’으로 작성하는 경우에는 함수를 호출했던 위치 에 값을 가져다 놓으며 복귀한다는 의미이다. 따라서 함수를 정의할 때 사용하는 자료형void와 int, float, char 등은 함수 호출 후 리턴되는 값의 자료형에 따라 결정된다.

재귀 함수

재귀 함수(recursive function)는 함수를 정의하는 과정에서 자기 자신을 호출하는 형태의 함수이다. 이런 재귀 함수를 정의할 수 있는 이유는 사용하기 전에 미리 그 내용을 정의한다고 컴파일러에 알려 주기 때문에 가능한 것이다. 재귀 함수는 어떤 문제 상황을 보다 작은 같은 형태의 문제 상황으로 재표현할 수 있는경우에 함수를 정의하여 효과적으로 문제를 해결할 수 있다. 재귀 함수는 문제를 보다 작은 형태로 쪼개 나가는 형태의 하향식 재귀와, 다음 상태로 키워 가는 형태의 상향식 재귀 2가지의 형태로 나누어 생각해 볼 수 있다.

문제를 쪼개 나가는 형태 다음 상태로 키워 나가는 형태 (하향식 재귀) (상향식 재귀)

                                                         int n;

int f(int k) int f(int k) { {

if(k == 1) return 1;                                        if(k == n) return n;
return k + f(k - 1);//작게 쪼개기                             return k + f(k + 1);//다음 호출

} {

재귀 함수를 설계하는 첫 번째 단계는 문제 상황 속에 들어 있는 관계를 찾아내고 그 관계를 표현하는 것이다. 그러기 위해서는 ‘재귀 함수의 의미’를 명확히 생각해야 한다. 예를 들어 ‘1~k까지의 정수 합을 계산하는 함수를 f (k)라고 한다’면,

                    f (k)=f (k -1)+ k

과 같은 관계식으로 재표현할 수 있는데, 이는 ‘1~k까지의 정수 합은 1~k-1까지의 정수 합에 k를 더한 것과 같다’는 의미로 해석할 수 있다. 마찬가지의 비슷한 아이디어로 다른 방법으로 재표현할 수 있는데, ‘k~n까지의 정수 합을 계산하는 함수를 f (k)라고 한다’면

                   f (k)=k+f(k +1)

과 같은 관계식으로 재표현할 수 있는데, 이 의미는 ‘k~n까지의 정수 합은 k에 k+1~n까지의 정수 합을 더한 것과 같다’는 의미로 해석할 수 있다. 문제 상황을 관찰한 후 답을 얻어 낼 수 있는, 자기 유사적인 관계식을 만들었다면, 재귀 함수의 호출을 ‘언제 끝내야 하는 것인가?’를 생각해야 한다.

f(k)의 의미 관계식 중단 시점 [1, n] 정수 합 하향식 점화 관계식 만약 k == 1이면 f(1)의 값은 1

               f (k) = f (k - 1) + k     if(k == 1) return 1;


[k, n] 정수 합 상향식 점화 관계식 만약 k == n이면 f(n)의 값은 n

              f (k) = k+ f (k+ 1)      if(k == n) return n;

이렇게 주어진 문제 상황에서 재귀적 관계를 찾아내고, 함수를 이용한 관계식으로 재표현한 후, 재귀 호출의 중단 시점을 명확하게 결정하였다면, 재귀 함수로 표현하여 문제 해결에 활용할 수 있다.