2012-04-12 51 views
1

我正在做一個有幾個特定要求的作業。必須有一個名爲TestScores的類,它以分數數組爲參數。如果任何分數爲負數或大於100,則它會引發異常。最後,它必須具有返回所有分數的平均值的成員函數。我沒有足夠的聰明才能找到一種只將數組傳遞給構造函數的方法,所以我還添加了一個int值來說明數組的大小。分段錯誤和神祕的循環行爲

運行代碼(我甚至還沒有到處去測試例外),我不斷收到Segmentation fault錯誤。 Valgrind的和gdb已相當無益,輸出信息,如:

==9765== Jump to the invalid address stated on the next line 
==9765== at 0x2200000017: ??? 

更神祕(至少對我來說),在爲客戶端代碼迴路,我的遞增器,我,不知何故會從0碰着一個在創建TestScores對象後,看似隨機的兩位數字。在之前的版本中,在我開始使用rand()來填充數組之前,我只是沒有增加,並且做了無限循環的事情。

這裏的TestScores.cpp的內容:

#include <iostream> 
using std::cout; 
using std::endl; 
#include "TestScores.h" 
#include <stdexcept> 
using std::runtime_error; 

// Constructor. 
TestScores::TestScores(int a[], int s): 
_SIZE(s), _scores() 
{ 
    // Look at each item in a[], see if any of them are invalid numbers, and 
    // only if the number is ok do we populate _scores[] with the value. 
    for (int i = 0; i < _SIZE; ++i) 
    { 
     if (a[i] < 0) 
     { 
     throw runtime_error ("Negative Score"); 
     } 
     else if (a[i] > 100) 
     { 
     throw runtime_error ("Excessive Score"); 
     } 
     _scores[i] = a[i]; 
     cout << _scores[i] << " "; 
    } 
    cout << endl; 
} 

// Finds the arithmetic mean of all the scores, using _size as the number of 
// scores. 
double TestScores::mean() 
{ 
    double total = 0; 
    for (int i = 0; i < _SIZE; ++i) 
    { 
     total += _scores[i]; 
    } 
    return total/_SIZE; 
} 

// median() creates an array that orderes the test scores by value and then 
// locates the middle value. 
double TestScores::median() 
{ 
    // Copy the array so we can sort it while preserving the original. 
    int a[_SIZE]; 
    for (int i = 0; i < _SIZE; ++i) 
    { 
     a[i] = _scores[i]; 
    } 

    // Sort the array using selection sort. 
    for (int i = 0; i < _SIZE; ++i) 
    { 
     int min = a[i]; 

     for (int j = i + 1; j < _SIZE; ++j) 
     { 
     if (a[j] < min) 
     { 
      min = a[j]; 
      a[j] = a[i]; 
      a[i] = min; 
     } 
     } 
    } 

    // Now that array is ordered, just pick one of the middle values. 
    return a[_SIZE/2]; 
} 

而這裏的客戶端代碼:

#include <iostream> 
#include "TestScores.h" 
#include <stdexcept> 
#include <cstdlib> 
#include <ctime> 
using std::exception; 
using std::cout; 
using std::endl; 

int main() 
{ 
    const int NUM_STUDENTS = 20, 
      NUM_TESTS = 4; 
    int test [NUM_TESTS][NUM_STUDENTS]; 

    // Make random seed to populate the arrays with data. 
    unsigned seed = time(0); 
    srand(seed); 

    // Populate the scores for the individual tests graded for the semester. 
    // These will all be values between 0 and 100. 
    for (int i = 0; i < NUM_TESTS; ++i) 
    { 
     for (int j = 0; j < NUM_STUDENTS; ++j) 
     { 
     test[i][j] = rand() % 100; 
     cout << test[i][j] << " "; 
     } 
     cout << endl; 
    } 

    // Now we have the data, find the mean and median results for each test. 
    // All values should be valid, but we'll handle exceptions here. 
    for (int i = 0; i < NUM_TESTS; ++i) 
    { 
     cout << "For Test #" << i + 1 << endl; 
     try 
     { 
     cout << "i = " << i << endl; // i = 0 here. 
     TestScores results(test[i], NUM_STUDENTS); 
     cout << "i = " << i << endl; // i = some random number here. 
     cout << "Mean: " << results.mean() << endl; 
     cout << "Median:" << results.median() << endl << endl; 
     } 
     catch (exception &e) 
     { 
     cout << "Error, invalid score: " << e.what() << endl; 
     } 
     cout << "For Test #" << i + 1 << endl; 
    } 

    return 0; 
} 

