我有一个函数应该删除动态指针数组中的元素。
我已经构建了一个动态创建此数组的函数,该函数似乎工作正常(如果您发现任何问题,请告诉我)。
但是,我的删除功能不允许我删除student[i]
处的值,特别是行137.代码编译好了这行被注释掉,但是需要删除该值,否则会导致内存泄漏。
为什么我不能像在线137那样打电话给delete student[i]
?有什么问题?我正在努力学习,并希望得到一个简单的答案。
这是我的代码:
#include <iostream>
#include <cstring>
#include <string> //TESTING
#include <fstream> //needed to use files (contains definitions for ifstream and ofstream)
#include <stdlib.h> //for exit
#include <cctype> //char handling functions
#include <iomanip> //setprecision ,etc
#include <cstddef>
using namespace std;
const int SIZE = 101; //max size of arrays
struct Student
{
char * name;
float gpa;
};
Student ** createStudentList(char ** names, int size);
bool destroyStudentList(Student ** studentList, int size);
int main ()
{
Student ** studentList;
char ** names;
int size = 0;
names = new char*[3];
names[size] = new char[strlen("Lindsay")+1];
strcpy(names[size], "Lindsay");
size++;
names[size] = new char[strlen("Emily") +1 ];
strcpy(names[size], "Emily");
size++;
studentList = createStudentList(names, size);
cout << "//TESTING: before destroyStudentList()" << endl;
destroyStudentList(studentList, size);
return 0;
}
// The function creates an array of pointers to Student objects dynamically.
//It allocates Student objects and set their name as the passed in “names” and gpa as 0. “size” is the number of “names” available.
// You can allocate 2*size as many pointers to Student objects just in case you need to add more to the list.
//For the extra spots in the array, set them to nullptr. The function returns the pointer to the Student pointer array.
Student ** createStudentList(char ** names, int size)
{
// code adapted from CS162 module 8 discussion post for Lab 6 (Nancy Chan and Li Liang)
int double_size = size *2;
Student ** studentList = new Student * [double_size];
Student * studentPtr = new Student [double_size];
for (int i = 0; i < 2 * size; i++)
{
studentList[i] = &studentPtr[i];
}
for (int i = 0; i < size; i++)
{
studentList[i]->name = new char[strlen(names[i]) + 1];
strcpy(studentList[i]->name, names[i]);
studentList[i]->gpa = 0;
}
for (int i = size; i < double_size; i++)
{
studentList[i] = NULL;
}
return studentList;
}
// The function deletes all the Student objects in the array along with their dynamically allocated data members,
// such as name. It also releases the array of the pointers to the Student objects.
// The function returns true if the operation is successful and false if “studentList” contains nullptr.
bool destroyStudentList(Student * studentList[], int size)
{
int double_size = size *2;
// When the pointer is nullptr, there is nothing to delete
if (studentList == nullptr)
{
return false;
}
else
{
//cout << "//TESTING: in destroyStudentList. Else..." << endl;
for (int i = 0; i < double_size; i++)
{
if (studentList[i] != NULL) {
cout << (*studentList[i]).name << endl;
delete [] (*studentList[i]).name;/////can't delete the char array here
cout << "//TESTING1: delete [] studentList[i]->name;" << endl;
(*studentList[i]).name = NULL;
cout << "//TESTING2: studentList[i]->name = NULL;" << endl;
delete studentList[i];////////////WHY DOES THIS CAUSE AN EXCEPTION?
//cout << "//TESTING3: delete studentList[i];" << endl;
//
//studentList[i] = NULL;
//cout << "//TESTING4: studentList[i] = NULL;" << endl;
}
}
}
delete studentList;
studentList = nullptr;
return true;
}
答案 0 :(得分:1)
你问:
delete studentList[i];////////////WHY DOES THIS CAUSE AN EXCEPTION?
在我回答为什么这条线路不好之前,让我先从一个简单的例子开始。 如果您使用以下内容分配内存:
int* ip = new int[10];
解除内存释放的唯一有效方法是使用:
delete [] ip;
以下是尝试释放该内存的所有无效方法。
delete ip;
delete [] ip+2;
delete [] ip+4;
delete ip+2;
delete ip+4;
delete &ip[2];
delete &ip[4];
该行
delete studentList[i];
遇到这个问题。您不仅没有使用delete
运算符的数组形式,而且还在使用一次调用分配的数组中的单个元素上调用delete
。
在createStudentList
中,您使用以下内容为Student
数组分配了内存:
Student * studentPtr = new Student [double_size];
然后使用:
将这些指针分配给studentList
for (int i = 0; i < 2 * size; i++)
{
studentList[i] = &studentPtr[i];
}
删除Student
数组的唯一有效方法是使用:
delete [] studentList[0];
答案 1 :(得分:1)
你的主要错误在于:
delete studentList[i]; ////////////WHY DOES THIS CAUSE AN EXCEPTION?
它会导致异常,因为studentList[i]
未通过new
分配。
事实上,它指向通过new[]
分配的块的中途。您只能delete
通过new
分配的指针;你不能删除一部分区块。
您的代码执行两项学生分配:
Student ** studentList = new Student * [double_size];
Student * studentPtr = new Student [double_size];
因此,您必须准确地使用两个delete
来释放该内存(而不是循环中的delete
)。
实际上,您的create
函数从未明确保存studentPtr
的值。但是您可以通过编写delete[] studentList[0];
来检索它,因为create
函数将studentPtr
存储到studentList[0]
中。这将删除整个学生块,并应放在for
循环结束后。
studentList
中的第二级间接完全是多余的;您只需使用Student *
和size
变量即可实现所有目标。它会简化你的代码,用第二个指针列表去除所有垃圾。
names
块比它应该更复杂。比较你得到的东西:
char const *names[] = { "Lindsay", "Emily" };
studentList = createStudentList(names, 2);
由于您的create
功能正在复制names
,因此无需为names
使用动态分配。
(您需要将const
添加到createStudentList
的第一个参数的开头,无论如何都应该这样。)
如果您的班级规则不会阻止您这样做,那么将Student
的成员char *name;
更改为std::string name;
将为您省去很多麻烦。然后你根本不需要删除循环。
对于类来说,拥有一个拥有某些文本的指针是非常糟糕的,但是期望该类的用户进行内存管理。类应该具有自包含的内存管理。您也可以通过为Student
编写构造函数和析构函数来实现此目的,尽管您还需要观察Rule of Three。事实上,你基本上会重新发明std::string
。