Mit Konstruktor Spielfeld initialisieren
-
Hallo ihr lieben,
habe folgendes Problem, wenn ich ein Spielfeld zu Beginn meines Programms im Konstruktor initialisieren will. Hier erstmal die relevanten Codeteile:class GameOfLife{ private: int rows; int cols; int* board; public: GameOfLife(int rows, int cols); ~GameOfLife(); void clear(); }; void GameOfLife::clear(){ for(int i = 0; i<rows*cols; i++){ *board = 0; *board ++} } GameOfLife::GameOfLife(int x, int y){ rows = x; cols = y; int* board = new int[rows * cols]; void clear();Also für ein x*y-Spielfeld, dass ich in einem eindimensionalen Array speichern will, will ich, dass mein Konstruktor Speicher für das Feld allokiert und mittels clear() das int-Feld mit Nullen initialisiert.
Wenn ich im Konstruktor probehalber *board ausgebe ist es aber mit "zufälligen" 7-stelligen Ints gefüllt, der Fehler liegt also vermutlich irgendwo bei den Zeigern

Stehe grade als Programmieranfängerin echt aufm Schlauch und wäre dankbar für den einen oder anderen Tipp

Grüße
-
Das void in Zeile 22 ist zu viel.
-
Ich wuerde die count * row multiplikation auch nicht in der Schleife machen.
Mach es einmal davor speicher es in ein int und gib es dann in der Schleife an.
Ist übersichtlicher und ich (glaube), dass ansonsten die Multiplikation bei jedem Schleifendurchlauf durchgeführt wird.
-
#include <algorithm> class GameOfLife { private: unsigned rows; unsigned cols; int * board; public: GameOfLife( unsigned rows, unsigned cols ); GameOfLife( GameOfLife const & other ); ~GameOfLife(); void clear(); }; void GameOfLife::clear() { std::fill( board, board + rows * cols, 0 ); } GameOfLife::GameOfLife( unsigned x, unsigned y ) : rows { y }, cols { x }, board { new int[ rows * cols ]() } {} GameOfLife::GameOfLife( GameOfLife const & other ) : rows { other.rows }, cols { other.cols }, board { new int[ rows * cols ]() } { std::copy( other.board, other.board + rows * cols, board ); } GameOfLife::~GameOfLife() { delete [] board; }ftfy.
-
for schrieb:
Ich wuerde die count * row multiplikation auch nicht in der Schleife machen.
Mach es einmal davor speicher es in ein int und gib es dann in der Schleife an.
Ist übersichtlicher und ich (glaube), dass ansonsten die Multiplikation bei jedem Schleifendurchlauf durchgeführt wird.P.S.: Außerdem wuerde ich beim Naming im deklarierten und definierten Konstruktor, den gleichen Text verwenden.
Am Besten hast du auch einen Namensunterschied zwischen member und Konstruktorparameter, einfach der zum Zwecke der besseren Übersicht.
In Zeile 15 fehlt dir auch ein Semikolon und die Zweile macht irgendwie auch keinen Sinn oder was willst du da machen?
-
manni66 schrieb:
Das void in Zeile 22 ist zu viel.
Wenn ich das void entferne lässt sich der Code seltsamerweise nicht mehr ausführen.
-
Definiere "lässt sich nicht mehr ausführen".
-
Der gezeigte Code ist sowieso nicht der echte ... in Zeile 15 fehlt ein Semikolon.
-
Leah92 schrieb:
Stehe grade als Programmieranfängerin echt aufm Schlauch und wäre dankbar für den einen oder anderen Tipp

Warum machst Du Dir das Leben denn dann unnötig schwer und greifst nicht einfach in die gefüllte Werkzeugkiste?
#include <vector> #include <algorithm> class GameOfLife { public: GameOfLife( unsigned rows, unsigned cols ); void clear(); private: std::vector< int > board; }; GameOfLife::GameOfLife( unsigned rows, unsigned cols ) : board( rows * cols ) { } void GameOfLife::clear() { std::fill( board.begin(), board.end(), 0 ); }ganz ohne Speicherleckts / double deletes etc. Im Berufsleben bezahlt Dich später auch keiner dafür, das Rad ständig neu zu erfinden

mfg Torsten
-
Torsten Robitzki schrieb:
ganz ohne Speicherleckts / double deletes etc. Im Berufsleben bezahlt Dich später auch keiner dafür, das Rad ständig neu zu erfinden

Ich glaube, die meisten Entwickler werden tatsächlich aus verschiedenen Gründen und Ursachen genau dafür bezahlt. Das wird dann natürlich nicht "Rad neu erfinden" genannt.
Jetzt mal mit dem richtigen Typ für Größen im Speicher:
GameOfLife::GameOfLife(std::size_t rows, std::size_t cols) : board(rows * cols) { }Man muss hier allerdings mit der Multiplikation aufpassen, denn die kann überlaufen.
Für den Anfang reicht wohl eine Exception:namespace { std::size_t check_board_size(std::size_t rows, std::size_t cols) { std::size_t cells = rows * cols; if (rows && (cells / rows != cols)) { throw std::length_error("This board size cannot be represented in memory"); } } } GameOfLife::GameOfLife(std::size_t rows, std::size_t cols) : board(check_board_size(rows * cols)) { }Die sollte natürlich wieder gefangen werden, wo die Behandlung Sinn ergibt.
-
TyRoXx schrieb:
Jetzt mal mit dem richtigen Typ für Größen im Speicher:
Das ist, ich sage mal: "akademisch". Wenn die Anzahl der Felder sich nur noch in einem size_t repräsentieren lässt, dann lässt sich dafür auch kein Speicher mehr alloziieren.
Und wenn man möchte, kann man natürlich prüfen, ob die Multiplikation zweier Integer zu einem Überlauf führt. Für bestimmte Domänen ist das bestimmt auch nötig, für Spielbretter würde ich den Aufwand nicht sehen. Eher eine Prüfung, ob row und column in einen für die Anwendung typischen Bereich sind und ob die Werte > 0 sind. Diese Prüfung würde ich dann aber wahrscheinlich auch eher da sehen, wo die Werte herkommen und im c'tor bestenfalls ein assert auf > 0 vorsehen.
mfg Torsten
-
Ja, assert im ctor fände ich auch am schönsten.
-
Torsten Robitzki schrieb:
Wenn die Anzahl der Felder sich nur noch in einem size_t repräsentieren lässt, dann lässt sich dafür auch kein Speicher mehr alloziieren.
Das stimmt nicht. Rechne es doch mal nach.
Und absichtlich den falschen Typ zu verwenden, ist dumm.Torsten Robitzki schrieb:
Und wenn man möchte, kann man natürlich prüfen, ob die Multiplikation zweier Integer zu einem Überlauf führt.
An irgendeiner Stelle muss man das sowieso prüfen, sonst hat man später leicht undefiniertes Verhalten.
Torsten Robitzki schrieb:
Für bestimmte Domänen ist das bestimmt auch nötig, für Spielbretter würde ich den Aufwand nicht sehen.
Hat dir deine Kristallkugel verraten, dass die Brettgröße keine direkte Benutzereingabe ist?
Wo kommt immer dieser Widerstand gegen korrekte, einfache ("akademische") Lösungen her?
Torsten Robitzki schrieb:
Diese Prüfung würde ich dann aber wahrscheinlich auch eher da sehen, wo die Werte herkommen und im c'tor bestenfalls ein assert auf > 0 vorsehen.
Assertion kann man machen, aber das befreit nicht davon die Werte irgendwo zu prüfen.
-
TyRoXx schrieb:
Das stimmt nicht. Rechne es doch mal nach.
Und absichtlich den falschen Typ zu verwenden, ist dumm.Tut mir leid, aber auf so ein Niveau lasse ich mich erst gar nicht ein.