編輯: 請求頭,以及:

#ifndef TEST_SCORES_H 
#define TEST_SCORES_H 

class TestScores 
{ 
    private: 
     const int _SIZE; 
     int _scores[]; 

    public: 
     // Constructor 
     TestScores(int a[], int); 

     double mean() const, 
      median() const; 
}; 
#endif 

我玩弄數組動態,並沒有初始化數組爲空,哪個解決了我的問題,這就是我最終轉入的問題。這導致我遇到了一些後續問題。

在開始動態之前,我嘗試給它初始化數組_scores,並嘗試給它一個應該已經初始化的大小值。這導致編譯器問題。我和老師討論過這個問題,他說除非有硬連線的全局常量,否則你不能爲數組分配空間。也就是說,您無法在構造函數中傳遞大小值來初始化數組。這是真的嗎?如果是這樣,爲什麼?

回想一下,在我看來,如果需要很多值,動態數組會更好,因爲這樣您就不需要內存中的連續空間塊。所以,如果你正在製作小型數組,看起來像浪費空間和時間打造動態數組。這是不是真的?我應該從現在開始做所有的數組嗎?這種經驗當然改變了我對常規數組的用途的看法,至少在涉及到類的時候。另外,雖然我完全相信這個任務,但是我覺得我通過傳遞一個大小參數來違背精神(因爲字面問題陳述寫道:「類構造函數應該接受一組測試分數作爲它的參數「)。除了硬連線的全局常量或大小參數外,有沒有辦法傳遞數組?我發誓我花了一個小時試圖想辦法做到這一點。

+3

你能發佈'TestScores.h'嗎? – QuantumMechanic 2012-04-12 16:18:35

+0

無論如何,分數是多少? – leftaroundabout 2012-04-12 16:20:00

+2

如果您使用的是gcc,請在所有內容中添加「-g」和「-O0」標誌,然後再次運行valgrind:它可能會顯示代碼行號。 – pzanoni 2012-04-12 16:20:31

回答

0

沒有TestScores.h一個有猜測,但給你說怎麼樣在你創建TestScores對象的循環被破壞的i值,即指向你_scores成員變量沒有被正確初始化,當你」重新嘗試加載它實際上是在摧毀內存。

一旦TestScores.h可見,我會重新考慮這個答案,考慮到該文件。


現在已更新TestScores.h可用。

問題是你沒有初始化_scores。你實際上並沒有分配任何內存來保存數組,更不用說設置指針指向那個內存了。所以當你試圖將東西存儲到數組中時,你只是在某處丟棄了內存。

在構造函數中的第一行應該是:

_scores = new int[_SIZE]; 

這將分配內存來保存_SIZEint S和設置_scores指向該內存。然後你的作業_scores[i]實際上將進入屬於你的程序的定義的內存。

當然,當TestScore的實例被破壞時,你也必須釋放這個內存(C++不會爲你做)。所以,你需要制定和實施爲TestScores析構函數和析構函數需要包含線路:

delete [] _scores; 

這將釋放的內存_scores指向塊。您可以閱讀有關delete操作的文檔,以瞭解爲什麼[]必須位於此處。

+0

更新了原始問題以顯示TestScores.h。 – beriukay 2012-04-17 10:38:35

0

看來你根本沒有初始化_scores。您需要構造函數頂部的_scores = new int[s];(並且在析構函數中還有delete[] s;)。

沒有初始化_scores,你寫東西到未定義的內存位置。

+0

那麼,假設'_scores'是'int *',我們還不知道。但是,是的,我還假設'_scores'有一些初始化問題導致了這種情況。 – QuantumMechanic 2012-04-12 16:25:59

+0

另請注意,由於構造函數可以拋出,析構函數可能無法始終運行。 – 2012-04-12 16:28:10

+0

是的,它似乎使_scores成爲一個動態數組,所有問題都解決了。但在添加了我之前的.h後,我有一些後續問題可以更好地理解問題。 – beriukay 2012-04-17 10:36:33