핵심 정리

함수에서 가변 인자 사용하기

함수의 매개변수 개수가 정해지지 않은 방식을 가변 인자(가변 인수)라고 합니다. 단, 고정 매개변수는 1개 이상 있어야 합니다.

반환값자료형 함수이름(자료형 고정매개변수, ...)
{
}

가변 인자는 stdarg.h 헤더 파일에 정의된 va_list, va_start, va_arg, va_end로 사용합니다(그림 65-1, 그림 65-2 참조).

  • va_list: 가변 인자 목록. 가변 인자의 메모리 주소를 저장하는 포인터입니다.
  • va_start: 가변 인자를 가져올 수 있도록 포인터를 설정합니다.
  • va_arg: 가변 인자 목록 포인터에서 지정된 자료형만큼 값을 가져온 뒤 포인터를 순방향으로 이동시킵니다(다음 인자의 위치로 이동).
  • va_end: 가변 인자 처리가 끝났을 때 포인터를 NULL로 초기화합니다.
// 가변 인자 함수 선언 및 정의
void printNumbers(int args, ...)    // 가변 인자의 개수를 받음, ...로 가변 인자 설정
{
    va_list ap;    // 가변 인자 목록 포인터

    va_start(ap, args);    // 가변 인자 목록 포인터 설정
    for (int i = 0; i < args; i++)    // 가변 인자 개수만큼 반복
    {
        int num = va_arg(ap, int);   // int 크기만큼 가변 인자 목록 포인터에서 값을 가져옴
                                     // ap를 int 크기만큼 순방향으로 이동
        printf("%d ", num);          // 가변 인자 값 출력
    }

    va_end(ap);    // 가변 인자 목록 포인터를 NULL로 초기화
}

// 가변 인자 함수 호출
printNumbers(1, 10);
printNumbers(2, 10, 20);
printNumbers(3, 10, 20, 30);
printNumbers(4, 10, 20, 30, 40);

함수의 재귀호출

함수 안에서 함수 자기자신을 호출하는 방식을 재귀호출이라 합니다. 재귀호출은 알고리즘을 구현할 때 자주 사용합니다.

// 재귀호출로 팩토리얼을 구하는 함수
int factorial(int n)
{
    if (n == 1)      // n이 1일 때
        return 1;    // 1을 반환하고 재귀호출을 끝냄

    return n * factorial(n - 1);    // n과 factorial 함수에 n - 1을 넣어서 반환된 값을 곱함
}

재귀호출은 반드시 정지 조건을 만들어주어야 합니다. 정지 조건이 없으면 함수가 계속 호출되다가 스택 오버플로우 에러가 발생합니다.

함수 포인터 사용하기

함수 포인터는 함수를 저장하는 포인터를 뜻합니다. 함수 포인터를 활용하면 함수를 자유롭게 주고 받거나 함수 호출을 자동화 할 수 있습니다.

// 함수 포인터 선언
반환값자료형 (*함수포인터이름)();
int (*fp)();

// 매개변수가 두 개인 함수 포인터 선언
반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
int (*fp)(int, int);

// 함수 포인터 배열 선언
반환값자료형 (*함수포인터이름[크기])(매개변수자료형1, 매개변수자료형2);
int (*fp[10])(int, int);

// 함수 포인터를 구조체 멤버로 사용
struct 구조체이름 {
    반환값자료형 (*함수포인터이름)(매개변수자료형1, 매개변수자료형2);
};
struct Calc {
    int (*fp)(int, int);
};

// 함수 포인터를 함수의 매개변수로 사용
반환값자료형 함수이름(함수포인터반환값자료형 (*함수포인터이름)(함수포인터매개변수자료형1, 함수포인터매개변수자료형2)) { }
void executer(int (*fp)(int, int)) { }

// 함수 포인터를 함수의 반환값으로 사용
함수포인터반환값자료형 (*함수이름(매개변수자료형 매개변수))(함수포인터매개변수자료형1, 함수포인터매개변수자료형2) { }
int (*getAdd())(int, int) { }

// typedef로 함수 포인터 별칭 정의
typedef 반환값자료형 (*함수포인터별칭)(매개변수자료형1, 매개변수자료형2);
typedef int (*FP)(int, int);

// 함수 포인터 별칭으로 함수 포인터 선언
함수포인터별칭 함수포인터변수;
FP fp;