함수에 인자로 포인터를 전달하는 경우에 대해

jh Seo·2023년 9월 12일
0

C++공부

목록 보기
21/21
post-custom-banner

개요

void* 포인터에 문득 호기심이 생겨 c언어에서 함수를 만들어 이것저것 실험해보던 중,
포인터 자체에 대해 잘 이해가 안 가는 내용이 있어서 검색해 정리한 글이다.
왜 c++공부에 태그가 되어있냐면 c++과 비교하는 내용이 있어서 해줬다.

이해가 안 갔던 부분

	int* data = (int*)malloc(sizeof(int)*10);
	int* client=nullptr;
	for (int i = 0; i < 10; i++) {
		data[i] = i;
	}

이런 식으로 data배열을 동적으로 할당 후, client 배열을 data배열로 복사하려고 한다.
(원본(data배열)에 영향을 미치므로 따로 메모리 할당후 내부값 복사가 더 좋지만(deep copy),
일단 학습적인 목적으로 실행해봤다. )

void copyAddress(int* from, void* to) {
	to = from;
}

from값과 to값이 주소값으로 전달이 되었으므로 이런식으로 주소를 그냥 복사해봤다.

copyAddress(data, client);
printf("%d\n", data[4]);
printf("%d\n", client[4]);

실행해보면 놀랍게도? client에는 그대로 nullptr이 들어가있었다.

이유

검색을 막 해보고 깨달은 사실은 함수의 인자는 무조건 pass by value형식으로 넘겨준다.
사실 당연한 사실인게 참조자가 없는 c언어에서는 모든 값이 다 value로 들어올 것이다.
따라서 포인터형으로 받을 때, 인자의 주소값(address)은 value로 16진수 수로 들어온다.

따라서

void copyAddress(int* from, void* to) {
	to = from;
}

이런 짓을 해봤자 포인터 처음 배울때 강의에서 맨날 써먹는 주제인 swap과 상황이 같다.

void swap(int a, int b){
	int tmp=a;
    a=b;
    b=tmp;
}

아무 일도 벌어지지 않는다.
copyAddress함수는 지역변수 to에 from값 넣어주고 끝난 함수다.

제대로 복사하는 방법

세 가지 정도가 있다.

1. deep copy

사실 이 방법은 주소를 복사한다기보단 맨 처음 내가 원했던 상황인 동적으로 할당한 배열의 값을
복사하는 방식이다.

void copy(int* from, void* to,int cnt) {
	to = malloc(sizeof(int) * cnt);
	for (int i = 0; i < cnt; i++) {
		*((int*)to + i) = *(from + i);
	}
}

to에 malloc을 이용해 메모리를 할당해준 후, 내부 값들을 하나하나 복사해준다.

2. 이중포인터 사용

c에서는 참조자가 없으므로 pass by value로 전달받은 주소값을 서로 변경해주려면
해당 주소값을 가리키는 이중포인터 ** 를 사용해야한다.

void copyAddress(int* from, void** to) {
	*to = from;
}

이중포인터를 이용해 to 주소를 가리키는 주소를 받아온 후
해당 주소가 가리키는 곳을 from으로 설정하면 비로소 from과 to 두 주소가 같아진다.

이중 포인터를 사용하려면 호출할때도 캐스팅을 적절히 해줘야한다.

	copyAddress(data, (void**)&client);

void*포인터는 모든 타입의 포인터를 다 가리킬 수 있지만,
void** 포인터는 void* 포인터만을 가리킨다.

따라서 client포인터의 주소를 넘겨주고 (void**) 로 캐스팅을 해줘야한다.

3. c++에서 &참조자 사용

void copyAddress(int*& from, int*& to) {
	to = from;
}

포인터의 주소값을 c++의 &참조자를 사용해 pass by reference로 넘겨주는 것이다.
이런식으로 구현시 주소 복사가 된다.
*& 연산자가 웃기게 생기긴 했지만 정상적으로 작동된다.

int* data = (int*)malloc(sizeof(int)*10);
int* client=nullptr;
for (int i = 0; i < 10; i++) {
	data[i] = i;
}

copyAddress(data, client);

생각

포인터주소형태로 넘겨주면 그냥 막연히 참조하겠거니 생각했지만 틀린 생각이었다.
해당 주소값 자체를 인자로 전달받는다는 사실을 처음 알았다.

이렇게 모르는 부분을 발견한걸 보면 주소 복사 해보려는 시도가 좋은 생각이였던것 같다.

profile
코딩 창고!
post-custom-banner

0개의 댓글