C프로그래밍 11/? 포인터&함수
함수는 인자를 전달받도록 정의할 수 있습니다. 사실 함수라는 이름이 붙은 이유도 인자의 전달과 값의 반환이 가능하기 때문입니다.
인자전달의 기본방식은 값의 복사입니다. 즉, 복사가 되는 것 뿐이기 때문에 함수가 호출되고 나면, 전달되는 인자와 매개변수는 별개가 됩니다.
int SimpleFunc(int num) {....}
int main(void)
{
int age = 17;
SimpleFunc(age); //age에 저장된 값이 매개변수 num에 복사된다
}
위 코드의 SImpleFunc 함수의 호출을 통해서 인자로 age를 전달하고 있습니다. 그러나 실제로 전달되는 것은 age가 아닌, age에 저장된 값일뿐입니다. 그리고 배열을 통째로 넘겨받으려면 매개변수로 배열을 선언할 수 있어야하지만, 허용되지 않습니다. 대신에 함수 내에서 배열에 접근할 수 있도록 배열의 주소값을 전달하는 것은 가능합니다. 이해를 돕기위해 예를 들어보겠습니다. 아파트를 보고 싶어 하는 사람 앞에 아파트를 통째로 복사해다 놓을 수 없다면, 아파트의 주소를 가르쳐줘서 직접 찾아가게 하면 되는 경우를 생각해보시면 이해가 될 것입니다. 예를 통해 보겠습니다.
#include <stdio.h>
void ShowArayElem(int *param, int len)
{
int i;
for(i = 0; i < len; i++)
printf("%d ", param[i]);
printf(("\n");
}
int main(void)
{
int arr1[3] = {1, 2, 3];
int arr2[5] = {4, 5, 6, 7, 8];
ShowArayElem(arr1, sizeof(arr1) / sizeof(int));
ShowArayElem(arr2, sizeof(arr2) / sizeof(int));
return 0;
}
결과
1 2 3
4 5 6 7 8
그러면 배열과 동일한 선언을 확인했다. 즉 포인터입니다. 위 코드에서 ShowArayElem함수의 int형 배열의 주소 값을 인자로 전달받을 수 있도록 int형 포인터 변수가 선언되었는데 이를 배열로 선언해도 동일합니다.
int *param >> int param[]
하지만 이 둘이 같은 선언으로 간주되는 경우는 매개변수의 선언을 제한됩니다.
함수호출
Call-by-value와 Call-by-reference는 구분하는 기준은 함수의 인자로 전달되는 대상에 있습니다. 사실, 이를 구분하는데 큰 의미는 없습니다. 하지만 이를 구분하는 이유는 실수를 막기 위함에 있습니다. 아래 설명을 통해 둘의 차이를 확인해보겠습니다.
Call-by-value
함수를 호출할 때 단순히 값을 전달하는 형태의 함수호출입니다.
void Swap(int n1, int n2)
{
int temp = n1;
n1 = n2;
n2 = temp;
}
Call-by-reference
메모리의 접근에 사용되는 주소 값을 전달하는 형태의 함수호출입니다.
void Swap(int *ptr1, int *ptr2)
{
int temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
}
이러한 형태는 scanf 함수호출시에도 확인했을 것입니다.
scanf("%d", &num);
이처럼 scanf 함수호출이 완료되면 변수 num에는 값이 채워집니다. 이때 변수 num에 그 값을 채우는 일을 scanf 함수가 하는데 이때 변수 num의 주소값을 알아야합니다. 이렇듯 scanf 함수의 호출도 Call-by-reference형태의 함수호출에 해당합니다.
const 선언
const 선언은 위치에 따라 그 의미가 변할 수 있습니다. 두 예를 모두 보겠습니다.
이는 포인터 변수가 참조하는 대상의 변경을 허용하지 않습니다.
int num = 20;
const int *ptr = #
*ptr = 30; // 컴파일 에러 ptr이 가리키는 변수에 저장된 값을 변경하는건 불가능하다는 의미
num = 40; // 컴파일 성공 ptr이 가리키는 변수 자체는 상수가 아니라 변경 가능
이는 포인터 변수의 상수화를 진행시키는 방법입니다.
int num1 = 20;
int num2 = 30;
int *const ptr = &num1;
ptr = &num2; // 컴파일 에러 ptr은 상수라서 변경 불가
*ptr = 40; // 컴파일 성공 ptr이 가리키는 대상에 저장된 값은 변경 가능
const는 코드를 작성하다보면 쉽게 지나칠 수 있는 부분입니다. 그러면 이는 왜 생겼는지 의문이 생길 것입니다. 그 이유는 실수로 변수에 잘못된 값으로 설정했을 때, 컴파일 시 발견되지않습니다. 그래서 이처럼 중요한 변수의 값을 실수로 변경하는 일을 방지하기 위해 사용할 방법을 찾아보다 이용하게 된게 아닐까 합니다.