c언어 동적할당 해제시 오류 질문 드립니다.
글쓴이: kokoroo / 작성시간: 금, 2018/01/12 - 11:24오후
구조체 포인터를 함수로 넘겨서 구조체 멤버변수들을 바꾸는 예제입니다.
함수 func2 만 보셔도 무방합니다.
소스코드---------------------------------
#include <stdio.h> #include <stdlib.h> typedef struct hello { int x; int y; int* px; int* py; }HELLO; void func2(HELLO* hello); int main() { HELLO hello1; hello1.x = 10; hello1.y = 20; hello1.px = &hello1.x; hello1.py = &hello1.y; printf("x의값 : %d\n", hello1.x); printf("x의주소 : %x\n", &hello1.x); printf("y의값 : %d\n", hello1.y); printf("y의주소 : %x\n\n", &hello1.y); printf("px의값 : %x\n", hello1.px); printf("px의주소 : %x\n", &hello1.px); printf("px가 가리키는 값 : %d\n", *hello1.px); printf("py의값 : %x\n", hello1.py); printf("py의주소 : %x\n", &hello1.py); printf("py가 가리키는 값 : %d\n\n\n", *hello1.py); HELLO* phello = &hello1; func2(phello); printf("x의값 : %d\n", hello1.x); printf("x의주소 : %x\n", &hello1.x); printf("y의값 : %d\n", hello1.y); printf("y의주소 : %x\n\n", &hello1.y); printf("px의값 : %x\n", hello1.px); printf("px의주소 : %x\n", &hello1.px); printf("px가 가리키는 값 : %d\n", *hello1.px); printf("py의값 : %x\n", hello1.py); printf("py의주소 : %x\n", &hello1.py); printf("py가 가리키는 값 : %d\n\n\n", *hello1.py); return 0; } void func2(HELLO* hello) { hello->x = 1; hello->y = 2; int* temp = (int*)malloc(sizeof(int)); temp = hello->px; hello->px = hello->py; hello->py = temp; // temp = NULL; free(temp); }
----------------------------------
이때 free(temp); 부분에서 runtime 에러가 납니다.
아예 free(temp); 를 빼서 해제를 하지 않거나,
주석부분인 temp = NULL; 을 적어서 해제전에 NULL포인터로 만들면 에러가 나지 않습니다.
하지만 이것들은 편법인것 같고, free(temp); 다음에 temp = NULL; 을 적으면 에러가 나네요..
temp = NULL;을 적지않고 free(temp);만 적어도 에러가나구요.
할당해제시 에러가 나는 이유가 무엇일까요?
Forums:
free할 때에 temp는 func2가 호출되던 때에
free할 때에 temp는 func2가 호출되던 때에 hello->px 가 가지고 있던 값입니다 (왜냐하면 temp = hello->px). 그 주소에는 메모리를 동적으로 할당한 적이 없으니까 당연히 에러가 납니다. func2 에서 temp에 할당한 메모리를 해제하고 싶으시면 다른 포인터를 하나 더 써서 temp를 복사해두었다가 free에게 넘겨야합니다.
> 아예 free(temp); 를 빼서 해제를 하지 않거나, 주석부분인 temp = NULL; 을 적어서 해제전에 NULL포인터로 만들면 에러가 나지 않습니다. 하지만 이것들은 편법인것 같고, ...
편법이 아니고, 그러면 안됩니다. 메모리 누수 입니다. 버그에요.
답변 감사합니다 그런데 이해가 잘 가지 않습니다.
1. temp라는 포인터가 hello->px 포인터가 가리키는 값과 같은 곳을 가리키고 있었다 하더라도, 동적 할당된 temp만을 free함수로 해제시키는 것이 왜 잘못된 것인지 모르겠습니다.
2. 다른 포인터를 쓴다는 것이 int* ptr = temp를 한 후에 free(ptr)을 하는 것이 맞나요?
3. 다른포인터를 써서 temp를 복사해둔 후, free에 넘기면 다른 포인터만 해제되는 것이 아닌가요?
4. 해제를 하지 않으면 메모리 누수인 것은 이해가 됩니다. temp = NULL; 로 바꿔준 다음에 free(temp)를 하는 것도 메모리 누수인가요?
답변 정말 감사합니다. C언어 너무 어렵네요 ㅠㅠ
제가 원 답변 올리신 분은 아니지만 지나가다 본 김에
제가 원 답변 올리신 분은 아니지만 지나가다 본 김에...
free는 "어떤 변수를" 해제하는 게 아닙니다. "그 변수가 가리키고 있는, 즉 변수에 담겨 있는 주소값부터 시작하고 있는" 공간을 해제하는 거죠. 그리고 그 주소는 malloc(또는 calloc, realloc)을 호출하여 리턴값으로 받은 주소여야 하고요.
1.
본문의 temp는 그저 int * 타입의 지역변수일 뿐입니다.
처음에는 malloc으로 할당된 공간을 가리키고(즉 그 공간의 시작 주소를 담고) 있었지만, hello->px 를 대입하는 순간부터 hello->px가 가리키고 있던, 이 경우 hello1.x 의 주소를 담게 되었습니다.
따라서 free는 hello->px 가 가리키는 공간을 해제하려고 하지, 의도하신 대로 "동적 할당된 temp만"(사실 이것도 잘못된 말이고, 동적할당되어 temp가 가리키고 있던 공간을이라고 써야겠지만)" 해제하지 않습니다.
그 동적할당된 공간은 이제는 해제하려고 해도 할 방법조차 없습니다. 그 주소를 누구도 모르니까요. 유일하게 그 주소를 담고 있던 게 temp 변수인데 이제는 temp에도 다른 값이 들어가 있어서요. 프로그램이 종료될 때까지, 저 공간은 할당받아놓고는 쓰지 못하게 된 공간으로 낭비됩니다.
2.
네 맞습니다. 물론 hello->px 를 대입하기 "전"에 복사해야 합니다.
3.
이제는 3번 질문이 왜 잘못된 건지 아셨을 겁니다.
4.
앞서 말했듯이 temp에 다른 값이 들어가면(NULL이든 뭐든) 이제 더 이상 원래 할당받았던 공간을 해제할 방법이 없으니 누수가 일어납니다. temp = NULL을 하고 해제했을 때 에러가 안 나는 건 그저 free가 인자로 널 포인터를 받으면 그냥 아무 일도 하지 않고 끝나기 때문입니다.
끝으로...
하려는 일이 그저 px 포인터와 py 포인터의 스왑이라면, 애초에 별도의 공간을 할당받을 필요조차 없습니다. px의 값을 임시로 저장할 공간은 temp이지, temp가 가리키는 다른 어딘가가 아니니까요.
좋은 하루 되세요!
정말 감사드립니다.
가슴 한 가운데 막혔던 것이 모두 뚫리는 기분입니다.
공부 열심히 하겠습니다. 진짜로 감사합니다.
댓글 달기