Как освободить память динамического массива struct - PullRequest
0 голосов
/ 22 апреля 2011

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

при удалении 2-го элемента массива размером 3, я перемещаю 3-й элемент на 2-ю позицию, а затем удаляю последний. При удалении последнего я всегда получаю сообщение об ошибке ... Есть ли кто-нибудь, кто может найти решение для меня?

struct myFriend {
    myFriend() {
        number=0;
        hobbys = new char*[10];
    }
    int number;
    char* name;
    char** hobbys;
};
int main() {
    myFriend* friendList = new myFriend[10];

    myFriend* tempFriend = new myFriend;
    tempFriend->number=1;
    tempFriend->name = "ABC";

    myFriend* tempFriend2 = new myFriend;
    tempFriend2->number=2;
    tempFriend->name = "XYZ";

    myFriend* tempFriend3 = new myFriend;
    tempFriend3->number=3;
    tempFriend3->name = "123";

    friendList[0] = *tempFriend;
    friendList[1] = *tempFriend2;
    friendList[2] = *tempFriend3;

    friendList[1] = friendList[2]; //move 3rd element on 2nd position
    delete &(friendList[2]); //and delete 3rd element to free memory
}

Ответы [ 6 ]

2 голосов
/ 22 апреля 2011

Я заметил две вещи.(1) Вы, очевидно, должны «создавать функции для добавления или удаления элементов», но вы этого не сделали, вы создали только одну функцию.(2) Вы делаете свою работу тяжелее, чем нужно, используя структуру, которая также должна управлять памятью.Я предлагаю вам использовать более простую структуру.

По сути, ваше назначение - создать простой «векторный» класс, поэтому я предлагаю вам это сделать.Начните с пустой структуры.Если учитель требует, чтобы вы использовали myFriend структуру, как написано, вы можете добавить, что в после вы закончите делать свой вектор похожим на функции.Я собираюсь предположить, что вам еще не разрешено посещать занятия, потому что большинство инструкторов допускают ошибку, оставляя это до последнего.

struct MyStruct {
    int value; // start with just one value here. Dealing with pointers is more advanced.
};

MyStruct* array;
int size;
int capacity;

void addMyStruct(MyStruct& value); // adds a MyStruct object to the end.
void removeMyStructAtPosition(int position); // removes the MyStruct object that is at 'position'

// I leave the functions for you to implement, it's your homework after all, but I give some clues below.

void addMyStruct(MyStruct& value) {
    // First check that there is enough capacity in your array to hold the new value. 
    // If not, then make a bigger array, and copy all the contents of the old array to the new one.
    // (The first time through, you will also have to create the array.)
    // Next assign the new value to array[size]; and increment size
}

void removeMyStructAtPosition(int position) {
    // If the position is at end (size - 1,) then simply decrement size.
    // Otherwise you have to push all the structs one to the left (array[i] = array[i + 1])
    // from position to the end of the array.
}

int main() {
    // test your new class here.
    // don't forget to delete or delete [] any memory that you newed.
}
2 голосов
/ 22 апреля 2011

Невозможно удалить подмножество из массива, выделенного new []

myFriend* friendList = new myFriend[10];

У вас есть один целый массив

+------------------------------------------------------------------+
|  friendList[0]  |  friendList[1]  |    .....  |   friendList[9]  | 
+------------------------------------------------------------------+

Вы не можете delete &(friendList[2]). Вы получаете от C++ целый массив из 10 элементов. Этот массив начинается с friendList (или &(friendList[0])).

operator delete с указателем на адрес, возвращаемый new (т.е. friendList), является действительным только.

2 голосов
/ 22 апреля 2011

Почему вы создали временные переменные?Они даже не нужны.

Если вы используете std::vector и std::string, проблема, с которой вы столкнетесь, автоматически исчезнет:

std::vector<myFriend> friendList(10);

friendList[0]->number=1;
friendList[0]->name = "ABC";

friendList[1]->number=2;
friendList[1]->name = "XYZ";

friendList[2]->number=3;
friendList[2]->name = "123";

Чтобы заставить ее работать, вам следуетпереопределите вашу структуру следующим образом:

struct myFriend {
    int number;
    std::string name;
    std::vector<std::string> hobbys;
};

Если вас попросят работать с необработанными указателями, вы должны сделать что-то вроде этого:

struct Friend 
{
    int    number;
    char*  name;
};

Friend * friends = new Friend[3];

