私はいくつかの特定の要件を満たして宿題に取り組んでいます。 TestScoresという名前のクラスがなければなりません.Questの配列を引数として取ります。スコアが負数であるか100より大きい場合は例外がスローされます。最後に、すべてのスコアの平均を返すメンバー関数が必要です。私は配列をコンストラクタに渡すしか方法が見つからないほど巧妙ではなかったので、配列のサイズを示すintも追加しました。セグメンテーションフォールトと不思議なループ動作
コードを実行すると(まだ例外がテストされていない)、セグメンテーションフォールトエラーが発生し続ける。 ValgrindのとGDBのようなメッセージを出力し、むしろ役に立たないされています(少なくとも私には)さらに不思議な
==9765== Jump to the invalid address stated on the next line
==9765== at 0x2200000017: ???
を、クライアントコードでのためのループでは、私のインクリメンタは、私は、何とか0からぶつかっますtestScoresオブジェクトを作成した直後の、ランダムな2桁の数字です。以前のバージョンでは、配列を生成するために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の初期化を行いました。これはコンパイラの問題を引き起こしました。私は教師と話をしましたが、配線されたグローバル定数がない限り、配列のスペースを割り当てることはできません。つまり、配列を初期化するためにコンストラクタにサイズ値を渡すことはできません。それは本当ですか、もしそうなら、なぜですか?
少し前に戻って、メモリに連続したスペースブロックを必要としないため、多くの値が必要な場合は動的配列が優れているようです。したがって、小さな配列を作成している場合は、動的配列を作成するためにスペースと時間の入力が浪費されるようです。これは間違っていますか?今からすべての配列を動的にするべきですか?この経験は、少なくともクラスに関係するものとして、通常の配列の有用性についての私の意見を確かに変えました。
また、私は割り当てについて完全な評価を得ていますが、大きさの引数を渡すことで精神に違反しているように感じます(「リテラル問題文は次のようになります:」クラスのコンストラクタは、 ")。固定配線されたグローバル定数の他に、サイズ引数を持っているだけで、配列だけを渡す方法はありますか?私は良い一時間を過ごして、これを行う方法を考えようと誓っています。
'TestScores.h'も投稿できますか? – QuantumMechanic
とにかくスコアは何ですか? – leftaroundabout
gccを使用している場合は、すべてに "-g"と "-O0"フラグを追加し、valgrindをもう一度実行します。コード行番号が表示されることがあります。 – pzanoni