【问题标题】:Setting constructor and destructor with *pointer array C++使用 *pointer array C++ 设置构造函数和析构函数
【发布时间】:2015-02-06 17:28:52
【问题描述】:

我使用 int *studentsAge 存储年龄列表,使用 double *marks[2] 存储每个学生 2 分的列表。

基本上,我不确定如何设置我的constructordestructor

这是我的构造函数...

Students::Students()
{
  num = 0;
  studentsAge = NULL;
  marks[2] = NULL;
}

我在这个函数中使用了两个指针数组...

void Students::storeValues(int num)
{
   this->num = num;
   studentsAge = new int[num];
   for(int i=0; i<num; i++)
   {
     studentsAge[i] = i;
     marks[i] = new double[num]
   }
}

这是我的析构函数...

Students::Students()
{
   for(int i=0; i<num; i++)
   {
      delete[] marks[i];
      delete[] studentAge[i];
   }
   delete[] marks;
   delete[] studentAge
}

我不确定我的constructordestructor 是否正确,我可以怀疑某处存在内存泄漏。我不太擅长指针,但如果有人能告诉我哪里出错了,我将不胜感激

【问题讨论】:

  • 我没有看到任何迹象表明marks 是动态分配的。事实上,double *marks[2] 声明了一个由两个指针组成的数组,而不是一个指向两个双精度数组的指针。而你的 marks[2] = ... 调用 undefined d 行为。这个类看起来并不复杂。发布整个内容,包括声明和成员实现。
  • marks[2] = NULL 实际上是将越界 0 写入 marks 的不存在的第三个元素,并且在每个单独的元素上使用 delete[] 是未定义的行为。
  • @WhozCraig,我很困惑,我以为double *marks[2] 存储了一个2 双精度数组,即marks[0][0] = 10.2marks[0][1] = 8.9; marks[1][0] = 69.0; marks[1][1] = 45.3,还是我错了?如果是这样,我如何声明一个包含 2 值的动态双精度数组
  • double *marks[2] 声明了一个包含两个双精度指针的数组;不是指向两个双精度数组的指针。后者是double (*marks)[2];
  • @WhozCraig 谢谢,那么如何在构造函数中初始化 double marks 数组并在析构函数中销毁它?

标签: c++ arrays pointers constructor destructor


【解决方案1】:

没有理由使用您的 2 元素标记数组。让自己轻松一点,并将其更改为 2 double* 的标记 0 和标记 1。

double* marks0;
double* marks1;

但是如果你想在当前路径上继续,首先你需要正确初始化标记:

Students::Students()
{
    num = 0;
    studentsAge = NULL;
    marks[0] = NULL;     //clear the pointer to the first array of marks
    marks[1] = NULL;     //clear the pointer to the second array of marks
}

现在您需要正确创建标记数组:

void Students::storeValues(int num)
{
   this->num = num;
   studentsAge = new int[num];
   marks[0] = new double[num];
   marks[1] = new double[num];
   for(int i=0; i<num; i++)
   {
     studentsAge[i] = i;  //what is this doing?  each student's age is the same as his/her index?
     marks[0][i] = 0;     //initialize the first mark for student i
     marks[1][i] = 0;     //initialize the second mark for student i
   }
}

最后你需要正确销毁数组:

Students::~Students()
{
   delete[] marks[0];
   delete[] marks[1];
   delete[] studentsAge;
}

【讨论】:

  • 除非您需要使用这些并行数组,否则我真的建议您尽可能避免动态分配,并使用 std::vector 为每个学生存储所有 3 个值的结构的实例
【解决方案2】:

让每个学生在一起是更好的设计:

struct Student
{
    int marks[2];
    int age;
};

然后存储一个学生容器:

struct Students
{
    std::vector<Student> students;
    void storeValues(int num);
}

你的函数看起来像:

void Students::storeValues(int num)
{
    students.resize(num, Student());   // zero-initialized students!

    for(int i=0; i<num; i++)
        students[i].age = i;
}

这样您就不需要编写任何析构函数或任何其他五法则中的函数,因此您可以减少出错的机会并避免浪费时间编写样板代码。

【讨论】:

  • 即使你想使用指针而不是向量来学习,使用struct Student的数组而不是几个数组仍然使事情变得更简单
【解决方案3】:

就您的主要领域而言,我猜您的学生课程看起来有点像这样:

class Students
{
   private:
    static const int maxNumberMarks = 2;  //the maximum number of marks that can be stored per student
    int numStudents;                      // the count of the number of students
    int* studentsAge;                     // an array of each students ages   
    double* marks[maxNumberMarks];        // an array of arrays to store each student mark
}

