함수를 만들면서 인자값을 전달하면 인자값을 복사해서 전달하였습니다.
다음과 같은 함수가 있다면
#include <stdio.h>
void add(int);
int main(void) {
int num = 10;
add(num);
printf("main 함수 num : %d\n", num);
return 0;
}
void add(int a) {
a = a + 10;
printf("add 함수 a : %d\n", a);
}
main함수에서 add 함수를 호출하고 num을 인수로 전달하면 num에 저장된 값 10이 매개변수 a에 복사되어 전달됩니다.
그렇기 때문에 add함수에서 a의 값을 변경해도 main함수의 num에는 영향을 주지 않습니다.
그렇다면 배열을 인자값으로 전달한다면 어떻게 될까요?
#include <stdio.h>
void arrayShow(int*, int len); // 배열을 출력
void arrayAdd(int[], int len, int add); // 배열의 각요소에 add 값을 더합니다
int main(void) {
int arr[] = { 10,20,30 };
int len = sizeof(arr) / sizeof(arr[0]);
printf("arrayAdd 함수 호출 전\n");
arrayShow(arr, len);
arrayAdd(arr, len, 5);
printf("arrayAdd 함수 호출 후\n");
arrayShow(arr, len);
return 0;
}
void arrayShow(int * ptr, int len) {
int i;
for (i = 0; i < len; i++) {
printf("%d ", *(ptr + i));
}
printf("\n");
}
void arrayAdd(int ptr[], int len, int add) {
int i;
for (i = 0; i < len; i++) {
ptr[i] += add;
}
}
배열을 인수로 전달하면 배열의 각 요소의 값 변경도 가능 한것을 알 수 있습니다.
이것은 배열이 주소를 참조하는 참조자료형이기 때문에 가능한 것입니다.
배열을 인수로 전달할때 포인터 변수로 받게 되므로 배열의 길이정보를 알수 없기 때문에 길이 같이 전달하였습니다.
arrayShow 함수의 int * ptr과 arrayAdd 함수의 int ptr[]은 동일한 선언입니다.
시각적인 차이로 int * ptr은 포인터의 성격이 강하고, int ptr[]은 배열의 성격이 강합니다.
그렇다고 해서 다음과 같이 사용할 수는 없습니다.
int arr[3] = {1,2,3};
int ptr[] = arr; // 이렇게는 안됩니다.
int *ptr = arr; // 이렇게 쓰셔야 합니다.
Call-by-value와 Call-by-reference는 함수 호출방식을 의미합니다.
지금까지 정의한 함수는 대부분 call-by-value에 속합니다.
main함수에서 두개 정수를 선언하고 함수를 호출하여 두개의 값을 바꾸어 저장하는 swap 함수를 선언하면 다음과 같습니다.
#include <stdio.h>
void swap(int, int);
int main(void) {
int num1 = 10, num2 = 20;
printf("** swap함수 호출 전 **\n");
printf("%d, %d\n", num1, num2);
swap(num1, num2);
printf("** swap함수 호출 후 **\n");
printf("%d, %d\n", num1, num2);
return 0;
}
void swap(int num1, int num2) {
int temp = num1;
num1 = num2;
num2 = temp;
printf("** swap함수 내부 **\n");
printf("%d, %d\n", num1, num2);
return;
}
swap 함수 내부에서 num1과 num2의 값을 서로 바꾸지만 main함수에서는 바뀌지 않는다는 것을 알 수 있습니다.
이것은 값을 복사하여 전달하기 때문입니다.
주소를 출력해보면 명확합니다.
직접해보세요.
위의 예제에서 함수의 매개변수로 주소값으로 전달하려면 포인터 변수로 인자를 받아야 합니다.
물론 전달할때에 주소를 전달해야 합니다.
#include <stdio.h>
void swap(int*, int*);
int main(void) {
int num1 = 10, num2 = 20;
printf("** swap함수 호출 전 **\n");
printf("%d, %d\n", num1, num2);
swap(&num1, &num2); // 주소를 전달
printf("** swap함수 호출 후 **\n");
printf("%d, %d\n", num1, num2);
return 0;
}
void swap(int * num1, int * num2) {
int temp = *num1;
*num1 = *num2;
*num2 = temp;
printf("** swap함수 내부 **\n");
printf("%d, %d\n", *num1, *num2);
return;
}
결과는 명확합니다. main함수에서 swap 함수를 호출 후 num1값과 num2값이 교환되었습니다.
swap(int*, int*) 두 매개변수 모두 포인터 변수로 전달 받고, swap(&num1, &num2); 주소를 전달하였습니다.
swap 함수 내부에서 포인터로 접근하여 값을 변경하기에 main함수의 num1과 num2에 참조할 수 있습니다.
배열은 그 자체로 주소이기 때문에 배열을 전달했을때 배열의 각 요소의 값을 변경할 수 있었습니다.
포인터도 변수 이기때문에 가리키는 대상을 변경할 수 있습니다.
포인터가 가리키는 값 또는 포인터변수의 주소값을 변경해서는 안될때에는 const 키워드를 사용하여 상수화 할수 있습니다.
자료형 앞에 const 선언합니다.
int num = 20;
int num2 = 30;
const int * ptr = #
*ptr = 30; // 이것은 에러입니다.
ptr = &num2; // OK
포인터 변수명 앞에 const 선언합니다.
int num = 20;
int num2 = 30;
int * const ptr = #
*ptr = 40; // OK
ptr = &num2; // 이것은 에러입니다.
두곳 다 const 선언합니다.
int num = 20;
int num2 = 30;
const int * const ptr = #
*ptr = 40; // 이것은 에러입니다.
ptr = &num2; // 이것은 에러입니다.
1. 3개의 값을 서로 변경하는 swap 함수를 정의하세요.
2. swap(&num1, &num2, &num3) 형태의 호출을 하면 num1은 num2의 값, num2는 num3의값, num3은 num1값이 저장되어야 합니다.
1. 사용자로부터 5개의 정수를 입력받아 저장하는 배열을 선언하세요.
2. 배열의 평균을 구하는 average 함수를 정의하세요.
3. average(arr, len, &avr) 형태의 호출을 하면 avr 변수에 배열의 평균이 저장되어야 합니다.
4. 평균은 소수점 2자리까지만 출력하세요.