Ich arbeite an einer Hausaufgabe mit ein paar spezifischen Anforderungen. Es muss eine Klasse namens TestScores geben, die ein Array von Scores als Argument akzeptiert. Wenn eine Punktzahl negativ oder größer als 100 ist, wird eine Ausnahme ausgelöst. Schließlich muss eine Mitgliedsfunktion einen Durchschnittswert für alle Punktzahlen enthalten. Ich war nicht klug genug, einen Weg zu finden, das Array nur in den Konstruktor zu übergeben, also fügte ich auch ein int hinzu, das die Größe des Arrays angibt.Segmentierungsfehler und mysteriöse Schleife Verhalten
Ich habe den Code ausgeführt (ich bin noch nicht einmal dazu gekommen, die Ausnahmen zu testen), ich bekomme immer einen Segmentierungsfehler. Valgrind und GDB haben eher wenig hilfreich, die Ausgabe-Nachrichten wie:
==9765== Jump to the invalid address stated on the next line
==9765== at 0x2200000017: ???
Noch mehr geheimnisvoll (für mich zumindest), in der for-Schleife in dem Client-Code, mein Inkrementierer, i, wird irgendwie von 0 bis einem gestoßen scheinbar zufällige zweistellige Zahl direkt nach dem Erstellen des TestScores-Objekts. In früheren Versionen, bevor ich mit rand() begann, um das Array aufzufüllen, habe ich einfach nie inkrementiert und die Endlosschleife gemacht.
Hier ist der Inhalt von 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];
}
Und hier ist der Client-Code:
#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;
}
Edit: Der Header wurde auch angefordert:
#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
I experimentierte mit der Dynamisierung des Arrays und initialisierte das Array nicht als leer habe meine Probleme behoben, also bin ich am Ende dran. Das führt mich zu ein paar Nachfragen.
Bevor ich dynamisch ging, spielte ich mit der Initialisierung des Arrays, _scores, herum, indem ich versuchte, ihm den Größenwert zu geben, der bereits initialisiert werden sollte. Dies führte zu Compiler-Problemen. Ich habe mit meinem Lehrer darüber gesprochen, und er sagte, dass Sie keinen Platz für ein Array reservieren können, es sei denn, es gibt eine festverdrahtete globale Konstante. Das heißt, Sie können im Konstruktor keinen Größenwert übergeben, um ein Array zu initialisieren. Ist das wahr, und wenn ja, warum?
Wenn ich ein wenig zurücktrete, scheint es mir, dass dynamische Arrays besser sind, wenn Sie viele Werte benötigen, weil Sie dann keinen zusammenhängenden Speicherblock im Speicher benötigen. Wenn Sie also kleine Arrays erstellen, scheint es eine Verschwendung von Speicherplatz und Zeit zu sein, um dynamische Arrays zu erstellen. Ist das unwahr? Soll ich jetzt alle Arrays als dynamisch ausführen? Diese Erfahrung hat sicherlich meine Meinung über den Nutzen von regulären Arrays geändert, zumindest was Klassen betrifft.
Auch wenn ich volle Anerkennung für die Aufgabe bekam, habe ich das Gefühl, dass ich den Geist verletzt habe, indem ich ein Argument für die Größe übergeben habe (da die literale Problembeschreibung lautet: "Der Klassenkonstruktor sollte eine Reihe von Testergebnissen akzeptieren "). Gibt es neben einer festverdrahteten globalen Konstante oder einem Größenargument eine Möglichkeit, nur das Array zu übergeben? Ich schwöre, ich habe eine gute Stunde damit verbracht, mir einen Weg zu überlegen, wie ich das machen könnte.
Können Sie auch 'TestScores.h' posten? – QuantumMechanic
Was ist überhaupt ein Score? – leftaroundabout
Wenn Sie gcc verwenden, fügen Sie die Flags "-g" und "-O0" für alles hinzu und führen Sie dann valgrind erneut aus: Es zeigt Ihnen möglicherweise die Codezeilennummern an. – pzanoni