티스토리 뷰

C언어

C 제9강 - 함수 활용하기

쉬엄쉬엄하자 2020. 2. 19. 16:52
728x90

안녕하세요 이번에는 C언어에서 기본적인 함수 활용법에 대해서 알아보겠습니다. 이 내용까지 다 익히고 나면 이제 C언어에서의 기본적인 부분은 모두 익혔다고 볼 수 있습니다. 그래서 이번 포스팅을 마치면 간단한 프로젝트를 기획하고 제 블로그에 방문해주시는 분들이 직접 구현할 수 있도록 명세서를 올릴까 생각중입니다. 물론 제가 블로그에서 다룬 내용만 활용하여 구현할 수 있는 프로그램이 될 것입니다.

 

서론이 길었습니다. 본론으로 와서 프로그래밍 언어에서 함수의 활용은 반복적으로 수행하는 작업을 자동화하고 코드를 간결하게 만드는 효과가 있습니다. 예를 들어 내가 계산기 프로그램을 만들고 싶다고 했을 때 덧셈, 뺄셈 등 연산작업을 해주는 코드는 필요할때마다 계속해서 반복적으로 사용해야 합니다. C언어의 특성상 위에서부터 아래로 순서대로 코드가 실행되기 때문에 필요한 시점에 위에서 구현한 연산작업 코드의 시작점으로 위치를 옮길수가 없습니다. 이러한 이유 때문이라도 함수사용은 복잡한 프로그램을 제작할수록 필수적입니다.

 

1.함수의 기본

모든 함수 활용법에 대해 익히기전에 함수와 관련된 용어를 먼저 알아보도록 하겠습니다.

 

정의 : 함수를 구현하는 그 자체를 말합니다. 함수의 기본형식과 함수 내부의 코드를 작성하는 것을 말합니다.

 

선언 : 함수를 사용하기 위해 C언어 컴파일러가 이해할 수 있도록 사전에 전달하는것을 말합니다.

 

호출 : 정의한 함수를 사용하는것을 말합니다. 

 

반환 : 함수를 호출한뒤 함수내부의 모든 코드를 수행하고 종료되면서 호출한 시점에 결과값을 전달하는것을 말합니다.

 

매개변수 : 함수를 호출할 때 함수내부에서 사용할 변수를 말합니다.  일반 변수와 마찬가지로 자료형 + 변수명의 형식으로 이루어져있습니다. 예시로 덧셈을 위한 함수를 정의한다고 하면 덧셈의 피연산자 int형 변수 2개를 매개변수로 받아 두개의 수를 더한 결과를 반환한다고 볼 수 있습니다.

 

여기까지가 함수에 대한 이해를 위한 기본적인 용어들입니다. 이제 이 용어들을 사용해서 함수의 사용법에 대해 알아보겠습니다.

 

2. 정의

먼저 함수를 정의하는 방법에 대해 알아보겠습니다. 함수의 정의는 먼저 함수의 기본형을 정의하고 그 후에 중괄호 사이에 함수의 내용을 정의합니다. 2개의 int형 매개변수를 갖고 두 수의 합을 반환하는 덧셈함수의 정의를 예시로 보겠습니다.

int sum(int num1, int num2){//제일 윗줄에 함수의 기본형을 정의합니다.
	return num1 + num2;//중괄호 사이에 함수의 내용을 정의합니다.
}

함수의 기본형을 정의하기 위해서 필요한 것은 먼저 반환값의 자료형입니다. 가장 앞에 반환값의 자료형을 입력하고 그 뒤에 함수의 이름을 정의합니다. 그 다음으로는 소괄호안에 필요한 매개변수들을 정의합니다. 따라서 함수의 기본형을 정의하는데 필요한 내용을 정리해보면

반환값자료형 함수이름(매개변수자료형 매개변수명, ----- ) 입니다. 위에서 예시로 정의한 함수의 기본형에서 반환값의 자료형은 int형이고 함수이름은 sum, 매개변수는 int형 변수 num1, num2가 되는것입니다. 이렇게 매개변수를 정해주면 함수내부에서 변수를 선언하지 않더라도 매개변수는 변수를 선언한 것처럼 사용할 수 있습니다. 

 

중괄호 사이에는 함수의 내용을 정의합니다. 위 예시에서는 두 매개변수의 합을 구하는것이 전부이므로 바로 두 매개변수의 합을 반환하였습니다. 여기서 함수의 결과를 반환할 때 쓰는 키워드는 위 예시처럼 return 을 사용하여야 합니다.

