Присвоение адреса указателю на указатель дает ошибку сегментации - PullRequest
0 голосов
/ 15 января 2011

У меня есть класс бинарного дерева поиска, 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 :: add, которая добавляет материал в дерево, использует указатель на указатель на корневой узел.Эта функция прервалась после того, как я добавил новый элемент сравнения.Функция начинается следующим образом (у нее есть несколько строк 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

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

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

Ответы [ 2 ]

1 голос
/ 15 января 2011

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

0 голосов
/ 15 января 2011
printf("compare = %p\n", (int(*)(T, T))compare);

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

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

...