C 언어(18) - 함수

C 언어 강의 - 함수

Featured image

🔚 짧게 하는 복습

✅ 1. 포인터 배열이 무엇인지 안다.

✅ 2. 포인터 배열을 응용해서 다차원 배열을 구현해보자.

혹시 기억이 안 난다면, 다시 돌아가자


이때까지 복잡한 포인터와 배열에 대해서 다루었다.

꼭꼭 어느 부분에 개념이 있다면 복습을 잘했으면 좋겠다.

특히 포인터는 앞으로의 설명에도 많이 쓰이기 때문이다.

자, 오늘부터는 새로운 개념에 대해 다룰 생각이다.

우리는 최댓값을 구하는 알고리즘에 대해 다룬 적이 있다. 과제 부분 참고

int a, b;

int max = a;

if(a>b){
    max = a;
}
else{
    max = b;
}

똑똑한 학생이라면 이렇게 짧게도 할 수 있다.

int a, b;

int max = (a > b) ? a : b;

우리는 후자를 이용해서 4가지 정수의 값 중 최댓값을 구하는 코드를 짜보자.

int a, b, c, d;

int max1 = (a > b) ? a : b;
int max2 = (c > d) ? c : d;

int max = (max1 > max2) ? max1 : max2;

그런데 이거 생각보다 훨씬 귀찮다. (눈치챈 사람도 있겠지만 배열과 for문을 이용하면 쉽게 할 수 있다.)


함수란?

우리는 이러한 일련의 절차를 해결하는 일을 간단하게 처리하고 싶다.

우리는 이럴 때 함수라는 것을 사용한다.

함수를 선언할 때는 정의라는 말을 대신 사용하는데, 함수 정의는 (반환 자료형) (함수 이름)(자료형1 매개변수1, 자료형2 매개변수2, 자료형3 매개변수3 …){정해진 작업}로 한다.

또한 함수 정의는 int main보다 위에 해야한다.

반환은 뭐고, 매개변수는 뭔지 어려운 말들이 가득한데, 우선 함수의 개념부터 정확하게 알아보자.

함수란 수학을 해본 사람은 알겠지만, 어떠한 일련의 입력값을 받아서 정해진 동작을 한 후 출력을 반환하는 것이다.

수학에서 쓰이는 함수를 예를 들면, y = 4x+3이라고 하자.

컴퓨터로 치면, 입력값(x)는 매개변수라고 하고, 정해진 동작(4를 곱해서 3을 더함)을 한 후 출력된 y를 반환 값이라고 한다.

이 모든 절차를 함수라고 할 수 있다. 물론 매개변수는 여러 개가 될 수 있다. 하지만 반환 값은 오직 하나의 자료형 혹은 배열, 구조체, 공용체(아직 안 배웠지만), 함수 로 정해져야 한다.


함수 정의 예제(최댓값 찾기)

위의 최댓값을 구하는 과정을 함수로 만들어보자.

우선 입력해야 할 것은 정수 2개이니까, 매개변수로 num1, num2라는 것을 입력받는다.

우리가 정하는 과정은 둘 중 큰 값을 찾는 것이니까, if, else로 정한다.

출력값은 둘 중 큰 값이니까 ret이란 변수에 담아서 반환해보겠다.

반환은 return을 이용하면 된다.

int max(int num1, int num2){
    int ret = 0;

    if(num1 > num2){
        ret= num1;
    }
    else{
        ret = num2;
    }

    return ret;
}

그런데 여기서 사실 ret이라는 변수는 필요 없다. 아래와 같이 함수를 정의할 수 있기 때문이다.

int max(int num1, int num2){
    if(num1 > num2){
        return num1;
    }
    else{
        return num2;
    }
}

그리고 2번째 알고리즘을 이용하면, 더 축약할 수도 있다.

int max(int num1, int num2){
    return (num1> num2) ? num1 : num2;
}

지금까지 함수를 정의했으니까 사용해보자. 함수를 사용하는 것을 호출이라고 하고 함수 이름(매개변수1, 매개변수2, …)을 적어서 사용할 수 있다.

아래의 코드를 실행해보자.

훨씬 코드가 간단해지고 명확해진 모습이다. (함수의 이름도 변수의 이름처럼 누가봐도 알기 쉽게 정하는 것이 좋다.)

그런데 함수의 매개변수로 함수의 반환 값을 넣을 수도 있다. 아래의 코드를 보자.