return 뒤에 위 예시처럼 수식이 와도 되고 변수만 와도 됩니다. 어떤식이든 함수의 기본형에서 정의한 자료형을 가지는 값을 return키워드 뒤에 오게 하면 됩니다. 그러면 위 sum함수의 정의와 내용은 같지만 구현방식은 다른 예시를 하나 더 보겠습니다.

 

int sum(int num1, int num2){
	int result;
	result = num1 + num2;
	return result;
}

이 함수는 위에서 정의한 함수와 같은 기능을 수행하는 함수 입니다. 다만  return 뒤에 수식이 바로오지 않고 덧셈의 결과를 함수내부의 변수에 저장한뒤 이 변수의 값을 return 뒤에 오도록 한것입니다. 이런식으로 같은 내용의 함수더라도 다른 방식으로 정의할 수 있습니다.

 

+추가적으로 반환값을 가지지 않는 함수는 어떻게 정의하는지 알아보겠습니다.

void printf_func(){
    printf("반복 출력할 내용\n");
}

이런식으로 덧셈과 같은 연산작업이나 계산작업이 아닌 단순 반복적인 출력을 위해 함수를 사용하는 경우도 있습니다. 이럴 경우에는 어떤 반환값도 없고 필요한 매개변수도 없습니다. 반환값이 없음을 정의할 때는 자료형 대신 void 라는 키워드를 사용합니다. 그리고 매개변수가 없는 함수라면 비어있는 상태로 소괄호만 입력합니다.

3. 선언

이제 정의한 sum함수를 선언하는 법을 알아보겠습니다. 선언에 대해 이해하기 위해서 먼저 알아야 할 것은 C언어의 컴파일러(*c언어의 문법을 해석해 컴퓨터에게 알려주는 프로그램) 는 위에서 아래로 코드를 해석해 나갑니다. 그리고 C언어로 작성된 프로그램은 가장 먼저 main함수를 자동으로 실행되게 되있습니다. 여기서 main함수는 지금까지 우리가 예시를 작성해왔던 함수이름이 main인 기본적으로 정의되어 있는 함수를 말합니다. 

따라서 만약 우리가 정의한 새로운 함수가 main함수보다 아래에 정의되어 있다면 컴파일러는 main함수를 먼저 해석해 나가기 때문에 우리가 정의한 sum함수의 존재를 알지 못합니다. 그래서 컴파일러에게 sum함수의 존재를 알려주기 위해 main함수보다 더 위에 정의한 sum함수를 선언해줘야 합니다. 변수를 선언해준것처럼 말이죠. 

 

함수를 선언하는 방법은 아주 간단합니다. 우리가 정의했던 함수의 기본형을 써주면 끝입니다. 바로 예시를 보면

int sum(int i, int j);

함수의 기본형인  반환자료형 함수명(매개변수1, 매개변수2); 를 코드에 입력해주면 함수의 선언이 정상적으로 이루어진 것입니다. 여기서 중요한점은 변수를 선언했을때와 동일하게 코드의 끝에 세미콜론 ; 을 붙여줘야 한다는 것입니다.

그리고 함수를 정의할때는 매개변수로 int num1, int num2라는 변수명을 사용하였지만 선언부 에서는 i, j를 사용하였습니다. 즉 함수를 정의할때와 선언할때는 매개변수명이 동일하지 않아도 되고 자료형만 같으면 됩니다. 선언부에서는 심지어 변수명을 아예 입력하지 않아도 됩니다.

int sum(int , int);

이렇게 함수를 선언하여도 이는 올바른 함수의 선언입니다. 하지만 보편적으로 함수를 선언할 때 매개변수명까지 동일하게 작성하여 함수를 선언하는것이 좋은 습관입니다. 모든 프로그램의 코드를 작성할 때는 기본적으로 내가 작성한 코드를 다른사람이 봤을 때 이해하기 쉽도록 하는것이 좋은 코딩의 습관이기 때문입니다. 때문에 주석도 내가 나중에 보기위함도 있지만 다른사람이 코드를 이해하는데에 도움을 주기위해 작성하는 요인이 더 큽니다.

 

4.호출과 반환

이제 마지막으로 함수를 호출하고 반환값을 가져오는 방법에 대해 알아보겠습니다. 예시로 main함수에서 sum함수를 호출하고 이 sum함수의 결과를 main내부에 있는 새로운 int형 변수에 저장하는 것을 보겠습니다.

 

int sum(int num1, int num2);

