我们正在学校的课程主题。我应该创建一个名为Student的类,我们可以使用它来在动态分配的数组中保存不同的测试分数。我正在努力弄清楚为什么当我打印出这个类的特定实例的数组时,它给了我完全不正确的值。我知道我的类的setter函数正在设置正确的值,但每当我打印它们时它们都是完全错误的。以下是我的代码。 main()中注释掉的部分仅用于测试makeArray()函数的逻辑。
#include <iostream>
using namespace std;
class Student {
private:
string name;
int id;
int* testptr;
int num;
void makeArray() {
int array[num];
testptr = &array[num];
for (int i = 0; i < num; i++) {
array[i] = 0;
}
}
public:
Student() {
setName("None");
setID(10);
num = 3;
makeArray();
}
Student(int n) {
setName("None");
setID(10);
if (n > 0)
num = n;
else
num = 3;
makeArray();
}
Student(string nm, int i, int n) {
setName(nm);
setID(i);
if (n > 0)
num = n;
else
num = 3;
makeArray();
}
void setName(string nm) {
name = nm;
}
void setID(int i) {
if (i >= 10 && i <= 99){
id = i;
}
else {
cout << "Error: Cannot set id to " << i << " for " << getName();
id = 10;
}
}
void setScore(int i, int s) {
if ((i >= 0 && i <= num) && (s >= 0 && s <= 100)) {
//Here is where I set the values for the array. They come out correct in the console.
testptr[i] = s;
cout << testptr[i] << endl;
} else {
cout << "The test " << i << " cannot be set to " << s << " for " << getName() << endl;
}
}
string getName() const {
return name;
}
int getID() const {
return id;
}
void showScore() {
//This is where I print out the values of the array. They come out incorrect here.
for (int i = 0; i < num; i++) {
cout << "Test " << i << " had a score of " << testptr[i] << endl;
}
}
void display() {
cout << "Calling the display function" << endl;
cout << "The Name: " << getName() << endl;
cout << "The ID: " << getID() << endl;
showScore();
}
~Student() {
}
};
int main() {
Student c("Joe", 40, 5);
c.setScore(0, 90);
c.setScore(1, 91);
c.setScore(2, 92);
c.setScore(3, 93);
c.setScore(4, 94);
c.display();
/**int* testpointer;
int num = 3;
int array[num];
testpointer = &array[0];
for (int i = 0; i < num; i++) {
testpointer[i] = i;
cout << testpointer[i] << endl;
}**/
}
答案 0 :(得分:1)
问题(实际上是一组问题)在这个函数中
void makeArray() { int array[num]; testptr = &array[num]; for (int i = 0; i < num; i++) { array[i] = 0; } }
第一个语句int array[num]
,因为num
不是编译时常量,所以它不是有效的C ++。如果您的编译器支持它,它是编译器特定的扩展。 (从技术上讲,这是一个可变长度数组,它是1999 C标准中C的一个特性,从2011年开始在C中可选,但在任何标准或草案中从未成为C ++的一部分。)。
其次,如果您的编译器支持该构造,则会创建一个自动存储持续时间的数组,该函数在函数返回时不再存在。这意味着testptr
包含一个悬空指针。函数返回后,testptr
的任何解除引用(例如访问数组元素)都会给出未定义的行为。
如果您确实必须使用动态内存分配,请使用“新表达式”,例如testptr = new int[num]
。请记住,有必要在类析构函数中执行delete [] testptr
。还要查找“三个规则”,因为在创建类的其他实例时,您需要编写复制构造函数和赋值运算符来正确管理数组。
更好的是,#include <vector>
,并将testptr
更改为std::vector<int>
类型。阅读标准矢量类的文档,了解如何使用它,包括管理其大小。
此外,#include <string>
也是如此。没有它,您的代码不需要使用std::string
类型进行编译 - 您很幸运,通过实施,<iostream>
包括<string>
。这不是C ++标准所要求的,实际上,它与某些编译器有关,而不是其他编译器。
您的代码中还存在其他问题,但上述内容应足以让您入门。
答案 1 :(得分:1)
您的代码中存在多个问题,但请先从问题开始。
问题是,在当前实现中,您不使用动态数组,而只使用指向内存中某些随机数据的指针。使用new
运算符创建动态分配的对象。在您的情况下,您在堆栈上分配对象:
void makeArray() {
int array[num]; // creates local object on stack
testptr = &array[num]; // stores pointer to local object
for (int i = 0; i < num; i++) {
array[i] = 0;
}
} // stack is being destroyed here along with array object
// testptr points to memory that should no be addressed anymore
在C ++中返回/存储指针或引用声明对象范围之外的本地对象是一个很常见的错误。初始化指针的正确方法是:
void makeArray() {
// note parenthesis at the end,
// default zero-initializer will be called
testptr = new int[num]();
}
请注意,在这种情况下,您必须记住在不再需要使用时释放已分配的内存。实现这一目标的最佳方法是将delete调用放入析构函数:
~Student() {
delete[] array;
}
然后当Student对象超出范围时,将释放内存。
但我严格鼓励您熟悉&#34;智能指针&#34;这是专门为减少手动内存管理工作而设计的。在现代C ++&#34; raw&#34;指针被认为是非常糟糕的做法,因为它可能导致很多错误。
更好的方法是根本不使用指针,而是使用一个标准C ++容器,如std::vector<int>
答案 2 :(得分:1)
为了让类中的函数共享数据,您可以在类范围内声明变量。
class Foo
{
public:
MyFunc1() { _n = 1; }
MyFunc2() { _n = 2; }
private:
int32_t n; // can be used by all member functions
};
在你的情况下,你在函数范围声明了一个数组,一旦你离开函数就会被销毁。
此外,您无法在堆栈上声明具有可变大小的数组,而是需要在堆上分配数组
class Foo
{
public:
Foo():_array(nullptr),_size(0) {}
void AllocateArray(int size) { _array = new int32_t[size]; _size = size; }
void DestroyArray() { delete [] _array; _size = 0; }
private:
int32_t* _array;
int8_t _size;
};
通常你会使用其中一个C ++容器(例如std :: vector)而不是使用原始指针。