C++ Создание двоичного дерева поиска: ошибка EXC_BAD_ACCESS. Плохой алгоритм или ошибка кодирования?

Вопрос: Я продолжаю получать сообщение об ошибке exc_bad_access (код процесса 11). Это из-за плохого алгоритма или просто ошибки кодирования? Может ли кто-нибудь помочь мне исправить это?

Мое задание на уроке — создать бинарное дерево поиска, узлы которого могут хранить имя, баланс и ключ. Узлы должны быть организованы и найдены с помощью ключа. Это дерево должно поддерживать вставку, неупорядоченный обход и поиск по ключу (эту функцию я еще не создал). Я также включил несколько других функций, чтобы облегчить их создание. Если это имеет значение, я использую CLion на OSX High Sierra. Кроме того, я получаю сообщение об ошибке при первом запросе на ввод информации об узле, ошибка, похоже, не связана с самим вводом.

//Genghis Khan
#include <iostream>
#include <vector>
using namespace std;
class node
{
public:
    int key;
    string name;
    double balance;
    node *leftptr;
    node *rightptr;
    friend class tree;
};
class tree
{
public:
    node *root, *temp, *v;

    //Constructor
    tree()
    {
        root = NULL;
        temp = root;
    }

    bool empty()
    {
        return(root == NULL);
    }


    bool isleaf(node *x)
    {
        return((x->leftptr == NULL) && (x->rightptr == NULL));
    }  

    void inorder(node *temp)
    {
        if(~isleaf(temp)) 
        {
            inorder(temp->leftptr);
            cout << "Name: " << temp->name << " " << "Balance: " << 
    temp->balance << " " << "Key: " << temp->key;
            inorder(temp->rightptr);
        }
    }

    node* createnode()
    {
        v = new node;
        cout << "Enter name (string): " << endl;
        getline(cin, v->name); 
        cout << "Enter key (integer): " << endl;
        cin >> v->key;
        cout << "Enter balance (double): " << endl;
        cin >> v->balance;
        return(v);
    }

    void set()
    {
        temp = root;
    }

    void insert(node *v)
    {
        while(~isleaf(temp)) 
        {
            if((v->key < temp->key))
            {
                temp = temp->leftptr;
                insert(v);
            }
            else if(v->key > temp->key)
            {
                temp = temp->rightptr;
                insert(v);
            }
        }
    temp->key = v->key;
    temp->balance = v->balance;
    temp->name = v->name;
    }

};

int main()
{
    int n;
    cout << "Enter number of people: ";
    cin >> n;

    //Creating instance of tree, inserting all data into tree
    tree b;
    for(int i = 0; i < n; i++)
    {
        b.set();
        node *a = b.createnode();
        b.insert(a);
    }

    //inorder part
    b.set();
    b.inorder(b.temp);

}

Функции (псевдокод):

1. function isleaf(x): return(x's left pointer and x's right pointer are both NULL)

2. function set(): set temp to root //temp will be reset every time an insertion, traversal, or search occurs

3. function createnode(): 

   v is  a new node

   get all the fields for v 

   return v

4. function insert(v)

   while(not isleaf(temp)):  
   -if(v's key < temp's key)
  temp = temp's left pointer (to the lower value child node)    
  insert(node *v)

   -if(v's key > temp's key)  
  temp = temp's right pointer (to the higher value child node)   
  insert(node *v)  
  end while  
  duplicate v's data to temp, now that temp is a leaf

5. function inorder(temp):  
   if(not isleaf(temp):  
   inorder(temp's left pointer)  
   output all info in temp node  
   inorder(temp's right pointer)

Основной алгоритм

для количества вводимых узлов:
1. set
2. node *a = createnode
3. insert(a)

Обновлять

Похоже, ошибка исходит из строки «if ((v-> key ‹ temp-> key))».


person arnavlohe15    schedule 14.11.2017    source источник
comment
Вы пытались пройти через это с помощью отладчика? Может ли быть ошибка в b.set()?   -  person George Birbilis    schedule 14.11.2017
comment
if(~isleaf(temp)) выглядит странно. Зачем вам переворачивать логическое значение? Возможно, вам здесь нужно if(!isleaf(temp)). g++ с -pedantic -Wall -Wextra помечает это предупреждением. Цепочка инструментов по умолчанию для xcode, clang, вероятно, также предупредит вас.   -  person user4581301    schedule 14.11.2017
comment
@user4581301 user4581301 Я не знал, что это правильный синтаксис. Благодарю вас!   -  person arnavlohe15    schedule 14.11.2017
comment
Рекомендуйте отредактировать свой вопрос, чтобы добавить набор входных данных, который вызывает эту ошибку.   -  person user4581301    schedule 14.11.2017
comment
Несвязанный: у вас есть потенциальная ошибка здесь: getline(cin, v->name); пользователь, скорее всего, нажмет клавишу ввода в cin >> n;, чтобы ввести значение для n и получить следующее приглашение. cin >> n; прочитает и преобразует число (если оно конвертируемое. Вы не проверили. Упс.) и оставит конец строки от нажатия Enter, чтобы getline(cin, v->name); забрал. getline мгновенно находит конец строки и выдает пустую строку. Затем имя будет прочитано для key и прервет поток. Размещение cin.ignore после cin >> n; необходимо.   -  person user4581301    schedule 14.11.2017
comment
Убедитесь, что v и temp указывают на допустимую память.   -  person user4581301    schedule 14.11.2017
comment
У вас есть переменная-член v, которая выглядит так, как будто она затенена некоторой локальной переменной vs. Я не думаю, что вам это нужно как переменная-член. Также серьезно переосмыслите всю эту temp штуку. Вот что убивает вашу программу. Это почти наверняка NULL при первой вставке, потому что у вас еще нет root.   -  person user4581301    schedule 14.11.2017


Ответы (1)


EXC_BAD_ACCESS просто означает, что вы пытаетесь получить доступ к недопустимой памяти. Кратко говоря, ваша функция isleaf не проверяет, является ли x нулевым.

Могут быть и другие ошибки, вы можете отладить и найти их самостоятельно.

person iamnoten    schedule 14.11.2017
comment
Ответы должны сделать некоторую попытку решить проблему. - person user4581301; 14.11.2017
comment
@iamnoten Ранее я пробовал ваше предложение проверить, является ли x нулевым, и только затем проверить его левый и правый указатели, но это, похоже, не имело значения. - person arnavlohe15; 14.11.2017
comment
@arnavlohe15 в вашей функции вставки сначала проверьте, пусто ли дерево, если оно пусто, просто назначьте узел root. Если не пусто, перейдите к циклу while. - person iamnoten; 14.11.2017