【问题标题】:Access an array of class in a function访问函数中的类数组
【发布时间】:2011-12-10 14:06:35
【问题描述】:

我创建了一个类数组st[5]。并尝试使用函数显示st[5] 的数据。但它不起作用。

仅显示第一类 (st[0]),并显示“调试错误消息”。不知道是什么问题。

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

并显示“调试错误消息”...

【问题讨论】:

  • 令人惊讶的是,在 MacOS X 下使用g++ 编译时,您的代码只需进行非常小的修改即可工作。我切换到使用strncpy(this-&gt;name, name, 10);,并且代码打印了五行非常好。
  • 当我回答你的问题时,你删除了它。所以我无法发布答案,所以我永久丢弃它。现在,问题再次出现,我将不得不再次输入所有内容。对于一个简单的问题,这将是双重工作(所以我没有,特别是因为无论如何都有正确的答案)。以后请不要这样做!
  • @ CygnusX1 。好的我明白了。对此感到抱歉。我是第一次在'StackOverflow',所以我不知道如何正确使用。对不起。

标签: c++ arrays class


【解决方案1】:

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

Totscore *st[MAX];

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

PrintArray(*st);

更改您的函数以获取指向整个数组的指针应该可以:

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

PrintArray(st);

【讨论】:

  • 天啊。非常感谢你!!!!!!!!问题解决了。非常感谢!!!!!对不起,我的声誉很低,我不能投票。
  • @NatuerConservation 你不能投票,但你可以接受这个作为答案。只需点击左侧的勾号即可。
【解决方案2】:

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

  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] = '\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);
}

【讨论】:

  • 我认为按值传递数组是不可能的。 char name[10] 与 char* name 相同
  • 非常感谢您的详细解释。对不起,我的声誉很低,我不能投票。非常感谢您非常有帮助的解释!
【解决方案3】:

这段代码看起来很痛苦。总体而言,您可以使用一些技巧来快速轻松地改进您的代码:

在 C++ 中,使用 const 而不是 #define 来获取常量。

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

同样,用户 std::string name 超过 char *name 或 char name[10]。否则,您只是用类编写 C,不幸的是,那里已经有足够的内容了。不要增加痛苦。 :)

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

【讨论】:

  • 非常感谢您的友好解释。我明白。我会改变的。
【解决方案4】:

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

Totscore st[MAX];

并在堆栈上分配 Totscore 对象(删除“新”)。 最后,在不取消引用的情况下调用 print 函数:

PrintArray(st);

您的原始代码将起作用...

【讨论】:

  • 哦,非常感谢您的解释。这种方式也不错。如果更改为 'void PrintArray(Totscore stu[])',则此工作。谢谢!!!
  • @NatuerConservation "Totscore * a" 与 "Totscore a[]" 相同,因为数组本质上会衰减为指向第一个元素的指针...
  • @NatuerConservation 另请阅读其他帖子。有几个很好的建议。尽量避免使用预处理器(“#define MAX 5”)。如果不需要堆对象,最好在堆栈上分配。请记住在使用堆对象时释放堆内存。考虑使用 STL 容器(向量)和算法。
  • @NatuerConservation 我建议查看 C++ 中堆和堆栈对象之间的指针、引用、值和差异。还可以进一步了解 STL 及其提供的功能。
【解决方案5】:

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

将您的printArray 实现为:

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

然后将其称为:

PrintArray(st);

这应该可行。

现在为什么您的原始代码不起作用是因为您正在传递数组的第一个元素,该元素不能用于遍历声明为 pointers 数组的数组。由于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!

完成!

【讨论】:

  • 为什么函数声明应该是void PrintArray(Totscore **stu);当传递 PrintArray(st);
  • @Jagannath:因为st被声明为指针数组,所以需要传递数组第一个元素的地址,而不是元素本身,所以您可以遍历指针数组。另外,请参阅我的答案,我对其进行了更多解释。
  • 传递数组变量名本身就是传递数组第一个元素的地址。
  • @Jagannath:是的。这就是我要说的。你哪里不同意我的观点?顺便说一句,如果你写printArray(st),你必须把函数写成void printArray(Totscore **stu),因为st的类型与Totscore**兼容,而不是Totscore*。
  • 非常感谢您的友好解释。对不起,我的声誉很低,我不能投票。但是谢谢!!
猜你喜欢
  • 2017-09-19
  • 2010-11-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多