before 2020/C

포인터의 Call by Value

hom2s 2009. 6. 24. 12:43
다음과 같은 구조체가 있다.
typedef struct IntElement{
	struct IntElement *next;
	int data;
}IntElement;
이 구조체를 사용하여 어떤 링크드리스트가 구현되어 있을때 그 링크드리스트의 헤드에 새로운 노드를 추가하는 함수가 아래의 함수이다.
bool insertInFront(IntElement *head, int data){
	IntElement *newElem = new IntElement;
	if(!newElem)return false;

	newElem->data=data;
	head=newElem;
	return true;
}
이 함수에선 헤드노드 다음에는 노드가 없다고 가정하고 헤드노드만 바꾸도록 되어있다. 그런데 이렇게 하면 newElem 노드가 헤드노드를 대체할 수 있을까?
난 사실 처음 언뜻봤을때 고개를 끄덕했다. 바뀔거 같다고 ㅡㅡ; 여기저기서 기초가 부족하단 얘기를 많이 들었지만 다시 한번 자신에 대해 돌아보게 된다. 젠장;;

그렇다 바뀌지 않는다. 새로운 노드를 만들고 거기에 data 값을 대입하여 head에 넣는다 하여도 함수를 빠져나가면 헤드는 원래의 헤드 정보를 가지고 있을뿐이다.
그럼 다음 함수를보자.
bool insertInFront(IntElement **head, int data){
	IntElement *newElem = new IntElement;
	if(!newElem)return false;

	newElem->data=data;
	*head=newElem;
	return true;
}
이건 바뀌겠는가?
그렇다. 이렇게 해야지 새로운 노드가 함수를 빠져나가서도 기존의 head를 대체할 수 있게된다.
그럼 왜 그렇게 되는지 생각해보자.

0)
우선 함수 밖에서의 링크드리스트 부터 살펴보자.
잘은 모르겠지만 IntElement *head = new IntElement; 이런식으로 head 노드를 만들었을 것이다. 이과정을 거치면 다음과 같은 공간이 메모리상에 만들어지게 된다.
간단히 한글로 head주소, 노드주소 라고 표시했지만 4500435 이라던지 ff40294 같은 숫자로 표현되어 있을것이다.
일단 이렇게 포인터변수의 공간이 만들어졌다면 이제 함수를 호출할 차례이다.

1)
첫번째 함수의 호출부터 보자. 함수의 타입으로 미루어 봤을 때
insertInFront(head,10); 대충 이런식으로 호출 했을 것이다. 이렇게 호출이 되면 우선 컴파일러는 자동으로 제 2의 head 포인터변수를 만들게 된다. 물론 insertInFront함수 내에서는 head라고 불리지만 실제 메모리상의 주소를보면 기존의 head와는 다른 head라는 것을 알 수 있다.
그렇다 이런식이 된다. 둘다 head로 불리우지만 메모리상에서 다른 공간을 차지하고 있는 head이다. 하지만 함수를 호출할때 head의 값을 넘겼음으로 insert 함수의 head 역시 기존 head의 값(head가 가리켰던 노드의 주소값이다)을 가지게 된다. 바로 기존 head의 값이 복사되어 넘어가는 것이다.

결국 함수내에서의 head=newElem; 코드는 insert 함수내에서의 head에 값을 대입한 꼴이 되어버렸다. 기존 head에 값을 바꾼것이 아니다.
대략 이런꼴이 되어버린거지. 결국 함수를 빠져나가면 기존의 head는 여전히 기존 노드를 가리키고 있을뿐이다.

2)
이제 두번째 함수이다.
**head를 인자로 받는걸로 보아 호출시 insertInFront(&head,10); 대략 이런식으로 넘겨줬을 것이다.(이렇게 넘겨야만 한다. 왜냐면 **head는 이중포인터로 포인터변수의 주소값을 값으로 가져야되기 때문이다.+_+)
이걸 그림으로 나타내면 다음과 같다.
그렇다. 마찬가지로 함수내에서 새로운 head공간이 생기게 되고 이 공간은 기존의 head의 주소값을 가지게 된다.
이제 함수의 *head=newElem; 코드가 실행되면 이렇게 바뀔것이다.
*head란 이중포인터인 head가 가진 주소값의 공간이 가진 주소값을 의미한다.(**head는 이중포인터 head가 가진 주소값의 공간이 가진 주소값의 공간이 가진 값이되겠지. 유상무상무상이 유상무상보상...)
이 값을 바꿨으니 그림처럼 될 수 밖에 없는거다.
이제 함수 밖으로 나가서 함수내의 head가 사라진다고 해도 기존 head가 가리키고 있는값은 새로운 노드의 값이된다.

이렇게 빡세게 설명했는데 이제 우리가 해야 할 일은 이런코드를 보면 위의 과정이 파노라마처럼 머릿속에 흘러가야 한다는 것이다. 그래야 포인터와 함수와의 관계를 명확하게 이해하고 코딩을 할 수 있기 때문이다.
혹시 개념상 오류가 있다면 거침없이 태클을 걸어 주십시오. 맞다고 생각하지만 혹 틀렸다면 나중에 개고생 할거 같아서요. ㅋ



'before 2020 > C' 카테고리의 다른 글

이중포인터  (0) 2009.06.24