정보공간_1

[2기 대구 최진원] Function & Pointer 본문

IT 놀이터/Elite Member Tech & Talk

[2기 대구 최진원] Function & Pointer

알 수 없는 사용자 2012. 11. 24. 01:53

안녕하세요. 대구 멤버십 21-1기 최진원입니다.

이번 포스팅에서는 C 언어에서 가장 중요한 포인터에 대한 이야기를 잠시 하고 포인터와 함수에 대한 내용을 좀 다루도록 할게요. 보통 C 언어를 공부하시면서 포인터가 어렵다고 느끼는데, 포인터는 사실 어렵지 않습니다. 포인터의 개념은 다들 아시지만 배열이나 함수 등과 만나면서 상황이 복잡해 지기 때문이죠. 그럼 먼저 함수의 인자 전달에 대해서 알아보도록 하겠습니다.

 

1) Function & Argument

 

먼저 함수와 인자에 대해서 말씀을 드리려고 합니다. 함수에서 인자의 전달 방식은 복사에 의해서 이루어진다는 것은 다들 알고 계실 것입니다.

 


위의 그림은 기본적인 함수 호출의 형태인데요. main 함수에서 fct 함수를 호출하면서 변수 val의 값을 인자로 전달하고 그 값을 매개변수인 a에 저장하게 되는데, 이때 val의 값이 a에 복사가 되었습니다. 복사라는 말의 의미는 val의 값이 a에 복사가 되었다고 하더라도 a의 값을 바꾸면 val의 값은 바뀌지 않는 다는 말입니다. 당연한 이야기지만 포인터의 개념을 잡기 위해서는 꼭 필요한 내용이죠.

 

그렇다면 배열을 넘길 때는 어떨까요. 다들 아시겠지만 배열의 경우, 배열을 통째로 넘겨주는 경우는 없습니다. 다만 포인터를 이용해 주소값을 넘겨주는 방법을 사용하고 있죠.

 

 

이 같은 경우는 앞의 경우와는 차이가 있다. 배열의 주소값을 함수로 넘겨주었고 그 주소값을 arr2가 가지게 된다. 이런 경우, arr1[2]의 배열의 첫 번째 arr1[0]의 주소를 arr1arr2가 가지게 된다는 의미이다. 복사가 아니기 때문에 당연히 한쪽에서 값을 바꾸면 배열의 값이 바뀌게 된다는 점이다. 그래서 이 예제의 출력 값은 13으로 나오게 된다.

 

이 때 arr1[]*arr2가 같다면 만약 void fct(int *arr2)void fct(int arr2[])로 바꾸면 어떻게 될까?

결과는 무리없이 컴파일 된다는 것이다. 둘다 int형 포인터 변수이기 때문에 충분히 가능하다는 것이고 다만 좀 더 읽기 편하도록 arr[]라고 선언해서 사용을 한다. 하지만 여기서 주의해야 할 점이 있다면 이 같은 상황이 배열 선언 시에는 사용이 될 수 없다는 점이다.

 

다시 말해

 

 

이와 같이 배열을 선언하는데 크기를 정해 주지 않았기 때문에 잘못 된 코드라고 보게 된다.

 

2) Call-By-Value &

                    Call-By-Reference

 

Call-By-Value, Call-By_Reference.. 정말 많이 들어본 말이다. 포인터를 배울 때 많이 듣게 되는 말인데, 아래의 예제는 그중 Call-By-Value에 대한 내용이다.

 

 

위의 결과값은 어떻게 나올까?

 

아주 기초 중에 기초지만 다시 한번 짚어 보도록 할게요. add 함수를 호출 하게 되면 인자인 val1, val2add 함수의 a, b에 복사가 됩니다. 복사.. 이미 앞에서 말씀 드렸었죠. 복사는 서로에게 영향을 주지 않습니다. 그래서 값만 복사를 한다고 하여 Call-By-Value가 되죠.

만약 swap함수를 만들어 두 값을 바꾸고 싶다면 어떻게 해야 할까요?

 

 

위의 예제의 의미는 다들 아시겠죠. ab의 매개변수를 temp라는 변수를 이용해서 swap을 시키는 함수입니다. 그럼 결과는 어떻게 될까요?

 

함수 내부에서는 당연히 값이 바뀌게 되겠죠. 하지만 함수를 호출했을 때 이미 복사를 했기 때문에 실질적으로 값은 변하지 않게 됩니다. 이 같은 예를 해결하고자 Call-By-Reference를 이용 할 수 있는 데요.

 

앞에서 배열을 함수로 넘길 때 사용하던 방식이 바로 Call-By-Reference입니다. 이미 설명을 했기 때문에 Call-By-Reference를 이용해서 swap함수를 다시 작성해보도록 할게요.

 

 

이렇게 되면 a 주소에 있는 값을 temp 라는 변수에 넣고 a 주소의 값을 b 주소의 값으로 대체를 하고 b 주소의 값을 temp 변수의 값으로 대체를 시킵니다. 결국 ab의 값이 바뀌게 되죠. 그리고 함수를 호출 할 때는 당연히 그 변수에 &를 붙여서 주소값을 넘겨주도록 해야 할 것입니다.

 

여기서 &가 나왔는데, 평소에 무심코 쓰던 & 하나가 생각이 납니다. 바로 scanf() . 처음 C 언어를 접했을 때 printf() 다음으로 알게 되었던 함수. 한 예로 val 라는 변수에 값을 입력 받고 싶을 때 우리는 scanf(“%d”, &val); 라고 코드를 작성하게 됩니다. 이때 scanf의 기능은 val라는 변수의 값을 바꾸는 역할을 하는데, 그 값을 함수안에서 바꾸려면 Call-By-Reference로 되어 있어야 하고, 호출시에는 그 변수의 주소값을 넘겨주어야 하기 때문이라는 것을 보너스로 알 수 있습니다.

하지만 여기서 의문점이 하나 생길 수 있습니다.

 

 

위의 예제에서 사용한 scanf는 앞에서 설명드린 것과 다르죠. &를 붙이지 않은 점이 다른데요. 그렇다면 이 예제는 에러를 발생하게 될까요?

 

대답은 No입니다. str의 경우 char 배열이고 그 배열의 주소를 의미하기 때문에 따로 &를 붙여주지 않아도 된다는 것을 조금만 생각해보시면 알게 되실 것입니다.

 

 3) Reference

- 윤성우, C++ 프로그래밍, FREELEC, 2004

 

 

알다가도 다시 돌아보면 모르는 일들이 참 많습니다. 이번 기회에 C 언어를 다시 한번 뒤돌아 보고 덮어두었던 책을 다시 한번 펼쳐 보면 새로운 것들이 쏟아집니다. 이번 포스팅에서는 배열을 함수인자로 전달하는 방법과 Call-By-Value, Call-By-Reference에 대해서 알아보았습니다. 이번 포스팅으로 기초적인 지식을 가볍게 복습하는 시간을 가졌으면 좋겠습니다.

 

 



<!--[endif]-->

<!--[endif]-->