int main()
{
    int result1, result2, result3;
    int a = 9999;
    int b = 1;
    result1 = sum(5, 5);//상수를 매개변수로 호출
    result2 = sum(a, b); //변수를 매개변수로 호출
    result3 = sum(a+b, 30);//수식과 상수로 매개변수 호출
    printf("%d %d %d\n", result1, result2, result3);
    printf("%d\n", sum(10, 25));
}

int sum(int num1, int num2){
	return num1 + num2;
}

result1, result2, result3 총 세개의 int 형 변수를 main함수 안에서 선언하고 각 변수에 sum을 세번 호출하여 반환값을 저장하였습니다. 그러면 결과는 각각 5+5, a+b, a+b+30이 저장됩니다. 예제 코드처럼 함수를 호출 할 때는 함수의 기본형에 맞춰 함수이름과 소괄호안에 매개변수를 입력하면 됩니다. 이 때 기본형에서 int형 매개변수를 받도록 함수를 정의하였으므로 해당 매개변수 자리에는 상수, 변수, 수식 뭐든 상관없이 int형의 자료형을 가지기만 하면 됩니다. 그리고 반환값 역시 int를 반환하도록 정의하였기 때문에 반환값을 저장할 변수도 int형이어야 합니다.

 

또 주의해야할 점은 함수의 호출과 반환에서도 이전 포스팅에서 배웠던 형변환이 자동적으로 이루어지게 되므로 이를 고려하여 함수를 호출하고 반환해야합니다.

12번째줄 코드처럼 변수에 반환값을 저장하는것이 아닌 바로 함수의 반환값을 printf함수를 호출할 때 매개변수로 전달하는것도 가능합니다.

 

5. 재귀호출

바로 위에서 printf문을 호출할 때 매개변수로 sum함수를 호출하여 반환값을 넣어줬습니다. 그렇다면 sum함수를 호출할 때의 매개변수로 sum함수를 호출하면 정상적으로 실행될까요? 

물론 잘 실행 됩니다. sum함수는 int 형을 반환하고 int 형 매개변수를 가지고 있기 때문에 sum(a, sum(a,b) ) 이런식의 호출도 가능합니다.

 

그렇다면 sum함수 내부에서 sum함수를 호출하면 어떻게 될까요? 이것 역시 가능합니다. 함수내부에서 자기자신을 호출하는것을 프로그래밍에서는 재귀호출이라고 칭합니다. 바로 예시를 보겠습니다.

 

int recursive_func(int a){
	int mul = a*a;
    return recursive_func(mul);
}

재귀호출을 하는 함수의 예제 코드입니다. 여기서 매개변수로 int형을 받고 a의 제곱을 변수에 저장한뒤 이 값을 자기자신 함수의 매개변수로 재호출한 값을 반환합니다. 그럼 여기서 매개변수 a에 3을 전달하여 main함수에서 호출하면 결과는 몇일까요??

정답은 결과는 나오지 않는다입니다. 저런식으로 재귀호출을 할 경우 함수는 최종적으로 결과를 내놓지 못하고 무한정 자기자신을 호출 하며 끝나지 않게됩니다. 따라서 재귀호출을 이용하여 기능을 구현할 때는 반드시 재귀호출이 멈추는 기점을 명시하여야 합니다. 예제 코드를 올바르게 수정한 재귀호출 방법은 다음과 같습니다.

 

int recursive_func(int a){
	int mul = a*a;
    if(mul > 1000000000)
        return mul;
    else
        return recursive_func(mul);
}

재귀호출을 무한히 호출되지 않도록 mul변수가 10억이 넘어가게되면 재귀호출을 하지 않고 mul변수를 반환하도록 하였습니다. 그래서 만약 최초의 호출에서 10을 매개변수로 호출하였다면 mul의값은

10 * 10 -> 100 * 100 -> 10000 * 10000 -> 100000000 * 100000000 까지 호출되며 1억 * 1억을 반환하게 됩니다. 이론상으로는 이 값을 반환해야겠지만 직접 실행해보신다면 1억*1억을 결과로 내놓지는 않을 것입니다. 이에 대한 이유는 추후에 각 자료형의 바이트수가 가지는 의미에 대해 다뤄볼때 설명하도록 하겠습니다.

 

이제 함수를 활용하는 기초적인 방법에 대해 모두 알아보았습니다. 앞서 처음에 예고했듯이 다음 포스팅에서는 보편적으로 기초단계의 프로그래밍 지식만을 활용하여 수행해보는 프로젝트의 명세를 올리고 해당 글을 보시는분들이 직접 구현해보는 시간을 가져보겠습니다.

댓글