좋은 코드는 아니지만, 이런 것도 가능하다는 것을 보여주는 코드이다.


함수를 정의하는 두 번째 방법

만약 우리가 계산기를 만드는 코드를 적는다고 하자.

위 코드를 보면 int main위에 함수를 정의한다고 상당히 많은 줄이 소모되었다.

그런데 실제로 대규모 프로젝트를 사용하면 훨씬 더 많은 함수가 사용된다.

이런 경우 main함수 위에 함수를 모두 정의하면 오히려 역으로 본 프로그램의 코드를 찾기 힘들어진다.

그래서 아래와 같이 함수를 정의할 수 있다.

함수 정의, (반환 자료형) (함수 이름)(자료형1 매개변수1, 자료형2 매개변수2, 자료형3 매개변수3 …){정해진 작업}에서 {정해진 작업}을 뺀 것을 함수 원형이라고 하고, int main 위에는 함수 원형만 적고 아래에 자세한 내용을 적을 수 있다.

이렇게 적으면 훨씬 읽기 편한 코드가 작성된다.

그런데 int main..? 이것도 함수인가?


int main이란?

우리가 이때까지 int main이라고 한 이 블록도, 사실 하나의 큰 함수이다.

main 함수라고 부르고 프로그램에서 제일 중요한 함수이다.

컴퓨터가 프로그램을 실행하면 가장 먼저 찾는 것이 이 main 함수이고, main 함수를 실행시키는 것이 결국 프로그램이 하는 일이다.

또한, 이것이 마지막에 return 0; 적는 이유이고, 사실 0이 아니라 아무 값이나 반환해도 된다.

그런데 0을 적는 이유는 프로그래머들의 관습에서 유래했다. 함수를 정의할 때 0 반환은 성공적인 종료, -1 반환은 오류 발생으로 정의했기 때문이다.


void 반환 함수란?

저번 강의에 더 읽어보기에 잠깐 담았었는데, 사실 void*형이라는 특수한 자료형이 있었다.(엄밀하게 말하면 자료형은 아니지만)

void란 단어는 영어로 ‘비어있는’이라는 뜻을 가지는데, 함수의 반환 값으로 쓰일 때는 아무것도 반환하지 않음을 의미한다.

이게 무슨 말이냐 하면, 위에서 사용했던 계산기 코드에 1~4가 아닌 다른 값을 넣으면 경고를 출력하는 코드를 만들어보겠다.

위 코드에서 볼 수 있듯 경고를 출력하는 함수는 반환 값이 없다. 그렇기에 void를 써서 함수를 정의할 수 있다.


함수를 쓰는 이유

함수를 쓰는 이유는 간단하게 말하면 가독성을 높인다는 점이다.

조금 자세하게 풀어서 말하면, 일단 소스 코드의 중복성을 줄인다. 비슷한 코드가 불필요하게 반복되면 읽기가 어렵다.

또한, 함수를 한 번 정의하면 어디서든 재사용이 가능하다. 이는 추후 강의에 나오겠지만 다른 프로그램조차 정의된 함수를 사용할 수 있다.

마지막으로는 복잡한 문제를 단순하게 분해할 수 있는데, 예를 들어 계산기 코드처럼 큰 틀을 이용해서 각각의 부분을 함수로 정의해서 사용할 수 있다.


📖 오늘의 핵심(다 알기 전까지는 넘어가지 말자❗)

✅ 1. 함수를 정의하고 호출할 수 있다.

✅ 2. main함수의 존재 이유에 대해 안다.

✅ 3. 함수를 쓰는 이유에 대해 안다.

⚠️ 함수 정의 안에 다른 함수를 쓸 수 있는데, 반드시 위에서 정의된 함수만 사용할 수 있다. (읽어볼 거리 참고)

⚠️ 또한 함수의 반환값으로도 함수를 쓸 수 있는데, 다른 함수를 반환하는 함수는 되도록 사용하지말자. (특히, 같은 함수, 즉 스스로를 반환하는 함수를 재귀함수라고 하는데 이를 알아보자, 읽어볼 거리 참고)

💣 과제,

  1. 원의 반지름을 입력받아서 각각 둘레, 넓이를 구하는 함수를 만들어보자(난이도 下)

  2. 임의의 정수 n을 입력받아 factorial n을 구하는 함수를 만들어보자(난이도 下)

🔜 더 공부해보기,

  1. 읽어볼 거리(1) - 함수 정의의 순서

  2. 읽어볼 거리(2) - 재귀함수란?