2011-01-15 6 views
0

BSTree라는 이진 검색 트리 클래스가 있습니다. 그것은 하나의 멤버 인 트리의 루트 노드를 사용했습니다. 노드의 유형은 BSTNode 구조체에 의해 정의됩니다. 하지만 두 멤버를 비교하는 데 사용되는 함수에 대한 포인터 인 다른 멤버를 추가했습니다. 그때부터 문제가 시작되었습니다.포인터 포인터에 주소를 할당하면 세그먼트 화 오류가 발생합니다.

인터페이스 :

template <typename T> 
struct BSTNode { 
public: 
    struct BSTNode<T> *left; 
    struct BSTNode<T> *right; 
    T key; 
    BSTNode<T>(T element){ key = element;} 
}; 

template <typename T> 
class BSTree { 
private: 
    BSTNode<T> *root; 
    int (*compare)(T el1, T el2); // this is the new member 
public: 
BSTree<T>(int (*cmp)(T el1, T el2)) {root = NULL; compare = cmp;} 
    //... 

함수 BSTree :: 추가, 트리에 물건을 추가, 루트 노드에 대한 포인터에 대한 포인터를 사용합니다. 이 함수는 새로운 'compare'멤버를 추가 한 후에 파열되었습니다.

기능 정의 :

template <typename T> 
BSTNode<T>* BSTree<T>::add(T element) { 
    BSTNode<T> **node; 
    printf("&root = %p\n", &root); 
    printf("node = %p\n", node); //must be NULL 
    printf("compare = %p\n", (int(*)(T, T))compare); //address stored in fn pointer 
    node = &root; /////////// THIS PART produces the segmentation fault. //////// 
    printf("succeeded"); 
    //... 

함수 호출 (주의) :

BSTree<int> bst(&stdcomp); //stdcomp is the integer compare function 
bst.add(6); 
//... 

다음과 같이 기능이 시작 (내가 추락 정확한 라인을 찾기 위해 추가 된 몇 가지의 printf 선이) 출력 :

&root = 0x7fff5fbff8c0 
node = 0x0 
compare = 0x100001325 
Segmentation fault 

특히 나에게 당황한 것은 할당이 실패하고 심지어 thoug h 포인터 포인터 '노드'에 저장된 주소를 역 참조하지 않으며 '노드'는 지역 변수이고 참조 해제되지 않습니다. 나는 불법 메모리 접근이 어디에서 발생 하는지를 모른다. 노드를 여러 리터럴 값 (예 : NULL 또는 0x1)으로 초기화하려고 시도했지만 오류가 발생하지 않았습니다. 인쇄 된 내용에 따라 올바른 주소가 할당 된 클래스에 함수 포인터를 추가 한 후에 만 ​​실패했습니다. 템플릿의 오용과 관련이 있습니까?

덧붙여서 BSTree 템플릿은 typenames int와 const char *로 인스턴스화됩니다. 각각은 올바르게 할당 된 다른 비교 함수를 사용합니다 (생각합니다). 필자는 추가 기능을 테스트했으며 둘 다 오류를 생성했습니다. printf%pvoid에 대한 포인터를 기대하고 있지만, 함수 포인터를 전달 -

+0

과부하 연산자 =가 트리거되었을 수 있다고 생각하지 않습니까? – Aron

+0

nope. 내가 연산자를 오버로드하지 못했고 클래스에 슈퍼 클래스가 없습니다. S –

+0

왜 'BSTNode ** node'입니까? 왜 포인터 대 포인터가 필요한지 모르겠습니다. –

답변

0
printf("compare = %p\n", (int(*)(T, T))compare); 

이 정의되지 않은 동작입니다. 함수 포인터는 void*으로 변환 할 수 없습니다.

디버거에서 프로그램을 실행하여 오류를 일으키는 것으로 의심되는 과제가 있는지 확인하는 것이 좋습니다. 스택 스매싱 등이 될 수 있습니다. 할당 자체는 스택을 참조하는 작업 만 호출해야합니다.

+1

함수 포인터는 대부분의 아키텍처에서 void로 변환 될 수 있지만 어쨌든 좋은 점이 밝혀졌습니다. 나는 명백한 던지기없이 하나를 보았 더라면 나는 여전히 떨렸다. 그러나 이것은 절대 변환 할 수없고 스택의 불균형을 초래할 수있는 멤버 함수에 대한 포인터처럼 보입니다. – Joshua

+0

그래, 할 일이 무서운 거 알아, 미안해. 그것은 내 아치에서 작동하며 비회원 함수에 대한 포인터입니다. 걱정하지 마십시오. 뚱뚱한 포인터가 아니라고 확신합니다. 그렇지만 이러한 가정을하지 않아도된다는 것을 잘 알고 있습니다 ... 이 문제는 실제로 스택과 관련이있을 수 있습니다. 프로그램을 중단시키는 로컬 변수에 대한 할당이 거의 확실하기 때문입니다. –

+0

@ user451963 : 거의 확실합니까? 디버거에서 실행 했습니까? 충돌하는 정확한 명령어는 무엇이며 'add'의 디스 어셈블리에서 어디에 있습니까? – jpalecek

1

printf("succeeded"); 호출 후 세그먼테이션 결함이 발생합니다. 그 printf에는 개행이 포함되지 않으며 사용자의 출력은 아마 라인 버퍼 모드 일 것입니다. 따라서 'succeeded'문자열은 stdout 버퍼로 들어가지만 화면에는 나타나지 않습니다. stdout을 unbuffered 모드로 두거나 문자열에 \n을 붙이십시오. 또는 각 출력 후에 fflush(stdout);을 붙이면 stdout 버퍼링 모드에 관계없이 버퍼가 플러시됩니다.

+0

또는 다른 사람과 마찬가지로 디버거를 사용할 수 있습니다. 나는 왜 그가 segfault를 찾는 것처럼 간단하게 printfing하고 있는지 알지 못합니다. –

관련 문제