Как правильно освободить память в main, которая выделяется в функции через указатель, переданный по ссылке или по указателю? - PullRequest
2 голосов
/ 10 марта 2011

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

1. используя указатель на указатель:

void fun1(int **a, double **b, char **c)
{

    *a=new int[20];
    *b=new double[20];
    *c=new char[10];

    for (int i=0;i<20;i++){
        (*a)[i]=i;
        (*b)[i]=sqrt((double)((*a)[i]));
    }
    *c="0123456789";

}


int _tmain(int argc, _TCHAR* argv[])
{
    int *a;
    double *b;
    char *c;

    fun1(&a,&b,&c);
    cout<<"a & b are:"<<endl;
    for(int i=0;i<20;i++)
        cout<<a[i]<<"\t"<<b[i]<<endl;
    cout<<"c is: "<<c<<endl;

    delete[] a;
    delete[] b;
    delete[] c;
    return 0;
}

2. используя ссылку на указатель:

void fun1(int*& a, double*& b, char*& c)
{

    a=new int[20];
    b=new double[20];
    c=new char[10];

    for (int i=0;i<20;i++){
        a[i]=i;
        b[i]=sqrt((double)a[i]);
    }
    c="0123456789";

}


int _tmain(int argc, _TCHAR* argv[])
{
    int *a;
    double *b;
    char *c;

    fun1(a,b,c);
    cout<<"a & b are:"<<endl;
    for(int i=0;i<20;i++)
        cout<<a[i]<<"\t"<<b[i]<<endl;
    cout<<"c is: "<<c<<endl;

    delete[] a;
    delete[] b;
    delete[] c;
    return 0;
}

Большое спасибо!

Ответы [ 5 ]

8 голосов
/ 10 марта 2011

Это в fun1()

*c="0123456789";

, за которым следует в main()

delete[] c;

- неопределенное поведение, так как вы пытаетесь delete[] строковый литерал.

2 голосов
/ 10 марта 2011

Проблема не имеет ничего общего с тем, как вы передаете указатели, и не связана с тем, как вы инициализируете содержимое c.c заканчивает тем, что указывает на память, которая не была создана new [] и поэтому не может быть освобождена delete [].

1 голос
/ 10 марта 2011
int *a;
double *b;
char *c;

fun1(a,b,c);

Вы имели в виду:

int* a;
double* b;
char* c;

fun1(&a,&b,&c);

И тогда все в порядке.

Однако, как говорит sharptooth, ваш delete[] c сломан, потому что вы просто переназначили указатель настроковый литерал вместо копирования символов.


Пожалуйста, используйте std::vector и std::string вместо всей этой чепухи:

#include <iostream>
#include <string>
#include <vector>

void fun1(std::vector<int>& a, std::vector<double>& b, std::string& c)
{
    a.resize(20);
    b.resize(20);

    for (int i = 0; i < 20; i++) {
        a[i] = i;
        b[i] = sqrt((double)a[i]);
    }

    c = "0123456789";
}


int main(int argc, char* argv[])
{
    std::vector<int> a;
    std::vector<double> b;
    std::string c;

    fun1(a,b,c);

    std::cout << "a & b are: \n";
    for (int i = 0; i < 20; i++)
        std::cout << a[i] << "\t" << b[i] << " \n";

    std::cout << "c is: " << c << std::endl;
}
0 голосов
/ 10 марта 2011

То, что вы делаете, является билетом к катастрофе.Я настоятельно рекомендую использовать контейнеры stl.Обычно рекомендуется использовать контейнеры, которые обрабатывают освобождение для вас, потому что освобождение является частой причиной досадных ошибок.Старайтесь избегать необработанных указателей, они очень редко дают преимущество и усложняют вашу жизнь.

#include <vector>
#include <string>
#include <iostream>
using namespace std;

void fun1(vector<int>& a, vector<double>& b, string& c)
{
    size_t size = 20;
    a.resize(size);
    b.resize(size);
    for (int i=0;i<size;i++){
        a.at(i) = i;
        b.at(i) = sqrt(i); // auto conversion to double
    }
    c="0123456789";
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<int> a;
    vector<double> b;
    string c;

    fun1(a,b,c);
    cout<<"a & b are:"<<endl;
    for(int i=0;i<a.size();i++)
        cout<<a.at(i)<<"\t"<<b.at(i)<<endl;
    cout<<"c is: "<<c<<endl;

    return 0;
}
0 голосов
/ 10 марта 2011

Не существует "правильного" способа сделать это, дизайн вашей программы несовершенен. Тот же самый модуль кода, который выделяет динамическую память, должен быть тем же самым, который ее освобождает. Таким образом, если fun1 () находится в fun.c, в fun.c также должна быть другая функция, называемая cleanup () или чем-то еще, которая очищает беспорядок, созданный fun1 (). В противном случае ваши программы скоро превратятся в мир утечки памяти.

В этом случае лучшим вариантом будет позволить main () выделить память, а затем передать выделенные буферы в качестве параметра функции.

Эта концепция известна как "частная инкапсуляция" в объектно-ориентированном программировании.

...