簡體   English   中英

為什么我動態分配的數組沒有正確的值?

[英]Why isn't my dynamically allocated array holding the correct values?

我們正在討論我學校的課程主題。 我應該創建一個名為Student的類,我們可以使用它在動態分配的數組中保存不同的測試分數。 我正在努力弄清楚為什么當我打印出此類的特定實例的數組時,為什么會給我完全不正確的值。 我知道我的班級設置函數正在設置正確的值,但是每當我打印出來時,它們都是完全錯誤的。 下面是我的代碼。 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;
    }**/


}

問題(實際上是一系列問題)在此功能中

 void makeArray() { int array[num]; testptr = &array[num]; for (int i = 0; i < num; i++) { array[i] = 0; } } 

由於num不是編譯時常量,因此第一條語句int array[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 ++標准所必需的,實際上,某些編譯器而不是其他編譯器會發生這種情況。

您的代碼中也存在其他問題,但是以上內容足以使您入門。

您的代碼中存在多個問題,但讓我們先從問題開始。 問題在於,在當前的實現中,您不是在使用動態數組,而只是在內存中指向某些隨機數據的指針。 使用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對象超出范圍時,將釋放內存。

但是,我強烈建議您熟悉“智能指針”的概念,這些概念是專門為減少手動內存管理工作而設計的。 在現代C ++中,“原始”指針由於可能導致許多錯誤而被認為是非常不好的做法。 更好的方法是根本不使用指針,而是使用一個標准C ++容器,例如std::vector<int>

為了使類中的函數共享數據,可以在類范圍內聲明變量。

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),而不是使用原始指針。

暫無
暫無

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

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