C, C++ 언어

C언어 기초 12. 함수

게임플밍마스터 2025. 10. 17. 11:44

지금까지 우리는 main이라는 커다란 작업실 안에서 모든 일을 처리해 왔습니다. 작은 프로그램을 만들 때는 이것으로 충분했지만, 집을 짓거나 자동차를 만드는 것처럼 복잡한 프로그램을 만든다고 상상해 보세요. 한 공간에서 수만 가지 부품을 만들고 조립하는 것은 비효율적이고 혼란스러울 것입니다.

파트 4에서는 프로그램을 '엔진 부서', '디자인 부서', '전기 부서'처럼 기능별로 나누고, 관련된 데이터들을 하나의 의미 있는 단위로 묶는 방법을 배웁니다. 이를 통해 우리는 코드를 재사용하고, 관리하기 쉬우며, 다른 사람과 협업하기 좋은 '잘 설계된' 프로그램을 만들 수 있게 될 것입니다. 그 위대한 첫걸음이 바로 '함수'입니다.


생각보다 프로그래밍하는 개념이 확장되는 부분이니 좀 어렵게 느껴질 수 있습니다. 문법이 어려운것이 아니라 생각의 확장 부분이 어렵게 느껴질 수 있으니 많이 예제를 풀어 보면서 생각을 확장하는것이 중요한 부분입니다. 저도 처음 배울때 아주 낮은 허들처럼 느껴지면서 약간 어려웠던 기억이 나네요.

 

우리가 계산기를 사용할 때, sin 버튼을 누르면 그 안에서 어떤 복잡한 수학 공식이 실행되는지 몰라도 사인 값을 얻을 수 있습니다. 우리는 그저 'sin 버튼은 사인 값을 계산해준다'는 기능만 알면 되죠.

함수(Function) 는 바로 이 계산기의 버튼과 같습니다. 특정 기능을 수행하는 코드 뭉치에 이름을 붙여놓고, 필요할 때마다 그 이름을 불러다 사용하는 것입니다. printf나 scanf 역시 C언어가 미리 만들어 제공하는 함수들이죠. 이번 장에서는 우리가 직접 우리만의 함수, 우리만의 버튼을 만드는 방법을 배워보겠습니다.

1. 왜 함수를 사용해야 할까요?

main 함수에 모든 코드를 다 작성할 수도 있는데, 굳이 함수를 만들어 쓰는 이유는 무엇일까요?

  1. 코드의 재사용성: 똑같은 작업을 여러 곳에서 해야 할 때, 그 작업을 함수로 만들어두면 필요할 때마다 함수를 호출하기만 하면 됩니다. 코드가 훨씬 간결해지고, 수정이 필요할 때도 그 함수 하나만 고치면 되니 매우 효율적입니다.
  2. 코드의 구조화: 복잡한 프로그램을 잘게 쪼개어 각각의 기능별로 함수를 만들면, 전체적인 코드의 구조를 파악하기 쉬워집니다. main 함수는 각 기능 함수들을 순서대로 호출하는 지휘자(오케스트라의 지휘자처럼) 역할만 하게 되어, 프로그램의 전체 흐름이 한눈에 들어옵니다.
  3. 관리의 용이성: 함수는 독립적인 작업 단위이므로, 문제가 발생했을 때 어떤 함수에서 문제가 생겼는지 찾아내기가 훨씬 수월합니다. 즉, 디버깅이 쉬워집니다.

2. 함수 만들기(정의)와 사용하기(호출)

함수를 사용하는 것은 '만들기(정의)'와 '사용하기(호출)' 두 단계로 나뉩니다.

함수 정의(Definition):

함수가 어떤 일을 할지 구체적인 코드를 작성하는 과정입니다.

반환_자료형  함수_이름 (매개변수_목록)
{
    // 함수의 기능을 수행하는 코드
    return 반환값; // 반환_자료형이 void가 아닐 경우
}
  • 반환 자료형 (Return Type): 함수가 작업을 마친 뒤, 자신을 호출한 곳에 돌려줄 값의 자료형입니다. 돌려줄 값이 없으면 void라고 씁니다.
  • 함수 이름 (Function Name): 함수의 기능을 잘 나타내는 이름으로 짓습니다.
  • 매개변수 (Parameter): 함수가 작업을 수행하는 데 필요한 값을 외부(호출한 곳)로부터 전달받는 통로입니다. (int a, int b) 와 같이 자료형과 변수 이름을 짝지어 씁니다. 필요한 값이 없으면 (void)라고 씁니다.
  • return: 함수의 실행을 마치고 반환값을 호출한 곳으로 돌려주라는 명령입니다.

함수 호출(Call):

잘 정의된 함수를 이름으로 불러 사용하는 과정입니다.

예제: 두 정수의 합을 구하는 add 함수

#include <stdio.h>

// 1. add 함수의 정의
int add(int a, int b) // int형 값 2개를 매개변수로 받아, int형 값을 반환하는 add 함수
{
    int sum = a + b;
    return sum; // 계산 결과인 sum을 호출한 곳으로 돌려준다.
}

