Chap.14 포인터와 함수에 대한 이해

xyzw·2022년 9월 11일
0

C

목록 보기
3/6

14-1; 함수의 인자로 배열 전달하기

인자전달의 기본방식은 값의 복사이다

함수 호출 시 전달되는 인자의 값은 매개변수에 복사가 된다.
매개변수로 배열을 선언할 수 없다.

배열을 함수의 인자로 전달하는 방식

배열의 주소 값을 인자로 전달

#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

배열의 값의 변경

#include <stdio.h>

void ShowArayElem(int* param, int len)
{
	int i;
    for(i=0; i<len; i++)
    	printf("%d ", param[i]);
    printf("\n");
}

void AddArayElem(int* param, int len, int add)
{
	int i;
    for(i=0; i<len; i++)
    	param[i] += add;
}

int main(void)
{
	int arr[3] = {1, 2, 3};
    AddArayElem(arr, sizeof(arr) / sizeof(int), 1);
    ShowArayElem(arr, sizeof(arr) / sizeof(int));
    
    AddArayElem(arr, sizeof(arr) / sizeof(int), 2);
    ShowArayElem(arr, sizeof(arr) / sizeof(int));
    
    AddArayElem(arr, sizeof(arr) / sizeof(int), 3);
    ShowArayElem(arr, sizeof(arr) / sizeof(int));
    return 0;
}

실행결과
2 3 4
4 5 6
7 8 9

배열을 함수의 인자로 전달받는 함수의 또 다른 선언

void ShowArayElem(int* param, int len){...}
void ShowArayElem(int param[],int len){...}

int param[]과 int* param은 완전히 동일한 선언이다. 그런데 전자의 선언이 배열이 인자로 전달된다는 느낌을 더 강하게 주는 선언이므로, 일반적으로 배열의 주소 값이 인자로 전달될 때에는 int param[] 형태의 선언을 주로 많이 사용한다.

참고: 함수 내에서는 인자로 전달된 배열의 길이를 계산할 수 없다.

void SimpleAryFunc1(int* arr)
{
	int size = sizeof(arr);  //변수 size에는 포인터 변수 arr의 크기가 저장
    ...
}

배열의 주소 값 을 인자로 전달받는 매개변수는 포인터 변수이기 때문에 이를 대상으로 sizeof 연산을 할 경우 배열의 크기가 반환되지 않고 포인터 변수의 크기가 반환된다.

14-2; Call-by-value vs. Call-by-reference

값을 전달하는 형태의 함수호출: Call-by-value

다음 예제는 문제점이 있다.

#include <Stdio.h>

void Swap(int n1, int n2)
{
	int temp = n1;
    n1 = n2;
    n2 = temp;
    printf("n1 n2: %d %d \n", n1, n2); 
}

int main(void)
{
	int num1 = 10;
    int num2 = 20;
    printf("num1 num2: %d %d \n", num1, num2);
    
    Swap(num1, num2);
    printf("num1 num2: %d %d \n", num1, num2);
    return 0;
}

실행결과
num1 num2: 10 20
n1 n2: 20 10
num1 num2: 10 20

Swap 함수 내에서는 매개변수 n1과 n2에 저장된 값이 변경되지만, num1과 num2에 저장된 값의 변경으로까지 이어지지는 않는다.

주소 값을 전달하는 형태의 함수호출: Call-by-reference

#include <Stdio.h>

void Swap(int* ptr1, int* ptr2)
{
	int temp = *ptr1;
    *ptr1 = *ptr2;
    *ptr2 = temp;
}

int main(void)
{
	int num1 = 10;
    int num2 = 20;
    printf("num1 num2: %d %d \n", num1, num2);
    
    Swap(&num1, &num2);
    printf("num1 num2: %d %d \n", num1, num2);
    return 0;
}

실행결과
num1 num2: 10 20
num1 num2: 20 10

scanf 함수 호출 시 & 연산자를 붙이는 이유

int main(void)
{
	int num;
    scanf("%d", &num);
    ...
}

scanf 함수 호출이 완료되면 변수 num에는 값이 채워진다. 이를 위해서 scanf 함수는 변수 num의 주소 값을 알아야 한다.

문자열 입력

int main(void)
{
	char str[30];
    scanf("%d", str);
    ...
}

배열 이름 str은 그 자체로 배열의 주소 값이므로 & 연산자를 붙이지 않는다.

문제

1

Q. 변수 num에 저장된 값의 제곱을 계산하는 함수를 정의하고, 이를 호출하는 main 함수를 작성해보자. 단, 여기서는 다음 두 가지 형태로 함수를 정의해야 한다.
• Call-by-value 기반의 SquareByValue 함수
• Call-by-reference 기반의 SquareByReference 함수
SquareByValue 함수는 인자로 전달된 값의 제곱을 반환해야 하며, SquareByReference 함수는 정수가 저장되어 있는 변수의 주소 값을 인자로 받아서 해당 변수에 저장된 값의 제곱을 그 변수에 다시 저장해야 한다.

2

Q. 세 변수에 저장된 값을 서로 뒤바꾸는 함수를 정의해보자. 예를 들어서 함수의 이름이 Swap3라 하면, 다음의 형태로 함수가 호출되어야 한다.

	Swap3(&numl, &num2, &num3);

그리고 함수호출의 결과로 num1 에 저장된 값은 num2에, num2에 저장된 값은 num3에, 그리고 num3에 저장된 값은 num1 에 저장되어야 한다.

14-3; 포인터 대상의 const 선언

포인터 변수가 참조하는 대상의 변경을 허용하지 않는 const 선언

const 선언을 하게 되면, 포인터 변수가 가리키는 변수에 저장된 값을 변경하는 것을 허용하지 않는다.

int main(void) 
{
	int num = 20;
	const int* ptr = &num;
	*ptr = 30; // 컴파일 에러!
	num = 40; // 컴파일 성공!
	...
}

포인터 변수의 상수화

int* const ptr = &num;

const 선언이 포인터 변수의 이름 앞에 오게 되면, 포인터 변수는 상수가 된다. 즉, 한번 주소 값이 저장되면 그 값의 변경이 불가능하며, 한번 가리키기 시작한 변수를 끝까지 가리켜야 한다.

두 가지 형태의 const 선언을 동시에

const int* const ptr = &num;

위와 같이 선언을 하게 되면 포인터 변수가 참조하는 대상의 내용을 바꾸는 것도, 포인터 변수가 가리키는 대상을 바꾸는 것도 불가능하다.

*ptr = 20;   //컴파일 에러
ptr = &age;  //컴파일 에러

문제

1

Q. 아래에 정의된 함수를 보자. 인자로 전달되는 정보를 참조하여 int형 배열요소 전체를 출력하는 함수이다.

void ShowAllData(const int * arr, int len) 
{
	int i;
	for(i=0; i<len; i++) 
		printf("%d ", arr[i]);
}

위 함수의 매개변수 선언에서 매개변수 arr을 대상으로 const 선언을 한 이유가 무엇이겠는가? 이 함수를 정의한 사람의 의도를 이야기해 보자.

2

Q. 아래의 예제는 한 가지 지적할만한 사항을 지니고 있다. 그것이 무엇인지 이야기해 보자. 특히 이와 관련해서 ShowData 함수를 유심히 관찰하기 바란다.

void ShowData(const int * ptr)
{ 
	int * rptr=ptr; 
	printf("%d \n", *rptr); 
	*rptr=20;
}

int main(void)
{
	int num=10;
	int * ptr=&num;
	ShowData(ptr); 
	return 0;
}

0개의 댓글