簡體   English   中英

為什么不能刪除此數組元素的指針值?

[英]Why can't I delete the pointer value at this array element?

我有一個函數,應該刪除動態指針數組中的元素。

我建立了一個可以動態創建此數組的函數,該數組似乎運行良好(請告訴我您是否遇到任何問題)。

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

}

您詢問:

 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];

您的主要錯誤所在:

delete studentList[i]; ////////////WHY DOES THIS CAUSE AN EXCEPTION?

因為沒有通過new分配studentList[i] ,所以會導致異常。

實際上,它指向通過new[]分配的塊的中途。 您只能delete通過new分配的指針; 您不能刪除塊的一部分。

您的代碼執行兩個學生分配:

Student ** studentList = new Student * [double_size];
Student * studentPtr = new Student [double_size];

因此,您必須恰好有兩個delete來釋放該內存(而不是循環中的delete )。

實際上,您的create函數從未顯式保存studentPtr的值。 但是您可以通過編寫delete[] studentList[0];來檢索它delete[] studentList[0]; ,因為create函數將studentPtr存儲到studentList[0] 這將刪除整個學生塊,應放置在for循環結束之后。


studentList的第二個間接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編寫構造函數和析構函數來實現此目的,盡管您還需要遵守“三法則” 實際上,您基本上將重新發明std::string

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM