프로그래밍/C 언어

포인터 ( 4. 함수와 포인터 )

Jay_rock 2020. 3. 2. 03:10

1. 포인터 인자

함수 수행 과정에서 정수 인자를 넘겨주는 방법과 주소를 넘겨주는 방법 두 가지가 있다.

 

1) 정수 인자를 넘겨주는 방법

void change(int i){
	i = 10;
}

void main(){
	int a = 5;
    
    change(a);
    
    printf("%d\n", a);
}

실행 결과

5

 

먼저 함수가 실행되면 인자( int i )에 공간이 할당되고 각 인자에 정수 값이 대입된다. 그다음 지역 변수 i에 10이 대입된다. 하지만 함수 사용이 종료된 후에는 지역 변수 i에는 할당된 공간이 반환되면서 i에 대입된 값 10은 사라진다. 그러므로 실행 결과로 5가 출력된다.

 

 2) 주소를 넘겨주는 방법

void change(int *p){
	*p = 10;
}

void main(){
	int a = 5;
    
    change(&a);
    
    printf("%d\n", a);
}

실행 결과

10

 

함수를 실행하면 위에 방법과 똑같이 형식 인자( int *p )에 공간이 할당되고, 각 인자에 전달된 주소가 대입된다. 함수 안에 있는 인자 p에 a의 주소를 넘겨주게 되는 것이다. 그다음 변수에 10이 대입되고 함수가 종료될 때, 함수의 지역변수는 없어지지만 할당된 메모리 공간은 저장된 값에 남아있게 된다. 그러므로 실행 결과가 10이 출력된다.

 

 

2. 함수 인자 비교

함수 인자를 비교하면, 함수의 인자로 정수 값이나 문자 등을 호출 하는 것을 '값에 의한 호출' 이라 부르고, 주소를 인자로 호출하는 것을 '주소에 의한 호출'이라고 부른다. 전자의 경우 함수의 변수에 영향을 못 미치지만, 후자의 경우 간접 참조로 인해 호출하는 함수의 변수 값을 변경시킬 수 있다. 하지만 함수의 변수에 영향을 미치는 것은 값이 전달되느냐, 주소가 전달되느냐에 따라오는 부수적인 효과일 뿐, 함수의 호출 과정(인자 전달 및 제어 흐름)은 완전히 동일하다. 만약 위의 1 - 2) 코드 중  *p=10에서 p = NULL 로만 바꿔도 1 - 1) 코드와 완전히 동일해진다.

 

 

3. 배열을 함수의 인자로 사용

배열의 이름 또한 배열의 시작 주소를 저장하는 포인터 변수이기 때문에 배열도 함수의 인자로 전달될 수 있다. 

 

void init(int ar[]) {  // 함수 인자를 *ar 로 변경 가능
	ar[0] = ar[1] = 0;
}
void main() {
	int ar[2] = { -2,4 };
	init(ar);
	printf("%d %d", ar[0], ar[1]);
}

실행 결과

0 0

 

 

4. scanf와 printf

scanf를 사용할 때 변수 앞에 주소연산자(&)를 붙이고, printf를 사용할 때는 변수 앞에 주소연산자를 사용하지 않는다. 그 이유는 scanf를 사용 시에 입력받은 값을 변수에 저장해야 하기 때문에 변수를 바꾸려면 변수의 주소를 넘겨줘야 한다. 그러나 printf는 출력할 값만 전달하면 되기 때문에 주소연산자를 사용하지 않는다. 

 

int ar[5], *p=&ar[2];

scanf("%d",&ar[0]);
scanf("%d",p);
scanf("%d",p-1);

printf("%d %d %d", ar[0], ar[1], ar[2]);

입력 값

1 4 -3

 

실행 결과

1 -3  4

 

※ 위의 예시처럼 scanf 사용 시에 주소 값이 인자로 전달만 되면 되기 때문에 항상 주소연산자를 사용하진 않는다.