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값 넣어주고 끝난 함수다.
세 가지 정도가 있다.
사실 이 방법은 주소를 복사한다기보단 맨 처음 내가 원했던 상황인 동적으로 할당한 배열의 값을
복사하는 방식이다.
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을 이용해 메모리를 할당해준 후, 내부 값들을 하나하나 복사해준다.
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**) 로 캐스팅을 해줘야한다.
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);
포인터주소형태로 넘겨주면 그냥 막연히 참조하겠거니 생각했지만 틀린 생각이었다.
해당 주소값 자체를 인자로 전달받는다는 사실을 처음 알았다.
이렇게 모르는 부분을 발견한걸 보면 주소 복사 해보려는 시도가 좋은 생각이였던것 같다.