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를 이용하여 first와 second에 저장된 값을 서로 바꾸었습니다.
void swapNumber(int first, int second) // 반환값 없음, int형 매개변수 두 개 지정 { int temp; // 임시 보관 변수 temp = first; first = second; second = temp; }
swapNumber를 호출할 때 10이 들어있는 num1과 20이 들어있는 num2를 넣었습니다. 그 뒤 printf로 값을 출력해보면 num1과 num2의 값이 서로 바뀌지 않고 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를 호출해봐야 num1과 num2의 값은 바뀌지 않습니다.
이번에는 매개변수를 포인터로 사용해보겠습니다. 다음과 같이 ( ) (괄호) 안에서 자료형 뒤에 * (애스터리스크)를 붙여서 매개변수를 포인터 형태로 만듭니다.
반환값자료형 함수이름(자료형 *매개변수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와 같이 포인터 형식으로 지정해줍니다. 그리고 함수 안에서는 매개변수를 역참조하여 first와 second의 값을 바꿉니다.
void swapNumber(int *first, int *second) // 반환값 없음, int 포인터 매개변수 두 개 지정 { int temp; // 임시 보관 변수 // 역참조로 값을 가져오고, 값을 저장함 temp = *first; *first = *second; *second = temp; }
num1에는 10, num2에는 20이 들어있습니다. 이 상태에서 & (주소 연산자)를 사용하여 swapNumber에 num1과 num2의 메모리 주소를 넣어줍니다.
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에 의해서 num1과 num2의 값이 서로 바뀐 것을 알 수 있습니다. 즉, 변수의 메모리 주소를 함수에 전달하면 함수 안에서는 메모리 주소에 접근하여 값을 저장할 수 있습니다.
함수의 반환값은 값을 하나만 반환할 수 있는데 이처럼 매개변수를 포인터로 사용하면 함수 바깥으로 여러 개의 값을 전달할 수 있습니다.
지금까지 scanf 함수를 사용할 때 변수를 그대로 넣지 않고 &를 사용하여 변수의 메모리 주소를 넣었습니다. 왜냐하면 scanf함수는 값을 여러 개 입력받을 수 있는데 반환값만으로는 여러 개의 값을 함수 바깥으로 가져올 수 없었기 때문입니다.
int num1; int num2; int num3; scanf("%d %d %d", &num1, &num2, &num3); // scanf에서 값을 3개 가져옴(scanf는 바깥으로 값을 3개 전달)
변수의 메모리 주소만 넘겨주면 값이 몇 개든 상관없이 값을 가져올 수 있습니다. 이제 왜 그랬는지 이해가 되시죠?
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 매크로 사용하기'에서 자세히 설명하겠습니다.