his130   2년 전

제가 disjoint-set 을 하고 있는데요..

문제 풀이에 대한 질문이 아니라..

일단 제가 아래 코드에서 map<char*,char*> p 로 설정했습니다.


근데 문제는 main 에서 두번째 변수 i를 갖는 for문 입니다. 

저는 한번 for문을 돌면 p 변수에 계속 추가가 되도록 코드를 짠거 같은데

p의 사이즈가 증가하지 않고, 자꾸 p는 2개로 초기화(?)가 됩니다..

단어를 노드로, 그리고 부모노드를 단어로 하려고 하는데, 무슨일인지 자꾸 2개밖에 안됩니다.


도대체 왜 p 변수가 2개에서 계속 헛도는걸까요..

디버그를 해봐도 도저히 모르겠네요..

lvalue   2년 전

std::map<char*, char*>는 생각하시는 대로 작동하지 않습니다. std::map에서 두 key가 동일한지를 검사하는 방법은 비교 연산자 <를 이용하는 것인데요, p[a] = a; 를 했을 때 a는 포인터 값이기 때문에 map 내부적으로 문자열 비교가 아니라 포인터 값을 비교하게 됩니다. 그리고 a에 해당하는 포인터 값은 for문을 한번 돌 때마다 scope에서 벗어나기 때문에 더 이상 유효하지 않게 됩니다. 유효하지 않은 포인터 값은 가지고 있는 것만으로도 오류(Undefined behavior)이거니와, 서로 다른 배열의 두 포인터를 비교하는 것 역시 Undefined behavior입니다.

자세히 설명하자면, a 배열이 선언된 곳(42번째 줄)은 for문 내부입니다. 따라서 for문이 끝날 때 (66번째 줄)마다 a 배열은 더 이상 존재하지 않게 되고, a를 참조하거나 그 값을 가지고 있는 것만으로도 C언어의 규칙을 위반하는 것이 됩니다. 우리가 사용하는 컴파일러는 그 점을 이용해서 char a[20];을 할 때마다 새로운 메모리를 할당하지 않고 기존에 사용했던 메모리를 재사용하도록 컴파일합니다.

그렇다고 char a[20]; 을 for문 밖에 선언해도 작동하지 않습니다. 문자열을 받을 때마다 포인터가 가리키는 문자열이 덮어씌워지기 때문입니다. 결국 std::map<char*, char*>는 잘못된 클래스고, 제대로 동작할 길이 없습니다. std::map 내부에서는 strcmp 따위를 사용하지 않기 때문입니다. 오직 비교연산자 '<'만 사용합니다. C언어를 배우셨다면 '<' 로 char* 타입 문자열 두 개를 비교하는 것이 제대로 작동하지 않는다는 걸 아실 겁니다. char*는 문자열 타입이 아니라 포인터 타입이기 때문입니다.

해결방법은 제대로 된 문자열 타입인 std::string을 이용하는 것입니다. std::string에는 문자열 비교연산자 '<'가 정의되어 있습니다.

his130   2년 전

친절한 설명 너무나 감사합니다!!

댓글을 작성하려면 로그인해야 합니다.