2011-01-15 2 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'. Функция начинается следующим образом (она имеет некоторый PRINTF строку я добавил, чтобы найти точную линию, разбитую):

Функции Определение:

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); 
//... 

Выход:

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

Что особенно озадачивает меня, так это то, что назначение не срабатывает, даже h он не разыскивает адрес, который хранится в моем узле указателя на указатель, а «node» является локальной переменной и не разыменовывается; Я не знаю, где происходит незаконный доступ к памяти. Я попытался инициализировать узел несколькими буквальными значениями (например, NULL или 0x1), и они не вызвали ошибку. Это произошло только после того, как я добавил указатель функции к классу, который в соответствии с тем, что напечатан, получает правильный адрес. Имеет ли это какое-либо отношение к неправильному использованию шаблонов?

Кстати, шаблон BSTree создается экземплярами типа int и const char *, каждый из которых имеет другую функцию сравнения, которая правильно назначена (я думаю). Я протестировал их функцию добавления, и оба вызвали ошибку.

+0

Я не предполагаю, что у вас есть перегрузка оператора =, который может срабатывать? – Aron

+0

nope. я не перегружал любого оператора, а мои классы не имеют суперклассов: S –

+0

Почему у вас есть 'BSTNode ** node'? Я не понимаю, почему нужны указатели на указатели. –

ответ

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

Это неопределенное поведение - printf «s %p ожидает указатель на void, но передать указатель на функцию. Указатели функций не конвертируются в void*.

Я рекомендую вам запустить программу в отладчике, чтобы убедиться, что это действительно то назначение, которое, как вы подозреваете, вызывает ошибку. Это может быть разбиение на стол и т. Д. Само присваивание должно вызывать операции, ссылающиеся на стек.

+1

Оказывается, что указатели на функцию конвертируются в void на большинстве архитектур, но в любом случае это хорошая точка. Я все еще дрожу, если увижу одно без явного приведения. Тем не менее, это выглядит как указатель на функцию-член, который определенно не конвертируется и может разбалансировать стек. – Joshua

+0

Да, я знаю, что это ужасно, извините. Он работает в моей арке, и это указатель на функцию, отличную от члена, не беспокойтесь, я уверен, что это не толстый указатель, но я хорошо знаю, что я не должен делать эти предположения ... Проблема может быть действительно связана с стеком, так как я почти уверен, что это назначение локальной переменной, которая приводит к сбою программы. –

+0

@ user451963: Почти уверен? Вы запустили его под отладчиком? Какова точная инструкция, которая рушится и где она находится при разборке 'add'? – jpalecek

1

Ошибка сегментации происходит после вызова printf("succeeded");, так как этот printf не включает новую строку, и ваш выход, вероятно, работает в режиме с буферизацией. Таким образом, строка «successed» входит в буфер stdout, но не появляется на экране. Либо введите stdout в небуферизованный режим, либо вставьте строку \n в строку. Или еще лучше, поместите fflush(stdout); после каждого printf, чтобы буфер сбросился независимо от режима буферизации stdout.

+0

ИЛИ он может просто использовать отладчик, как и любой другой. Я не понимаю, почему он печатает для чего-то так же просто, как найти segfault. –

Смежные вопросы