Использование C ++ Custom HashTable дает SegFault - PullRequest
0 голосов
/ 04 мая 2020

Мне пришлось реализовать Linked HashTable для проекта. Теперь я должен придумать упражнение и решить его, используя мою хэш-таблицу. Все работает просто отлично, за исключением того, что я получаю случайные ошибки Segfault.

Под случайностью я подразумеваю: это одна и та же строка кода, которая вызывает ее, но всегда в разное время, вызывает. Я проверял мой код в Atom, Codeblocks и в коде Visual Studio. И Atom, и CB выдали ошибку SegFault, но VS Code запустил ее без проблем.

ПРИМЕЧАНИЕ: ЭТО НЕ ПОЛНЫЙ / РЕАЛЬНЫЙ КОД. Он является частью файла заголовка, который включен в основной файл. cpp, который затем компилируется и запускается. Код:

#include <iostream>
#include <typeinfo>
#include <string>

using namespace std;

//List:
template<class T>
struct Node
{
  string data;
  Node *next;
};

class List
{
  private:
    Node *head, *tail;
    int length;
    friend class HashTable;
  public:
    List();
    List(const List &L);
    //~List() {delete this;};
    List& operator =(List L);
    int find(string);
    void insert(string value);
    void remove_head();
    void remove_poz(int);
    void remove_tail();
    void clear();
    void display();
};

List::List()
{
   head = NULL;
   tail = NULL;
   length = 0;
}

template<>
string List<string>::findByIndex(int ind)
{
    int i = 0;
    Node<string>* temp = new Node<string>;
    temp = head;
    while (temp != NULL)
    {
        i++;
        if (i == ind) return temp->data;
        temp = temp->next;
    }
    delete temp;
    return "-1";
}

template<class T>
void List<T>::remove_head()
{
  Node<T>* temp = new Node<T>;
  temp = head;
  head = head->next;
  delete temp;
  length--;
}

template<class T>
void List<T>::remove_pos(int pos)
{
  int i;
  Node<T>* curr = new Node<T>;
  Node<T>* prev = new Node<T>;
  curr = head;
  for (i = 1; i < pos; ++i)
  {
      prev = curr;
      curr = curr->next;
  }
  if (curr)
  {
    prev->next = curr->next;
    length--;
  }
  else cout << "Error" << endl;
}

template<class T>
void List<T>::remove_tail()
{
  Node<T>* curr = new Node<T>;
  Node<T>* prev = new Node<T>;
  curr = head;
  while (curr->next != NULL)
  {
      prev = curr;
      curr = curr->next;
  }
  tail = prev;
  prev->next = NULL;
  delete curr;
  length--;
}

//HashTable:
class HashTable
{
  private:
    List *table;
    float load, stored;
    int slots;
    friend class List;
  public:
    HashTable();
    HashTable(int);
    ~HashTable();
    int hashFunc(string key);
    int findTable(string);
    int findList(string);
    HashTable& operator =(const HashTable&);
    void resize();    //I need this one
    void insert(string);
    void remove(string);
    void clear(int);
    void clear();
    void display();
};

HashTable::HashTable()
{
  stored = 0;
  load = 0.00;
  slots = 15;
  table = new List[slots];
}

int HashTable::hashFunc(string key)
{
  int g, h = 0;
    unsigned int i;
    for (i = 0; i < key.size(); ++i)
    {
        h = (h << 4) + (int)(key[i]);
        g = h & 0xF0000000L;
        if (g != 0)
        {
            h = h ^ (g >> 24);
        }
        h = h & ~g;
    }
    return h % slots;
}

template<class T>
void HashTable<T>::remove(T value)
{
  int ind = hashFunc(value);
  int findInd = table[ind].findByValue(value);


  if (findInd == 0)
      table[ind].remove_head();

  else if (findInd < table[ind].length)
      table[ind].remove_pos(findInd);

  else table[ind].remove_tail();

  if (table[ind].isEmpty()) occupied--;
  stored--;
  load = stored / slots;
}

Функция, которая вызывает segfault: (Это будет вызываться снова и снова в al oop, пока в моей таблице больше нет элементов)

string reakcio(HashTable<string>& HT, int tarolok)
{
    const int anyagszam = rand() % 4 + 2; //Min 2, Max 5 anyag hasznalodik
    int i = 0, j;
    string anyagok[5];
    string eredmeny;

    for(j = 0; j < tarolok && i < anyagszam; ++j) //elemek kivetele
    {
        while(!HT.table[j].isEmpty())
        {
            anyagok[i++] = HT.table[j].findByIndex(1); //This line right here is the culprit :(
            HT.remove(anyagok[i-1]);
        }
    }

    const int siker = rand() % 4 + 0; //75% esely a sikerre
    if (siker)
    {
        eredmeny = anyagok[0];
        for(i = 1; i < anyagszam; ++i)
            eredmeny += " + " + anyagok[i];
    }
    else
        eredmeny = "Sikertelen reakcio";
    return eredmeny;
}

(Примечание: здесь показаны только те функции, которые могут понадобиться)

Каждый элемент моей хеш-таблицы или моих списков представляет собой случайное строковое значение длиной 10 символов. srand (время (NULL)) используется перед вызовом функции в main. cpp

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

Основной. cpp файл:

#include <iostream>
//#include "LinkedHash.h"
#include "functions.cpp"

int main()
{
  HashTable<string> Anyagok;
  int tarolok;

  tarol(Anyagok); //Stores the data from file, no problem here, functions.cpp
  tarolok = Anyagok.getSlots();

  srand(time(NULL));
  int i = 1;
  while (Anyagok.getStored() > 5 )
    cout<<reakcio(Anyagok, tarolok)<<" "<<i++<<endl;

  return 0;
}

LinkedHa sh .h содержит хеш-таблицу и список , функции. cpp содержит проблемную функцию c.

РЕДАКТИРОВАТЬ: По предложению я заменил

Node<string>* temp = new Node<string>;
temp = head;

часть на

Node<string>* temp = head;

Также удалена строка удаления. Но моя проблема все та же: /

1 Ответ

3 голосов
/ 04 мая 2020

Все работает просто отлично, за исключением того, что я получаю случайные ошибки Segfault

Тогда вообще ничего не работает.

В первом обзоре мало внимания уделяется углу в списке учебный класс. Необходимо определить правильное поведение для операции

  • для пустых списков * операция 1010 *
  • для первого и последнего элемента
  • ключ не найден во время поиска

Обнаружены существенные ошибки:

  • remove_head, remove_tail приведет к ошибке по пустому списку. голова пуста head-> next - неверный доступ к памяти. Подобные ошибки встречаются по всей реализации.
  • HashTable<T>::remove(T value) всегда что-то удалит. Даже если аргумент значения отсутствует в хеш-таблице. Это глубоко ошибочный
  • findByIndex, возвращающий «-1», не имеет смысла. «-1» является допустимым вводом.
  • Node<T>* temp = new Node<T>;temp = head;. Вы просто слили память. Вам нужно указатель на манипулировать адресами узлов . Вы не должны создавать экземпляры Nodes для получения указателя. Это не проблема (ie не заметно) для небольшого проекта, но неприемлемая для реальной реализации.
...