int main(void) 
{
    int result;

    // 2. add 함수의 호출
    result = add(10, 5); // 10과 5를 '인자'로 전달하여 add 함수를 호출하고, 반환값을 result에 저장

    printf("10과 5의 합은 %d입니다.\\n", result);
    return 0;
}

매개변수(Parameter) vs 인자(Argument)

  • 매개변수: 함수를 정의할 때 괄호 안에 선언된 변수들 (int a, int b). 외부로부터 값을 받을 '자리'나 '그릇'을 의미합니다.
  • 인자: 함수를 호출할 때 괄호 안에 실제로 전달하는 값들 (10, 5). '실제 데이터'를 의미합니다.

3. 컴파일러에게 미리 알려주기 - 함수 선언

C언어 컴파일러는 위에서 아래로 순서대로 코드를 읽습니다. 만약 main 함수에서 add 함수를 호출했는데, 컴파일러가 아직 add 함수의 정의를 보지 못했다면 "add? 그게 뭔데?"라며 오류를 발생시킵니다.

이를 해결하는 방법은 두 가지입니다.

  1. 방법 1: add 함수처럼 사용할 모든 함수를 main 함수보다 위쪽에 정의하는 것. (간단한 프로그램에 적합) - 우리는 처음 c언어 실습을 진행할 때는 이 방법을 사용할 예정입니다.
  2. 방법 2 (권장): main 함수 위쪽에 함수 선언(Function Declaration) 또는 함수 원형(Prototype)을 미리 적어두는 것. - 나중에는 이것을 모두 .h 에 넣어 #include 하는 방법을 사용합니다.

함수 선언은 컴파일러에게 "이런 모양의 함수가 아래 어딘가에 있으니, 오류 내지 말고 일단 넘어가 줘!" 라고 미리 알려주는 예고장과 같습니다.

// 함수 선언 형식: 반환_자료형 함수_이름(매개변수_자료형_목록);
int add(int, int); // 또는 int add(int a, int b);

함수 선언을 사용한 예제 구조:

#include <stdio.h>

// 함수 선언 (Prototype)
int add(int a, int b);
void print_hello(void);

int main(void) 
{
    // 이제 main 함수가 위에 있어도 함수들을 자유롭게 호출할 수 있다.
    int result = add(10, 5);
    printf("합계: %d\\n", result);
    print_hello();
    return 0;
}

// 함수 정의 (Definition)
int add(int a, int b) 
{
    return a + b;
}

void print_hello(void)  // 반환값과 매개변수가 모두 없는 함수
{
    printf("Hello, Function!\\n");
}

이 구조는 main 함수에서 프로그램의 전체적인 흐름을 먼저 보여줄 수 있어 가독성이 높고, 더 체계적입니다.

4. [도전! 프로그래밍] 나만의 계산기 함수 만들기

지금까지 배운 내용을 총동원하여, 기능별로 함수를 사용하는 계산기 프로그램을 만들어 봅시다.

요구사항:

  1. 덧셈, 뺄셈, 곱셈, 나눗셈을 수행하는 4개의 함수를 각각 정의하세요.
    • double add(double a, double b)
    • double subtract(double a, double b)
    • double multiply(double a, double b)
    • double divide(double a, double b) (나눗셈 시 0으로 나누는 경우는 고려하지 않아도 됩니다.)
  2. main 함수에서는 사용자로부터 두 개의 숫자와 연산자(+, -, *, /)를 입력받습니다.
  3. if문 또는 switch문을 사용하여 사용자가 선택한 연산자에 따라, 위에서 만든 함수 중 알맞은 함수를 호출합니다.
  4. 호출된 함수가 반환한 결과값을 출력합니다.

이 도전을 통해 여러분은 프로그램의 '인터페이스(UI)' 부분과 '로직(계산)' 부분이 함수를 통해 어떻게 아름답게 분리되는지 경험하게 될 것입니다.


이번 장 정리

  • 함수는 특정 기능을 수행하는 코드 뭉치로, 재사용성, 구조화, 관리 용이성을 높여줍니다.
  • 함수를 만드는 것을 정의(Definition), 사용하는 것을 호출(Call) 이라고 합니다.
  • 매개변수는 함수가 외부로부터 받는 값의 통로, 인자는 호출 시 실제로 전달하는 값입니다.
  • *return*은 함수의 결과를 호출한 곳으로 돌려줍니다. 반환값이 없으면 자료형을 **void*로 씁니다.
  • 함수를 main보다 아래에 정의할 경우, main 위쪽에 **함수 선언(Prototype)**을 해주어야 합니다.

이제 여러분은 코드를 기능별 서랍에 깔끔하게 정리하는 방법을 배웠습니다. 다음 장에서는 '같은 종류의 데이터 여러 개'를 하나의 이름으로 묶어서 관리하는 매우 중요한 도구, 배열에 대해 알아보겠습니다.