63.1 포인터 매개변수 사용하기

먼저 매개변수에서 일반적인 변수를 사용하면 변수의 내용이 어떻게 되는지 알아보겠습니다. 다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

parameter.c

#include <stdio.h>

void swapNumber(int first, int second)    // 반환값 없음, int형 매개변수 두 개 지정
{
    int temp;    // 임시 보관 변수

    temp = first;
    first = second;
    second = temp;
}

int main()
{
    int num1 = 10;
    int num2 = 20;

    swapNumber(num1, num2);    // 변수 num1과 num2를 넣어줌

    printf("%d %d\n", num1, num2);    // 10 20: swapNumber 함수와는 상관없이 
                                      // 처음 저장한 10과 20이 출력됨

    return 0;
}

실행 결과

10 20

void swapNumber(int first, int second)과 같이 int형 매개변수 두 개를 지정하고, 함수 안에서 임시 변수 temp를 이용하여 firstsecond에 저장된 값을 서로 바꾸었습니다.

void swapNumber(int first, int second)    // 반환값 없음, int형 매개변수 두 개 지정
{
    int temp;    // 임시 보관 변수

    temp = first;
    first = second;
    second = temp;
}

swapNumber를 호출할 때 10이 들어있는 num1과 20이 들어있는 num2를 넣었습니다. 그 뒤 printf로 값을 출력해보면 num1num2의 값이 서로 바뀌지 않고 10과 20이 그대로 출력되는 것을 볼 수 있습니다. 즉, 매개변수는 값을 전달하는 역할만 할 뿐 함수 바깥의 변수와는 상관이 없습니다.

int num1 = 10;
int num2 = 20;

swapNumber(num1, num2);    // 변수 num1과 num2를 넣어줌

printf("%d %d\n", num1, num2);    // 10 20: swapNumber 함수와는 상관없이 
                                  // 처음 저장한 10과 20이 출력됨

아무리 swapNumber를 호출해봐야 num1num2의 값은 바뀌지 않습니다.

그림 63‑3 매개변수와 변수의 관계

이번에는 매개변수를 포인터로 사용해보겠습니다. 다음과 같이 ( ) (괄호) 안에서 자료형 뒤에 * (애스터리스크)를 붙여서 매개변수를 포인터 형태로 만듭니다.

반환값자료형 함수이름(자료형 *매개변수1, 자료형 *매개변수2)
{
}

다음 내용을 소스 코드 편집 창에 입력한 뒤 실행해보세요.

parameter_pointer.c

#include <stdio.h>

void swapNumber(int *first, int *second)    // 반환값 없음, int 포인터 매개변수 두 개 지정
{
    int temp;    // 임시 보관 변수

    // 역참조로 값을 가져오고, 값을 저장함
    temp = *first;
    *first = *second;
    *second = temp;
}

int main()
{
    int num1 = 10;
    int num2 = 20;

    swapNumber(&num1, &num2);        // &를 사용하여 num1과 num2의 메모리 주소를 넣어줌

    printf("%d %d\n", num1, num2);   // 20 10: swapNumber에 의해서 num1과 num2의 값이 서로 바뀜

    return 0;
}

실행 결과

20 10

먼저 함수를 정의할 때 매개변수 부분을 int *first, int *second와 같이 포인터 형식으로 지정해줍니다. 그리고 함수 안에서는 매개변수를 역참조하여 firstsecond의 값을 바꿉니다.

void swapNumber(int *first, int *second)    // 반환값 없음, int 포인터 매개변수 두 개 지정
{
    int temp;    // 임시 보관 변수

    // 역참조로 값을 가져오고, 값을 저장함
    temp = *first;
    *first = *second;
    *second = temp;
}

num1에는 10, num2에는 20이 들어있습니다. 이 상태에서 & (주소 연산자)를 사용하여 swapNumbernum1num2의 메모리 주소를 넣어줍니다.

int main()
{
    int num1 = 10;
    int num2 = 20;

    swapNumber(&num1, &num2);        // &를 사용하여 num1과 num2의 메모리 주소를 넣어줌

    printf("%d %d\n", num1, num2);   // 20 10: swapNumber에 의해서 num1과 num2의 값이 서로 바뀜

    return 0;
}

printf로 값을 출력해보면 swapNumber에 의해서 num1num2의 값이 서로 바뀐 것을 알 수 있습니다. 즉, 변수의 메모리 주소를 함수에 전달하면 함수 안에서는 메모리 주소에 접근하여 값을 저장할 수 있습니다.

그림 63‑4 포인터 매개변수

함수의 반환값은 값을 하나만 반환할 수 있는데 이처럼 매개변수를 포인터로 사용하면 함수 바깥으로 여러 개의 값을 전달할 수 있습니다.

지금까지 scanf 함수를 사용할 때 변수를 그대로 넣지 않고 &를 사용하여 변수의 메모리 주소를 넣었습니다. 왜냐하면 scanf함수는 값을 여러 개 입력받을 수 있는데 반환값만으로는 여러 개의 값을 함수 바깥으로 가져올 수 없었기 때문입니다.

int num1;
int num2;
int num3;

scanf("%d %d %d", &num1, &num2, &num3); // scanf에서 값을 3개 가져옴(scanf는 바깥으로 값을 3개 전달)

변수의 메모리 주소만 넘겨주면 값이 몇 개든 상관없이 값을 가져올 수 있습니다. 이제 왜 그랬는지 이해가 되시죠?

읽을거리 | 매개변수 포인터와 IN, OUT

C 언어로 작성된 여러 프로그램들을 보면 매개변수 부분에 IN, OUT, in, out 등의 단어가 추가로 붙어있는 경우가 있습니다(Windows 커널모드 드라이버를 만들 때 자주 나옵니다).

//            ↓ 일반적인 매개변수
void GetValue(IN int a, OUT int *b)
{ //                     ↑ 값이 바깥으로 나오는 매개변수
    printf("%d\n", a);

    *b = 10;
}

IN은 함수 안으로 들어가기만 하는 일반적인 매개변수라는 표시이고, OUT은 함수 바깥으로 값이 나오는 매개변수라는 표시입니다. IN, OUT은 C 언어의 문법은 아니지만 전처리기를 활용하여 사람만 알아볼 수 있도록 정의한 것입니다. 즉, 함수의 매개변수 부분만 보고도 매개변수의 방향을 쉽게 알 수 있죠.

IN, OUT은 다음과 같이 정의되어 있으며 컴파일할 때는 아무런 영향을 주지 않습니다.

#define IN
#define OUT

전처리기에 대해서는 'Unit 75 매크로 사용하기'에서 자세히 설명하겠습니다.