friends[0]->number=1;
friends[0]->name = new char[4];
strcpy(friends[0]->name, "ABC");

//similarly for other : friends[1] and friends[2]

//this is how you should be deleting the allocated memory.
delete [] friends[0]->name;
delete [] friends[1]->name;
delete [] friends[2]->name;

delete [] friends; //and finally this!

И если вы это сделаетелюбое из следующих действий будет неверным и приведет к неопределенному поведению:

delete friends[2];    //wrong
delete &(friends[2]); //wrong
0 голосов
/ 22 апреля 2011

Чтобы сделать вашу домашнюю работу, я бы предложил больше узнать об указателях, операторах new / delete, операторах new [] / delete [] (не путать с операторами new / delete) и создании / копировании объектов / конструкторах / деструкторов. Это базовые возможности C ++, и ваша задача заключается в следующем.

Чтобы указать некоторые направления:

1) Когда вы динамически распределяете объект следующим образом

MyType* p = new MyType;

или

MyType* p = new MyType(constructor_parameters);

вы получаете указатель p на созданный объект (new выделяет память для одного объекта типа MyType и вызывает конструктор этого объекта).

После того, как ваша работа с этим объектом закончена, вы должны позвонить

delete p;

delete вызывает деструктор объекта, а затем освобождает память. Если вы не позвоните delete ваша память просочилась. Если вы вызываете его более одного раза, поведение не определено (вероятно, повреждение кучи, которое может привести к сбою программы - иногда в очень странный момент).

2) Когда вы динамически распределяете массив следующим образом

MyType* p = new MyType[n];

вы получаете указатель p на массив n созданного объекта, расположенного последовательно в памяти (new[] выделяет один блок памяти для n объектов типа MyType и вызовов конструкторы по умолчанию для каждого объекта).

Вы не можете изменить количество элементов в этом динамическом массиве. Вы можете только удалить его. После окончания работы с этим массивом вам нужно вызвать

delete[] p;  // not "delete p;"

delete[] вызывает деструктор каждого объекта в массиве, а затем освобождает память. Если вы не позвоните delete[], у вас утечка памяти. Если вы вызываете его более одного раза, поведение не определено (вероятно, сбой программы). Если вы вызываете delete вместо delete[], поведение не определено (вероятно, деструктор вызывается только для первого объекта, а затем пытается освободить блок памяти - но это может быть что угодно).

3) Когда вы назначаете структуру / класс, вызывается operator=. Если у вас нет operator=, явно определенного для вашей структуры / класса, то генерируется неявный оператор = (он выполняет присваивание каждого нестатического члена вашей структуры / класса).

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

Кажется, вопрос в том, чтобы управлять динамическим массивом.Основная проблема в том, что он использует массив friendList.Использовать массив указателей на friendList:

struct myFriend {
    myFriend() {
        number=0;
        hobbys = new char*[10];
    }
    int number;
    char* name;
    char** hobbys;
};
int main() {
    myFriend** friendList = new myFriend*[10];

    myFriend* tempFriend = new myFriend;
    tempFriend->number=1;
    tempFriend->name = "ABC";

    myFriend* tempFriend2 = new myFriend;
    tempFriend2->number=2;
    tempFriend->name = "XYZ";

    myFriend* tempFriend3 = new myFriend;
    tempFriend3->number=3;
    tempFriend3->name = "123";

    friendList[0] = tempFriend;
    friendList[1] = tempFriend2;
    friendList[2] = tempFriend3;

    friendList[1] = friendList[2]; //move 3rd element on 2nd position
    delete friendList[2]; //and delete 3rd element to free memory
}

Но все остальные правы - есть основные проблемы с выделением памяти для «хобби» и «имени», которые вам нужныразобраться отдельно.

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

Размер массива фиксирован и равен 10, поэтому вам не нужно удалять из него какие-либо элементы.Но вам нужно удалить элементы name и hobbys из friendList[1]до того, как перезаписать его).Здесь есть две проблемы:

  1. Вы устанавливаете friendList[0]->name = "ABC"; Здесь "ABC" - это константа строка с нулевым окончанием где-то в памяти.Вы не можете удалить его.Таким образом, вы должны сделать копию.
  2. Вы хотите удалить hobby[i] всякий раз, когда он был назначен.Но в вашем коде вы не можете сказать, был ли он назначен.Таким образом, вы должны установить каждый элемент на 0 в конструкторе, чтобы позже вы знали, какие элементы удалить.

Правильное место для удаления этих элементов - в деструкторе myFriends.

...