在这种情况下,您的默认构造函数几乎是正确的。您只需要正确初始化您的标记数组。

Students::Students()
{
   num = 0;
   studentsAge = NULL;
   for( int markIndex = 0; markIndex  < maxNumberMarks; ++markIndex )
   {
       marks[markIndex ] = NULL;
    }
}

你的初始化函数有点混乱。

首先,我会将输入的 num arg 重命名为类似 numStudents 的名称,以免与同名的成员变量混淆。

其次,您需要将数组的分配与初始化它们分开

void Students::storeValues(int numStudents )
{
  this->num = numStudents ; //store off how many students we are handling.

  //allocate 3 storage arrays for each student. The age array and 2 mark arrays 
  studentsAge = new int[numStudents ];
  for( int markIndex =0; markIndex < maxNumberMarks; ++markIndex)
  {
     marks[markIndex] = new double[numStudents];
  } 

  //now init the arrays to something 
  for(int studentIndex=0; studentIndex < numStudents ; studentIndex++)
  {
     studentsAge[studentIndex] = studentIndex;
     for( int markIndex =0; markIndex < maxNumberMarks; ++markIndex)
     {
        marks[markIndex][studentIndex] = 0.0; //zero seems a reasonable initial value.
     }
  }
}

最后,要获得析构函数,您只需要镜像分配数组的代码即可。

~Students()
{
   //delete the marks arrays 
    for( int markIndex =0; markIndex < maxNumberMarks; ++markIndex)
    {
       delete[] marks[markIndex];
       marks[markIndex] = NULL;
     } 

   //delete the ages array
   delete[] studentsAge;
   studentsAge = NULL;
}

随着代码的增长,您可能希望为每个学生存储不同的数据,我建议创建一个 Student 类来帮助简化一切。

class Student
{
  private:
    static const int maxNumberMarks = 2;  //the maximum number of marks that can be stored per student
    int age; //the age of the student
    double marks[maxNumberMarks];
 }

假设您使用适当的 Default 构造函数充实 Student 数组,这会将所有许多分配都简化到 Student 类中的一个位置

Students
{
   Student* studentsArray;  //dynamically  allocated array of student info
   int numStudents;     
 }

 void Students::storeValues(int numStudents )
 {
    this->num = numStudents ;
    studentsArray = new Student[numStduents];
 }

 ~Students()
 {
   delete[] studentsArray;
   studentsArray = NULL;
 }

如果你使用 std::vector 代替分配的数组,你甚至不需要担心分配和释放它。

【讨论】:

    【解决方案4】:

    简答:

    您需要编写以下内容:

    Students::Students()
    {
      num = 0;
      studentsAge = NULL;
      marks[0] = NULL;
      marks[1] = NULL;
    }
    
    void Students::storeValues(int num)
    {
       this->num = num;
       studentsAge = new int[num];
       marks[0] = new int[num];
       marks[1] = new int[num];
    
       for(int i=0; i<num; i++)
       {
         studentsAge[i] = i; // this is where you give each student an age, are you sure you want to use i?
         // here you can put grade assignments as follows:
         marks[0][i] = val1; // first mark for student i
         marks[1][i] = val2; // second mark for student i
       }
    }
    
    Students::~Students()
    {
       delete[] marks[0];
       delete[] marks[1];
       delete[] studentsAge;
    } 
    

    长答案:

    看来你需要了解什么是指针,什么是数组。

    当您将double *marks[2] 放入类声明中时,它将保留一个大小为 2 的双精度数组 附加到类的每个实例的指针。您无需将[2] 放入构造函数中。

    指针是一个变量,用于保存内存中保留地址块的首地址。这意味着当你分配一个指针时,你需要给它一个内存地址。要将值写入存储在指针中的地址,请在变量前使用* 字符。

    int num = 2;
    int* p;
    
    p = &num; // p will hold the address of num.  Any changes to p's value will be reflected in num
    
    p = new int; // p is assigned a new address
    *p = num; // the address that p points to will hold 2 (the value in num), but if that value is changed, num will still hold 2
    

    如果你想给 p 分配一个数组,你可以使用 new 关键字。这将分配内存 供您的程序使用。不要忘记释放它。

    size = 10;
    p = new int[size];
    

    现在您可以通过将p 中的值视为数组或指针算术来引用它, 我现在不会进入。

    p[0] = 1; // the first 
    p[5] = 56;
    

    指针和数组的区别在于数组分配和释放由 编译器,并且需要在编译时具有固定的大小。指针分配和释放由用户处理,其大小在运行时定义。

    【讨论】:

      猜你喜欢
      • 2021-07-20
      • 2011-04-03
      • 2010-12-16
      • 2012-04-10
      • 2012-11-14
      • 2016-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多