C ++ удаляет указатель на символ, выделенный с новым - PullRequest
3 голосов
/ 24 января 2020

В этом коде я получаю числа из файла, когда первое число является размером 2D-массива.

В моем коде я определяю

char *filename=new char;

(I должен использовать char * имя файла, это упражнение ..) Все работает нормально, до того момента, пока я пытаюсь delete. и delete, и delete[] выдают ошибку и сбой моей программы.

Вот мой полный код:

#include <iostream>
#include <fstream>
using namespace std;
double **readmat(char *filename, int *size)/////question 2
{
    ifstream read(filename);
    cout << filename << endl;
    if (!read)
    {
        cout << "Can't open file!" << endl;
        exit(1);
    }
    read >> *size;
    double **mat = new double*[*size];
    for (int i = 0; i < *size; i++)
    {
        mat[i] = new double[*size];
        for (int j = 0; j < *size; j++)
        {
            read >> mat[i][j];
        }
    }    
    read.close();    
    return mat;
}
int main()
{
    int size;
    char *filename = new char;
    filename = "text.txt"; 

    double **arr = readmat(filename, &size);
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            cout << arr[i][j]<<"  ,  ";
        }
        cout << endl;
    }
    cout << endl;

    delete filename; //<-------- this crashed my code
    for (int i = 0; i < size; i++)
    {
        delete[] arr[i];
    }
    delete[] arr;
    return 0;
}

Вот так выглядит мой файл:

enter image description here

Вот так выглядит консольное приложение после запуска кода:

enter image description here

Какой это то, что я ожидаю получить, но я получаю эту ошибку:

enter image description here

Кто-нибудь есть какие-либо идеи, что может произойти, и что я могу сделать Исправить это?

Ответы [ 5 ]

5 голосов
/ 24 января 2020

Вы пытаетесь delete a char*, который не указывает на память, выделенную с помощью new.

В этой строке:

char *filename = new char;

Вы делаете new некоторая память (одна char, а не строка char с). Но затем в этой строке:

filename = "text.txt"; 

Вы изменяете указатель char*, чтобы указывать на совершенно другую память, таким образом, утечка памяти, которую вы new 'редактировали.

Затем в этой строке :

delete filename;

Вы пытаетесь delete буквально "text.txt", а не char you new 'ed. Вот почему вы делаете sh.

Для того, что вы пытаетесь сделать, вам нужно сделать это вместо этого:

char *filename = new char[strlen("text.txt")+1];
strcpy(filename, "text.txt");
...
delete[] filename;

Однако вам не следует использовать new / new[] для filename вообще. Вместо этого используйте std::string:

#include <fstream>
#include <string>

double **readmat(const std::string &filename, int *size)
{
    std::ifstream read(filename.c_str());
    ...
}

int main()
{
    int size;
    double **arr = readmat("text.txt", &size);
    ...
}

В качестве альтернативы:

#include <fstream>
#include <string>

double **readmat(const char *filename, int *size)
{
    ifstream read(filename);
    ...
}

int main()
{
    int size;
    std::string filename = "text.txt";

    double **arr = readmat(filename.c_str(), &size);
    // or simply:
    // double **arr = readmat("text.txt", &size);
    ...
}

И затем, пока вы это делаете, вам также не следует использовать new[] для своей матрицы. Используйте std::vector вместо:

#include <vector>

std::vector< std::vector<double> > readmat(char *filename)
{
    ...

    int size;
    read >> size;

    std::vector< std::vector<double> > mat(size);
    for (int i = 0; i < size; i++)
    {
        mat[i].resize(size);
        for (int j = 0; j < size; j++)
        {
            read >> mat[i][j];
        }
    }    

    return mat;
}

int main()
{
    ...

    std::vector< std::vector<double> > arr = readmat("text.txt");
    size_t size = arr.size();

    for (size_t i = 0; i < size; i++)
    {
        for (size_t j = 0; j < size; j++)
        {
            std::cout << arr[i][j] << "  ,  ";
        }
        std::cout << endl;
    }
    std::cout << endl;

    return 0;
}
4 голосов
/ 24 января 2020
char *filename = new char;
filename = "text.txt";

Это создает новый символ, а затем пропускает его, потому что указатель filename переназначается чему-то статически объявленному.

Следовательно, позже вы удалите что-то другое, чем исходный символ.

Несколько проблем здесь (использование нового вместо нового [] и т. Д. c). Предложение, забудьте все и используйте std :: string и STL.

3 голосов
/ 24 января 2020

Это источник вашей проблемы:

char *filename = new char;
filename = "text.txt";

filename больше не указывает на динамически распределенную память, поэтому вы не можете delete это (и вы также теряете 1 байт Память). Измените вашу декларацию на const char *filename = "test.txt"; и удалите delete filename;.

2 голосов
/ 24 января 2020

new char выделяет один символ в куче. Большинство функций, которые принимают const char* в качестве параметра, ожидают указатель на первый элемент массива с нулевым символом (\0) в качестве разделителя (строка стиля C).

Вы даже не сможете назначить строковый литерал переменной типа char *, по крайней мере, в стандартном C ++. Вам также не нужно динамически выделять память для строковых литералов, просто используйте

const char *filename = "text.txt"; 

Тогда вы также не удаляете указатели на строковые литералы. (Это то, что вызывает ошибку, скорее всего, вы удалили указатель, который указывал на строковый литерал)

0 голосов
/ 24 января 2020

Просто замените

char* filename = new char;

на

const char* filename = "text.txt";

и удалите

delete filename;

Так будет выглядеть ваш окончательный код

int main()
{
    int size;
    const char *filename = "text.txt"; 

    double **arr = readmat(filename, &size);
    for (int i = 0; i < size; i++)
    {
        for (int j = 0; j < size; j++)
        {
            cout << arr[i][j]<<"  ,  ";
        }
        cout << endl;
    }
    cout << endl;

    for (int i = 0; i < size; i++)
    {
        delete[] arr[i];
    }
    delete[] arr;
    return 0;
}
...