访问函数中的类数组

Access an array of class in a function

本文关键字:数组 函数 访问      更新时间:2023-10-16

我制作了一个类为st[5]的数组。并尝试用一个函数来显示st[5]的数据。但是它不工作。

只显示第1类(st[0]),并显示debug error Message。我不知道是什么问题。

下方为main函数。

#include <iostream>
using namespace std;
#define MAX 5       //size of array
//Class 'Student' 
class Student
{
public:
    int num;
    char name[10];
};
//Class 'Lscore' extends Student (virtual)
class Lscore : virtual public Student   
{
public: 
    int eng;    
};
//Class 'Nscore' extends Student (virtual)
class Nscore : virtual public Student
{
public:
    int math;   
};
//Class 'Totscore' extends Lscore, Nscore
class Totscore : public Lscore, public Nscore
{
public:
    Totscore();     //Constructor1
    Totscore(char name[], int num, int eng, int math); //Constructor2
    void Display();     //Print Myself
};
//Constructor1
Totscore::Totscore( )
{
}
//Constructor2
Totscore::Totscore(char name[10], int num, int eng, int math)
{       
    strcpy_s(this->name, 10, name);
    this->num = num;    
    this->eng = eng;
    this->math = math;  
}

//Print Myself
void Totscore::Display(){
    cout<<this->num<<"  "<<this->name<<"  ";
    cout<<this->eng<<"  "<<this->math<<"  "<<endl;
}

//Print Array (--- Problem Part !! ---)
void PrintArray(Totscore *stu){ 
    for(int i=0; i< MAX; i++){
        stu[i].Display();       
    }
}
//Main Function
int main(){
    Totscore *st[MAX];      //Class Array 'st'
    st[0] = new Totscore("A",101,85,77);
    st[1] = new Totscore("B",102,90,89);
    st[2] = new Totscore("C",103,80,55);
    st[3] = new Totscore("D",104,75,85);
    st[4] = new Totscore("E",105,85,85);
    PrintArray(*st);
}

和运行画面如下。(我不能上传图片,因为我的声誉很低。)

101  A  85  77

你在这里创建了一个指针数组:

Totscore *st[MAX];

但是你传递的是第一个元素:

PrintArray(*st);

把你的函数改成一个指向整个数组的指针就可以了:

void PrintArray(Totscore **stu){ 
    for(int i=0; i< MAX; i++){
        stu[i]->Display();       
    }
}
PrintArray(st);

导致未定义行为的几个主要问题:

  1. Student的默认构造函数没有初始化它的char数组。
  2. 通过值传递给构造函数的数组。
  3. 数组迭代不正确。对象数组的内存布局与对象指针数组的内存布局不同。

还有一个内存泄漏,许多不必要的操作只是为了初始化数据。您应该使用构造函数初始化列表。在C/c++中没有strcpy_s函数,这是一个可怕的微软发明。为什么不使用便携式strncpy呢?

这是一个稍微改进的代码:

#include <cstring>
#include <iostream>
using namespace std;
#define MAX 5       //size of array
//Class 'Student' 
class Student
{
public:
    Student (int num = 0) : num (num)
    {
        name[0] = '';
    }
    Student (const char *name, int num = 0) : num (num)
    {
        strncpy (this->name, name, sizeof (this->name));
    }
    int num;
    char name[10];
};
//Class 'Lscore' extends Student (virtual)
class Lscore : virtual public Student   
{
public: 
    Lscore (int eng = 0) : eng (eng) {}
    int eng;    
};
//Class 'Nscore' extends Student (virtual)
class Nscore : virtual public Student
{
public:
    Nscore (int math = 0) : math (math) {}
    int math;   
};
//Class 'Totscore' extends Lscore, Nscore
class Totscore : public Lscore, public Nscore
{
public:
    Totscore() {}     //Constructor1
    Totscore(const char *name, int num, int eng, int math); //Constructor2
    void Display();     //Print Myself
};
//Constructor2
Totscore::Totscore(const char *name, int num, int eng, int math)
        : Student (name, num), Lscore (eng), Nscore (math)
{       
}

//Print Myself
void Totscore::Display(){
    cout<<this->num<<"  "<<this->name<<"  "
        <<this->eng<<"  "<<this->math<<"  n";
}

//Print Array (--- Problem Part !! ---)
void PrintArray(Totscore **stu){ 
    for(int i=0; i< MAX; ++i){
        stu[i]->Display();       
    }
}
void DeleteArray(Totscore **stu){ 
    for(int i=0; i< MAX; ++i){
        delete stu[i];
    }
}
//Main Function
int main(){
    Totscore *st[MAX];      //Class Array 'st'
    st[0] = new Totscore("A",101,85,77);
    st[1] = new Totscore("B",102,90,89);
    st[2] = new Totscore("C",103,80,55);
    st[3] = new Totscore("D",104,75,85);
    st[4] = new Totscore("E",105,85,85);
    PrintArray(st);
    DeleteArray (st);
}

这段代码看起来很痛苦。以下几个技巧可以帮助您快速、轻松地改进代码:

在c++中,使用const而不是#define作为常量。

#define MAX 5  // Instead of this...
const int MAX = 5;  // ...do this.

同样,用户std::string name优于char *namechar name[10]。否则,你只是在用类写C,不幸的是,已经有足够多的类了。不要增加痛苦。:)

学习使用标准容器类型(vector、list、set和友元)而不是裸数组。没有理由不这样做,他们提供的内置功能是惊人的!当然,这是一个学习曲线。但你最终会表现得更好。

如果你想要一个对象数组,你必须声明数组为:

Totscore st[MAX];

并在堆栈上分配Totscore对象(删除"new")。最后,在不解引用的情况下调用print函数:

PrintArray(st);

首先,我会告诉你你需要做什么(不要求你改变整个代码)才能使你的代码工作,然后解释为什么你的代码不能工作:

printArray实现为:

void PrintArray(Totscore **stu){ 
    for(int i=0; i< MAX; i++){
        stu[i]->Display();     
    }
}

则称其为:

PrintArray(st);

应该可以。

为什么你的原始代码不能工作是因为你传递了数组的第一个元素,这个元素不能用来遍历被声明为指针数组的数组。由于st被声明为指针数组,因此需要传递数组第一个元素的地址,而不是元素本身,以便可以遍历指针数组。注意,数组元素的类型是Totscore*,所以它的地址是Totscore**


嗯,这对初学者来说非常复杂,所以我建议一个更好的,健壮的和简单的替代方案。使用std::vector作为:

std::vector<Totscore> st;

然后调用.push_back()向它插入元素:

st.push_back(Totscore("A",101,85,77));
st.push_back(Totscore("B",102,90,89));
st.push_back(Totscore("C",103,80,55));
//etc
PrintArray(st);

则实现PrintArray为:

void PrintArray(const std::vector<Totscore> & stu)
{ 
    for(size_t i=0; i< stu.size(); i++){
        stu[i].Display();     
    }
}

现在,您还需要在代码中做一个非常小的更改。使Display()函数成为const成员函数

void Display() const;
               ^^^^^ //this makes the  function const!
                     //in its definition too, write const!

完成了!