如何释放动态结构数组的内存

Posted

技术标签:

【中文标题】如何释放动态结构数组的内存【英文标题】:How to free memory of dynamic struct array 【发布时间】:2011-04-22 11:17:52 【问题描述】:

作为一个从未处理过释放内存等问题的人,我的任务是创建一个动态结构数组并创建函数来添加或删除数组元素。删除时我必须释放不再需要的内存。

删除大小为 3 的数组的第二个元素时,我将第三个元素移动到第二个位置,然后删除最后一个。删除最后一个时,总是出错...有没有人可以为我找到解决方案?

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

【问题讨论】:

你应该改用std::vectorstd::string 对于据说使用字符数组的任务。但也许这会改变。尽管如此,这并不能解决真正的问题:(;) 您将必须跟踪从newdelete 返回的每个指针,准确一次。您还必须跟踪从new [] 返回的每个指针,并在该指针上只使用一次delete[]。猜猜为什么我们更喜欢向量和字符串! 【参考方案1】:

为什么要创建临时变量?他们甚至不需要。

如果你使用std::vectorstd::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

【讨论】:

问题是,学习如何处理数组是一项任务。也许允许使用字符串,但不幸的是没有办法使用向量。我猜肯定还有其他解决方案。 @Sebastian:好的。然后让我们解释一下你应该如何使用指针。 @Nawaz:我知道如何使用指针。我只是不知道如何删除数组元素。我只能删除整个数组,但这不是重点。我们必须使用这样的数组。动态数组(在结构中定义下一个和/或上一个元素)也是不允许的 - 这很容易。 @Blazes:哎呀。是的...让我解决它。【参考方案2】:

无法从new []分配的数组中删除子集

myFriend* friendList = new myFriend[10];

你有一个完整的数组

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

你不能delete &amp;(friendList[2])。 您从 C++ 获得 10 个元素的整个数组。 这个数组从friendList(或&amp;(friendList[0]))开始。

operator delete 带有指向由new 返回的地址的指针(即friendList)是有效的 仅限。

【讨论】:

你很准。他需要的是一个指针数组。我在上面发布了解决方案,但我将此标记为有用的点。【参考方案3】:

我注意到了两件事。 (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.

【讨论】:

【参考方案4】:

数组大小固定为 10,因此您无需从中删除任何元素。但是您确实需要删除friendList[1]namehobbys 元素(以及在覆盖它之前)。这里有两个问题:

    您正在设置friendList[0]-&gt;name = "ABC"; 这里,"ABC" 是内存中某处的常量 以零结尾的字符串。您无权删除它。所以你必须复制一份。 您想在分配hobby[i] 时删除它。但是在您的代码中,您无法判断它是否已分配。所以你必须在构造函数中将每个元素都设置为0,这样你以后才能知道要删除哪些元素。

删除这些元素的正确位置是在myFriends 的析构函数中。

【讨论】:

>作者试图删除它的代码在哪里? 好吧,这就是 OP 想要添加到他的代码中的内容:删除未使用的内存。所以一般来说name 元素必须被删除。但其中有一个陷阱,我是先发制人地指出的。【参考方案5】:

似乎问题的重点是管理一个动态数组。主要问题是他使用了一个朋友列表数组。使用指向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

但其他人都是对的 - 关于“爱好”和“姓名”的内存分配存在主要问题,您需要分别解决。

【讨论】:

【参考方案6】:

要做好功课,我建议您了解更多关于指针、new/delete 运算符、new[]/delete[] 运算符(不要与 new/delete 运算符混淆)和对象创建/复制/构造函数/析构函数。它是基本的 C++ 功能,您的任务就是这样。

指出一些方向:

1) 当你像这样动态分配对象时

MyType* p = new MyType;

MyType* p = new MyType(constructor_parameters);

您将获得指向所创建对象的指针 pnewMyType 类型的单个对象分配内存并调用该对象的构造函数。

在您对该对象的工作完成后,您必须调用

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=,则会生成隐式 operator=(它执行您的结构/类的每个非静态成员的赋值)。

【讨论】:

以上是关于如何释放动态结构数组的内存的主要内容,如果未能解决你的问题,请参考以下文章

如何在C中释放指向结构的指针数组?

对删除分配给结构数组的动态内存感到困惑

释放结构成员指向的内存

我应该如何释放类型映射中为 argout 结构数组分配的内存?

C#有关数组内存的释放及动态数组问题

在 C++ 中的 2D 动态内存分配数组中释放分配的内存