Ошибка сегментации при вызове конструктора класса - PullRequest
0 голосов
/ 22 апреля 2020

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

Основной файл выглядит следующим образом:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <string.h>
#include <time.h>
using namespace std;

#include "tabeladesimbolos.hpp"
typedef char * String;
typedef int * Integer;


int main(int argc, char *argv[])
{
    fstream arqTexto;

    /* abra arquivo com texto */
    arqTexto.open(argv[1]);

    if (arqTexto.fail())
    {
        cout << "ERRO: arquivo" << argv[1] << "nao pode ser aberto.\n";
        exit(EXIT_FAILURE);
    }

    arqTexto.close();

    string nome_arquivo = argv[1];

    /* crie a ST*/
    cout << "criando ST...\n";

    /* usadas para medir tempo de processamento */
    clock_t start, end;
    double elapsed = 0;

    start = clock();
    vetorDes *st = new vetorDes(nome_arquivo);
    end = clock();

    /* calcule o tempo */
    elapsed = ((double)(end - start)) / CLOCKS_PER_SEC;
    cout << "arquivo lido e ST construida em " << elapsed << " segundos\n";

    delete st;

    return 0;
}

Ошибка происходит в следующая строка:

vetorDes *st = new vetorDes(nome_arquivo);

Файл с конструктором (tabeladesimbolos.hpp):

#include <string>
#include <string.h>
#include <iostream>
#include <fstream>
#include <vector>

typedef char * String;
typedef int * Integer;
using namespace std;

struct Valor
{
    String chave;
    Integer valor;
};

class vetorDes
{
    vector<Valor> vetor;

public:
    vetorDes(string nomeArquivo);
    void insere(String chave, Integer valor);
    Integer devolve(String chave);
};

vetorDes::vetorDes(string nomeArquivo)
{
    ifstream arqTexto;
    String palavra;
    Integer aux = nullptr;
    vetor.reserve(10000);
    arqTexto.open(nomeArquivo);
    while (arqTexto >> palavra)
    {
        aux = devolve(palavra);
        if (aux == nullptr)
        {
            int* um = new int;
            *um = 1;
            insere(palavra, um);
        }
        else
        {
            (*aux)++;
        }
    }
}

void vetorDes::insere(String chave, Integer valor)
{
    Valor *aux = new Valor;
    aux->chave = (String) malloc(20*sizeof(char));
    strcpy(aux->chave, chave);
    aux->valor = valor;
    int maxsize = vetor.max_size();
    int currentsize = vetor.size();
    vetor.push_back(*aux);
    return;
}

Integer vetorDes::devolve(String chave)
{
    for (std::size_t i = 0; i < vetor.size(); ++i)
    {
        String teste = vetor[i].chave;
        if (!strcasecmp(teste, chave))
        {
            return vetor[i].valor;
        }
    }
    return nullptr;
}

Мой отладчик возвращает меня к этому последнему} в конструкторе без ошибок, что приводит я верю, что проблема в том, как я распределяю что-то, поскольку это происходит только тогда, когда программа пытается завершить sh вызов "new vetorDes".

Полное сообщение об ошибке:

Program received signal SIGSEGV, Segmentation fault.
__GI___libc_free (mem=0x3b002e6f746e6174) at malloc.c:3103

Что я делаю не так? Чего мне не хватает?

Ответы [ 2 ]

0 голосов
/ 22 апреля 2020
String palavra; 
...
while (arqTexto >> palavra)

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

0 голосов
/ 22 апреля 2020

__GI___libc_free (mem=0x3b002e6f746e6174)

Указатель 0x3b002e6f746e6174 явно недействителен:

Можно с уверенностью предположить, что у вас есть какое-то переполнение кучи (или другое повреждение кучи). Используйте Valgrind или Address Sanitizer , чтобы найти ошибку.

Как отмечал Н.М., вы делаете себе плохую услугу, скрывая указатели за этими typedefs:

typedef char * String;
typedef int * Integer;

Ошибка будет гораздо более заметной, если вы этого не сделаете:

char *palavra;  // uninitialized pointer
...
while (arqTexto >> palavra) // BUG: writes to random memory
...