함수
함수를 공부하기 전에 잠깐 다른 이야기를 해보면, 사람과 컴퓨터 중 누가 더 똑똑한지 질문하면 일단은 사람이 더 똑똑하다는 것이 정답이다. 물론 의문이 들수도 있는데,
컴퓨터가 사람보다 우월한 것은 바로 속도이다. 예를 들어 "1~10 숫자를 전부 다 더하면 얼마일까" 라는 질문을 던지면 대부분의 사람들은 답이 55 라는것을 알지만
컴퓨터는 일일이 계산해서 결과를 출력하는데 이 속도는 사실상 비슷하다. 그렇다면 "1 ~ 345" 숫자를 전부 다 더하면 얼마일까" 라는 질문을 던지면
사람과 컴퓨터 모두 일일이 계산하는데, 컴퓨터는 순식간에 계산해버린다. 즉, 컴퓨터는 연산의 속도가 어마어마 하기 때문에 얼핏 보기에는 컴퓨터가 더 똑똑해 보이지만
실제로는 사람이 더 똑똑한 것이다. 굳이 함수 포스팅에서 이런 얘기를 하는 것은 함수과 컴퓨터 효율성 관의 관계이다.
컴퓨터의 연산 속도를 좌우하는 CPU의 속도는 개인용 컴퓨터의 경우 일반적으로 3.5GHz를 넘지 않는다. 그러나 서버의 경우는 어떨까?
지구촌 국가 중 95% 이상의 국가에서 서비스를 제공하는 구글의 서버를 예로 들면 3.5GHz로는 택도 없다. 최소 몇백, 몇천의 GHz가 필요한데 이걸 또 무작정
CPU를 증설하는 방법은 예산 낭비이다. CPU의 개수만큼 중요한 것이 바로 서비스 알고리즘의 효율성이다.
이해가 가질 않는 다면 이전에 살펴본 프로그램을 잠시 떠올려보자. "1 ~ 10 숫자를 전부 더 하는 프로그램" 이 있다고 가정하자.
반복문(for, while 등)을 사용하지 않으면 사람이 일일이 "1+2+3+4+5+6+7+8+9+10"을 입력해줘야 한다. 1000까지 숫자를 더하려면 1000개를 입력해야 한다.
그러나 반복문을 사용하면 몇줄 안되서 끝난다. 바로 이게 알고리즘의 효율성이다.
이제 본격적으로 함수에 대해 알아보자. 함수는 호출에 의해 실행되도록 만들어진 일련의 코드를 의미하는데, 한 프로그램 내에서 반복적으로 실행되거나
여러 프로그램에서 공통적으로 실행되는 기능들을 말한다.
위의 그림은 '함수 A'를 따로 만들어 놓고 필요할 때 마다 호출해서 사용하는 그림이다.
함수를 호출하면 함수가 실행되고, 실행이 끝나면 호출한 프로그램으로 다시 돌아온다.
main 함수 하나로 프로그램을 코딩한 것보다는 여러 함수를 이용한 프로그램이 더욱 효율적인데 이유는 다음과 같다.
1. 함수를 여러 번 호출해서 재사용 할 수 있기 떄문에 소스의 가독성이 높아지며 간결해진다.
2. 기능별로 함수를 만들 기 때문에 어떤 함수가 어떤 기능인지 알기 쉽다.
3. 다른 프로그램에서 작성한 함수를 재사용 할 수 있다.
4. 컴파일/실행 시 에러가 나면 찾기가 쉽다.
5. 유지보수가 용이하다.
이런 함수의 종류는 2가지가 있는데, 라이브러리 함수와 사용자 정의 함수로 나뉠 수 있다.
라이브러리 함수는 이미 이전의 포스팅 마다 등장했던 녀석들이다. (printf, scanf, strcat, strcpy, whlie, for, if 등등)
이런 함수들은 너무나도 자주 사용되기 때문에 OS에서 미리 정의해서 제공하는 함수이다.
이에 비하여, 사용자 정의 함수는 프로그래머가 프로그램 코딩 시 반복되는 기능을 묶어놓은 함수를 말한다.
물론, 본 포스팅에서는 사용자 정의 함수를 살펴본다.
함수의 정의와 호출
프로그램에서 함수를 사용하려면 해당 함수가 프로그램에 미리 정의되어 있어야 하고, 해당 함수를 호출하는 부분이 있어야 한다.
(없어도 되지만 그러면 만든 이유가 없다).
함수 정의는 함수가 실행할 내용을 작성한 일종의 코드의 모음이며, 함수 호출은 호출 되는 함수를 실행하란 명령이다. 아래의 사진은 간단한 함수를 정의하고
호출한 것으로, func()가 함수의 이름이며 printf("함수입니다"); 문장이 func() 함수가 실행할 내용이다.
함수의 실행 순서는 다음과 같다.
04 ~ 07 행 : func() 함수를 정의하는데 void 데이터 타입 (=void 형) 으로 선언한다.
void 형은 리턴 값이 없다는 뜻이다.
13 행 : func() 함수를 호출한다.
함수와 매개변수(파라미터)
함수를 호출할 때 어떤 정보를 넘겨줄 수 있는데 이를 매개변수(=파라미터) 라고 한다. 매개 변수가 있는 함수의 정의는 아래와 같다.
이를 이용한 프로그램은 아래와 같다.
03 ~ 06 행 : outName 이라는 함수를 정의하되, name[] 배열을 파라미터로 넘겨준다.
15 행 : outName 함수를 13 행에서 입력 받은 name 변수와 함께 호출한다.
물론 파라미터가 꼭 1개라는 법은 없다. 2개 이상의 파라미터를 가지는 경우 파라미터를 ',' 콤마로 구분한다.
03 행 : 함수 선언
12 행 : 10 행에서 입력받은 정수 2개를 파라미터로 add 함수를 호출한다.
17 ~ 21 행 : add 함수를 정의한다.
* 본 프로그램에서는 함수의 정의를 아래 부분에 하고 선언을 윗 부분에 하였다. 이와 관련해서는 바로 아랫 부부에서 자세히 다룬다.
굳이 여기서 사용한 이유는 본 프로그램과 이전의 프로그램의 가독성을 비교하기 위함이다.
함수 정의를 위해서 하는 것과 아래에서 하는 것 중 어느 프로그램이 가독성이 더 좋은지 보길 바란다.
사용자 정의 함수는 void형 함수처럼 아무것도 리턴하지 않을 수는 있지만, 특정 값을 반환시킬 수도 있다. 물론 이 경우의 경우 리턴되는 값의 데이터 형식을
함수 정의 부분에 명시해야 한다.
03 행 : int 형의 add 함수 선언 (함수 선언은 바로 아래 부분에서 나옴)
12 행 : add 함수를 호출하는데...
20 행 : add 함수의 정의 부분인데, 정수 2개를 파라미터로 받아와서 이를 더하고 더한 값을 리턴해준다.
12 행 : add 함수를 호출하는데 22 행에서 리턴 되는 add 함수의 리턴 값을 result 변수에 대입한다.
함수 선언
함수 선언이 어떤 개념인지 알아보기에 앞서 아래 2 개의 프로그램 보도록 하자.
(a) (b)
(a) 프로그램은 func 함수의 정의가 먼저 오고, 그 다음에 main 함수 내에서 func 함수를 호출 한다.
(b) 프로그램은 main 함수 내에서 func 함수 호출을 먼저 하고, 다음에 func 함수의 정의가 온다.
C 언어는 컴파일러를 사용하여 실제 실행되는 프로그램을 만드는데, 컴파일러는 위에서부터 아래로 컴파일을 진행하기 때문에
(a)의 경우 main 함수 내에서 func 함수 호출을 만나면 이미 이전에 func 함수가 정의되어 있기 때문에 별다른 문제가 발생하지 않는다.
그러나, (b)의 경우 main 함수 내에서 func 함수 호출이 먼저 나오고 그 뒤에 func 함수 정의가 오기 때문에 컴파일러는 func 함수가 정의되지 않았다고 생각하여
에러가 발생한다.
위와 같은 경우 (b) 프로그램에서 사용할만한 방법이 함수 선언을 이용하는 것이다. 함수 선언은 함수 호출 전에 어떤 함수가 정의되었는지를 미리 알려주는
역활을 하는데, 사용 형식은 다음과 같다.
함수 선언을 이용하면 (b) 프로그램을 제대로 동작하게 만들면 아래와 같아진다.
위와 같이 함수 선언을 사용하면 아무런 문제없이 실행된다. 그리고 함수 선언에서의 파라미터 리스트 역시 데이터 타입과 변수 이름으로 구성되는데,
함수 정의와는 달리 변수 이름은 생략해도 된다.
int func(int) ;
즉, 위와 같이 선언해도 별 문제는 없으나 프로그램의 가독성을 위해 생략하지 않는것이 바람직하다.
만약 아직까지도 "왜 함수 선언을 사용하는가" 를 모르겠다면 (사실 1개의 함수로는 무리가 있음) 아래의 프로그램을 보자.
main 함수를 포함한 5 개의 함수를 사용하는 프로그램이다.
03 ~ 06 행 : 4 개의 함수를 선언한다.
14 ~ 17 행 : 파라미터를 각 함수 별로 넘긴 뒤 리턴값을 출력한다.
22 ~ 40 행 : 각 함수를 정의한다.
* 이제 함수 선언을 사용하는 이유를 알 것이다. 사실 프로그램에서 가장 중요한 부분은 main (이름도 메인) 함수이다.
즉, main 함수를 위쪽에 위치시킴으로써 프로그램의 전체적 흐름을 알아보기 쉽게 하고,
기능을 각 함수벼로 나누어 마지막에 위치시킴으로써 어떤 함수가 어떤 기능인지 알아보기 쉽게 한다.
재귀 함수
재귀 함수는 자기 자신을 호출하는 함수를 의미한다.
04 행 : 자기 자신은 func 함수를 호출하는데 이를 '재귀호출' 이라고 하며, 재귀 호출하는 func 함수를 '재귀함수' 라고 한다.
09 행 : func 함수를호출하면 04 행의 01 행의 func 함수를 호출하고, 03 행에서 "Hello World" 가 출력되고 다시 04 행에서 func 함수를 호출한다.
위의 과정을 그림으로 나타내면 다음과 같다.
즉, 위와 같은 프로그램은 계속 자기 자신을 호출하면서 별 다른 종료 조건을 주지 않았기 때문에 무한적으로 실행된다.
따라서 재귀 함수는 반드시 종료 조건이 있어야 한다.
종료 조건을 입력한 프로그램은 다음과 같다.
< 1 부터 입력한 수(n) 까지 합을 구하는 프로그램 >
12 행 : 끝부분 sum(num) 부분에서 10 행에서 입력받은 nun 값을 파라미터로 넘겨준다.
19 행 : 12 행에서 입력받은 num이 1이면 1을 돌려준다.
22 행 : 1 이 아닐 경우 입력받은 num 숫자 + 재귀함수를 통해 (num-1) 결과를 더한 값을 돌려준다.
즉, 3 이 입력되었다고 가정하면,
3 입력
3 + sum(n-1) ==> 3 + sum(2)
3 + 2 + sum(2-1) ==> 3 + 2+ 1
'Developing > C 언어' 카테고리의 다른 글
[C언어 강의 - 15] 표준 입출력 (0) | 2014.06.01 |
---|---|
[C언어 강의 - 14] 기억클래스, 변수 (2) | 2014.05.10 |
[C언어 강의 - 12] 배열 (0) | 2014.05.09 |
[C언어 강의 - 11] 제어문 (0) | 2014.05.08 |
[C언어 강의 - 10] 반복문 (1) | 2014.05.08 |