피호출 함수(justFunc)에서 num을 형식 매개변수(formal parameter)라 합니다.
Call by address vs Call by reference
위에서 제가 두 번째 예시를 call by address라 했습니다. 이는 실 매개변수(&n)로 주소값을 전달하고, 이를 복사한 값이 형식 매개변수(p)에 들어가는 방식으로 작동하였고, 이는 말 그대로 '주소에 의한 호출'이기 때문입니다. 또한 값을 복사해서 전달했으므로 call by value, 값에 의한 호출이기도 하죠.
그러면 call by reference는 대체 뭐냐?
일단 결론부터 말하면 C에는 call by reference가 존재하지 않습니다. call by reference가 뭔지 제대로 알고 싶으면 c++을 입문하고 제가 올린 나무위키 링크의 예제를 보시길 바랍니다.
간단히만 말하자면 일단 call by reference는 call by address, call by value와 달리 실질 매개변수를 제외하고는 변수(메모리)를 추가로 사용하지 않습니다.
첫 번째 예시를 보면 실질 매개변수 n을 제외하고 형식 매개변수 num을 추가로 사용하면서 메모리를 사용합니다.
두 번째 예시를 보면 실질 매개변수 n을 제외하고 형식 매개변수 p를 추가로 사용하면서 메모리를 사용합니다. 혹시 헷갈리시면 p의 주소값과 n의 주소값을 비교해보시길 바랍니다. 주소값이 다르며 따라서 다른 변수라는 것을 알 수 있습니다.
그러나 call by reference는 저 둘과 다르게 변수를 추가로 사용하여 메모리를 사용하지 않고, c++의 기능 중 하나인 '참조자 &'라는 것을 이용하여 오직 실질 매개변수만으로 호출하고 합니다.
When a parameter is passed by reference, the caller and the callee use the same variable for the parameter. If the callee modifies the parameter variable, the effect is visible to the caller's variable.
When a parameter is passed by value, the caller and callee have two independent variableswith the same value. If the callee modifies the parameter variable, the effect is not visible to the caller.
Call by value vs Call by reference
call by value와 call by reference의 차이점은 다음과 같이 세 가지입니다.
1. 복사한 값을 전달한다 vs 복사가 아닌 실질 매개변수 그 자체를 전달한다.
2. 호출 함수에 영향을 미치지 못한다 vs 호출 함수에 영향을 미칠 수 있다.
3. 인자(실질 매개변수)를 다루는 메모리의 위치가 다르다(형식 매개변수의 메모리 위치) vs 인자를 다루는 메모리의 위치가 같다(실질 매개변수의 메모리 위치)
이를 바탕으로 이제 call by value와 call by reference와 call by address를 구분하면 다음과 같습니다.
Call by address는 복사한 값(주소값)을 전달한다는 점과 인자를 다루는 메모리의 위치가 다르다는 점에서 Call by value, 그래서 결론적으로 Call by value가 맞습니다.
하지만 호출 함수에 영향을 미칠 수 있다는 점에서 Call by reference의 특성을 띄고, 그래서 많이들 Call by reference로 여기고 사용하고는 합니다.
그러므로 이번 기회에 정확하게 알고 가되, 남들과 소통할 땐 이런 점을 감안해서 이해하시기를 바랍니다.
In C and in C++ single quotes identify a single character, while double quotes create a string literal. 'a' is a single a character literal, while "a" is a string literal containing an 'a' and a null terminator (that is a 2 char array). //stack overflow 참고
즉, 우선 한 개는 홑따옴표, 여러 개는 쌍따옴표가 맞다. 그러나 한 개를 표현할때도 쌍따옴표를 쓰면 뒤에 널문자가 붙는다는 것!
따라서 널문자가 나타날때까지 읽는 %s에서는 한 문자를 쓰더라도 쌍따옴표(double quotations)를 사용해야하는 것이다.
※읽다보면 헷갈리는 부분이 있을 수 있습니다. 그럴 때 거기에 막혀서 검색해보기 전에, 일단 모두 읽어보시길 추천합니다! 서술된 내용 뒤에 보충 설명을 달아놓은 경우가 많습니다^^
포인터란?
C에서 포인터 변수는
자료형* 변수명; <- 이렇게 선언되고는 합니다.
※포인터 변수 선언 방식
1. 자료형* 변수명;
2. 자료형 * 변수명;
3. 자료형 *변수명;
모두 가능합니다.
그러나 저는 1번 방식을 추천드립니다
저는 포인터=주소명, *포인터=주소에 도착한 포인터 라고 이해했습니다.
다음의 간단한 예제를 보며 이해를 해보겠습니다.(이해에 앞서, *연산자는 주소에 접근, &연산자는 주소를 반환합니다.)
int main(void) {
int num = 5;
int* ptr; //int형 포인터 변수 ptr 선언
ptr = # //포인터 변수 ptr에 num의 주소를 저장(&num은 num의 주소를 반환합니다)
printf("주소명(포인터) = 0x%x \n", ptr); //주소명 표시
printf("주소에 도착한 포인터(*포인터) = %d \n", *ptr); //주소에 도착한 포인터 변수 ptr이 마치 num인듯이 행동
return 0;
}
실행결과
주소를 16진수로 표현하는 컴퓨터 업계에서 주로 컴퓨터의 언어인 2진수로 쉽게 표현할 수 있고, 2진수를 줄여서 쓸 수 있기 때문이라 합니다.
좀 더 자세히 설명하자면(사실상 저는 위의 예제 하나면 포인터의 개념을 모두 설명했다 생각합니다.)
포인터 변수란 메모리의 주소 값을 저장하기 위한 변수입니다.
&연산자를 통해 num의 주소 값을 반환하여,
int형 포인터 변수 ptr에는 변수 num의 '시작번지 주소'가 저장됩니다.
그리고 *연산자를 이용해 포인터가 가르키는 메모리 공간에 접근합니다.(*ptr을 통해 num이 가르키는 메모리에 접근하여 num처럼 행동하였습니다)
이러면 포인터 개념 설명 끝!
+추가)
포인터 변수에도 다양한 타입이 존재합니다. int, double, char, unsigned int 등등..
포인터 변수에 이러한 타입이 왜 존재하느냐!하면 다음 코드를 보고 생각해봅시다.
double num = 3.14;
int* pnum=#
double형의 크기는 8byte, int형의 크기는 4byte입니다.
포인터 변수 pnum는 int형이고 크기는4byte인데 여기에는 double형 num의 주소가 담겨있습니다. 이는
"num의 시작 주소부터 4byte를 읽겠다"를 의미합니다.
허나 num의 크기는 8byte이므로 포인터 변수 pnum은 *pnum으로 num에 접근하였을 때 읽다말아서(8byte 중에서 4byte만 읽어서) 원하는 값을 표시하지 않습니다.
따 라 서~~ 포인터 변수의 타입의 존재 이유는 * 연산자로 메모리를 올바르게 읽기 위해서라 할 수 있을것 같습니다.
++추추가)
잘못된 포인터의 사용과 널 포인터
다음의 포인터 선언의 잘못된 예를 보시고 무엇이 잘못되었는지 맞춰보시기 바랍니다.
int* ptr;
*ptr = 0;
C언어에서 변수를 초기화하지 않고 선언 시, 쓰레기값이 저장됩니다.
int *ptr; 을 실행하였을 때, 포인터 변수 ptr에는 임의의 주소값(쓰레기 값)이 저장될 것 입니다.
*ptr = 0;을 실행한다면? 그 임의의 주소값에 0을 저장하겠죠.
근데 만약 *ptr이 가르키는 곳이 메모리상의 중요한 부분이였다면 어떻게 될까요?? 컴퓨터를 다신 사용할 수 없을지도 모릅니다..