为什么我不能删除此数组元素的指针值?

时间:2015-03-02 03:22:23

标签: c++ arrays pointers

我有一个函数应该删除动态指针数组中的元素。

我已经构建了一个动态创建此数组的函数,该函数似乎工作正常(如果您发现任何问题,请告诉我)。

但是,我的删除功能不允许我删除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;

}

2 个答案:

答案 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