INI Datei auslesen und als #define speichern
-
llm schrieb:
…
1. Attribute hoch!
2. Nimm Copy&Swap
3. Lass die Nullzuweisung nach delete
-
//neues array mit inhalt des alten anlegen ala array2(array1) array_2d_t(const array_2d_t& p_other) m_width(p_other.m_width), m_height(p_other.m_height), m_buffer(0) { m_buffer = new int[m_width*m_height](); // mit 0 initialisierung std::copy(p_other.m_buffer, p_other.m_buffer + m_width*m_height, m_buffer); }
=>
//neues array mit inhalt des alten anlegen ala array2(array1) array_2d_t(const array_2d_t& p_other):: // =0 nicht nötig, Array mit zu 0 vollschreiben unnötig, Reihenfolge der Member beachten. m_buffer(new int[p_other.m_width*p_other.m_height]), m_width(p_other.m_width), m_height(p_other.m_height) { std::copy(p_other.m_buffer, p_other.m_buffer + m_width*m_height, m_buffer); }
-
1. Attribute hoch!
ist keine class (es fehlt an private usw.) aber gehören trotzdem nicht
zur Schnittstelle - also ist es gut wenn man die nicht sofort sieht2. Nimm Copy&Swap
ich dachte etwas mehr Handarbeit könnte verständlicher sein
3. Lass die Nullzuweisung nach delete
ich finde ich es manchmal nett mein Objekt stärker zu invalidieren
(als eine Art assert für z.B. fehlerhafter move-semantic implementation usw.)@4.
ich wollte die kopiererei nur homogener aussehen lassen
es fehlt noch eine const-korrekte at methode, public/private, ein paar kleine Hilfsmethoden, value_type als template Parameter usw... aber es sollte nur ein wenig besser sein - nicht gleich die volle Ladung Perfektion
-
Carreck schrieb:
Ich bin jetzt mal auf den Zug von llm aufgesprungen und habe folgendes gebastelt:
Nicht basteln...
Man, Kerl! Ich dachte Du willst jetzt C machen, und auf einmal kommst Du mit noch mehr C++ um die Ecke.
Vielleicht beendest Du mal Deinen panischen trial-and-error Modus und kommst zur Besinnung. Du bist doch nicht auf der Flucht!So wird das jedenfalls nix!
PS: Happy Ausbildungsanfang!
-
llm schrieb:
1. Attribute hoch!
ist keine class (es fehlt an private usw.) aber gehören trotzdem nicht
zur Schnittstelle - also ist es gut wenn man die nicht sofort siehtDas Gedasel um Schnittstellen ist absolut kein Argument. Es erhöht die Lesbarkeit ungemein, wenn man die Attribute zuerst gezeigt bekommt.
llm schrieb:
2. Nimm Copy&Swap
ich dachte etwas mehr Handarbeit könnte verständlicher sein
Aber ist nicht exception-sicher.
llm schrieb:
3. Lass die Nullzuweisung nach delete
ich finde ich es manchmal nett mein Objekt stärker zu invalidieren
(als eine Art assert für z.B. fehlerhafter move-semantic implementation usw.)Aber im Destruktor?! Das Attribut verschwindet eh sofort.
-
@volkard - 100% ACK
m_buffer = 0 ist nur eine pseudo-Strategie die ich mir angewöhnt habe
weil ich zu oft während meiner Arbeit use-after-free Bugs usw. finde (auch ohne Sanitizer/Valgrind,...) - das hilft ein wenig, ist aber wie du schon sagst völlig unnötignur so als Tip:
nimm einfach deinen funktionierenden Source vom ersten Post (UNVERAENDERT)
der mit den #defines welcher funktioniertdann fuegst du meine erste Version des array_2d_t oben rein
die Kopierfunktionalität aus der neueren brauchst du gar nichtErsetze stupide genau in der Reihenfolge
1. void random_array(int A[X][Y]) -> void random_array(array2d_t& A)
2. void array_anzeigen(int arr[X][Y]) -> void array_anzeigen(array_2d_t& arr)
3. void neues_array(int A[X][Y]) -> void neues_array(array_2d_t& a)
4. int temp[X][Y]; -> array_2d_t temp(X,Y);
5. int maske[Y][X]; -> array_2d_t maske(X,Y);
6. int A[X][Y]; -> array2d_t A(X,Y);
7. alle Zugriffe auf X durch passendes .width()
8. und alle Zugriffe auf Y durch passendes .heigth()
9. und alle Array-Zugriffe mit [?][?] durch .at(?,?)dann sollte schonmal alles mit dem array_2d_t laufen - wenn
der assert wieder zuschlaegt ist dein original auch schon fehlerhaft
und muss korrigiert werden
jetzt kannst du sehr leicht deine INI-Parameter einbauen
-
llm schrieb:
m_buffer = 0 ist nur eine pseudo-Strategie die ich mir angewöhnt habe
weil ich zu oft während meiner Arbeit use-after-free Bugs usw. finde (auch ohne Sanitizer/Valgrind,...) - das hilft ein wenig, ist aber wie du schon sagst völlig unnötigFalls es dir nicht bekannt ist: Du verschleierst dafür andere Arten von Fehlern, wie doppelte frees. Diese würden zwar im Gegensatz zum beschriebenen Fehler kein undefiniertes Verhalten auslösen, deuten aber auf einen Logikfehler hin, der dann unentdeckt bleibt. Da dies die selbe Klasse von Logikfehlern ist wie use-after-free, ist anzunehmen, dass es auch diese Sorte in den genannten Programmen gibt.
-
llm schrieb:
@volkard - 100% ACK
m_buffer = 0 ist nur eine pseudo-Strategie die ich mir angewöhnt habe
weil ich zu oft während meiner Arbeit use-after-free Bugs usw. finde (auch ohne Sanitizer/Valgrind,...) - das hilft ein wenig, ist aber wie du schon sagst völlig unnötignur so als Tip:
nimm einfach deinen funktionierenden Source vom ersten Post (UNVERAENDERT)
der mit den #defines welcher funktioniertdann fuegst du meine erste Version des array_2d_t oben rein
die Kopierfunktionalität aus der neueren brauchst du gar nichtErsetze stupide genau in der Reihenfolge
1. void random_array(int A[X][Y]) -> void random_array(array2d_t& A)
2. void array_anzeigen(int arr[X][Y]) -> void array_anzeigen(array_2d_t& arr)
3. void neues_array(int A[X][Y]) -> void neues_array(array_2d_t& a)
4. int temp[X][Y]; -> array_2d_t temp(X,Y);
5. int maske[Y][X]; -> array_2d_t maske(X,Y);
6. int A[X][Y]; -> array2d_t A(X,Y);
7. alle Zugriffe auf X durch passendes .width()
8. und alle Zugriffe auf Y durch passendes .heigth()
9. und alle Array-Zugriffe mit [?][?] durch .at(?,?)dann sollte schonmal alles mit dem array_2d_t laufen - wenn
der assert wieder zuschlaegt ist dein original auch schon fehlerhaft
und muss korrigiert werden
jetzt kannst du sehr leicht deine INI-Parameter einbauenDie erste Version ist insofern fehlerhaft, dass, wenn ich bei (0,0) bin und er dann -1 macht, bin ich ja definitiv in einem Speicherbereich, wo ich nicht sein kann, da er nicht belegt ist.
Von der Logik her muss ich also "nur" die Abfrage umschreiben.
Überprüfen, wo ich bin und dann die Felder drum rum. Macht man das am besten im Switch-Case Format?Ich weiß, ich bin ein bisschen schwierig.. In diesem Sinne: Danke schonmal, dass ihr mir helft..
-
Du verschleierst dafür andere Arten von Fehlern, wie doppelte frees.
du hast ja recht - ich mache es auch eher so
m_buffer = (int*)-1;
aber gehört hier wohl einfach nicht rein
Von der Logik her muss ich also "nur" die Abfrage umschreiben.
der zuletzt von dir gepostete Source ist totaler Müll
mach einfach das stupide Ersetzen GENAU SO wie in meinem letzten Post beschrieben und suche dann den Fehler in der Verarbeitung - alles andere macht einfach keinen Sinn - dein nächster Post sollte deine 1. Version mit dem array_2d_t sein - ohne sonstige Änderungen, sei einfach mal Konsequent ohne basteln
-
llm schrieb:
mach einfach das stupide Ersetzen wie in meinem letzten Post beschrieben und suche dann den Fehler in der Verarbeitung - alles andere macht einfach keinen Sinn
Das habe ich bereits gemacht, dementsprechend sieht der Quellcode folgendermaßen aus:
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <fstream> #include <cassert> #define X 10 #define Y 10 struct array_2d_t { array_2d_t(int p_width, int p_height) : m_width(p_width), m_height(p_height), m_buffer(0) { //allokieren m_buffer = new int[p_width*p_height]; } ~array_2d_t() { //speicher aufrauemen delete[] m_buffer; m_buffer = 0; } int& at(int x, int y) { assert(x >= 0 && x < m_width); assert(y >= 0 && y < m_height); return m_buffer[x*m_width + y]; } int width() const { return m_width; } int height() const { return m_height; } int* m_buffer; // alternativ auch std::vector<std::vector<int>> aber man soll ja noch was lernen int m_height; int m_width; }; void random_array(array_2d_t& A) //Random Array mit X,Y erzeugen { for (int i = 0; i < A.height(); i++) { for (int j = 0; j < A.width(); j++) { A.at(i,j) = rand() % 2; //Füllen mit 0 / 1 } } } void array_anzeigen(array_2d_t& arr) //Random Array mit X,Y anzeigen { for (int i = 0; i < arr.width(); i++) { for (int j = 0; j < arr.height(); j++) { printf(" %d", arr.at(i,j)); } printf("\n"); } printf("\n"); } void neues_array(array_2d_t& a) { array_2d_t temp(X, Y); for (int i = 0; i < a.height(); i++) { for (int j = 0; j < a.width(); j++) { temp.at(i,j) = a.at(i,j); } } array_2d_t maske(X, Y); for (int i = 0; i < a.height(); i++) { for (int j = 0; j < a.width(); j++) { maske.at(i,j) = 0; } } for (int i = 0; i < a.height(); i++) { for (int j = 0; j < a.width(); j++) { if (temp.at((i-1),(j-1)) == 1 && i > 0 && j > 0) ++maske.at(i,j); if (temp.at(i,(j-1)) == 1 && j > 0) ++maske.at(i,j); if (temp.at((i-1),j) == 1 && i > 0) ++maske.at(i,j); if (temp.at((i-1),(j+1)) == 1 && i > 0 && j + 1 < X) ++maske.at(i,j); if (temp.at(i,(j+1)) == 1 && j + 1 < X) ++maske.at(i,j); if (temp.at((i+1),j) == 1 && i + 1 < Y) ++maske.at(i,j); if (temp.at((i+1),(j-1)) == 1 && i + 1 < Y && j > 0) ++maske.at(i,j); if (temp.at((i+1),(j+1)) == 1 && i + 1 < Y && j + 1 < X) ++maske.at(i,j); if (maske.at(i,j) > 3 || maske.at(i,j) < 2) a.at(i,j) = 0; else if (maske.at(i,j) == 3) a.at(i,j) = 1; } } } int main(void) { srand((unsigned int)time(NULL)); array_2d_t A(X, Y); random_array(A); int runde = 1; while (getchar()) { neues_array(A); printf(" Runde %i\n", runde); array_anzeigen(A); ++runde; } return 0; }
Und dennoch:Es existiert immer noch der Assert-Fehler, weshalb ich die Abfrage umschreiben muss (so denk ich mir zumindest..)
-
Das habe ich bereits gemacht
guter Junge - jetzt machen wirs noch kurz "konfigurierbar" und dann darfst
du deinen Fehler suchen1. in void neues_array(array_2d_t& a){...}
X ersetzen durch a.width()
Y ersetzen durch a.height()2. in int main(){...}
nach srand((unsigned int)time(NULL));
int X = GetPrivateProfileInt("general","X", 10, ini);
int Y = GetPrivateProfileInt("general","Y", 10, ini);einfuegen
#define X und Y loeschen
dann deinen Fehler suchen und die dynamische Spielfeldgroesse geniessen
-
Und wie schon geschrieben, die Bedingungen umdrehen:
if (i > 0 && j > 0 && temp.at((i-1),(j-1)) == 1)
etc.
Aber dieses Gemisch aus C und C++ ist schrecklich - entweder nur C (dies ist schließlich das C Subforum!) oder konsequent modernes C++.
-
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <fstream> #include <Windows.h> #include <cassert> struct array_2d_t { array_2d_t(int p_width, int p_height) : m_width(p_width), m_height(p_height), m_buffer(0) { //allokieren m_buffer = new int[p_width*p_height]; } ~array_2d_t() { //speicher aufrauemen delete[] m_buffer; m_buffer = 0; } int& at(int x, int y) { assert(x >= 0 && x <= m_height); assert(y >= 0 && y <= m_width); return m_buffer[x*m_width + y]; } int width() const { return m_width; } int height() const { return m_height; } int* m_buffer; // alternativ auch std::vector<std::vector<int>> aber man soll ja noch was lernen int m_height; int m_width; }; void random_array(array_2d_t& A) //Random Array mit X,Y erzeugen { for (int i = 0; i < A.height(); i++) { for (int j = 0; j < A.width(); j++) { A.at(i,j) = rand() % 2; //Füllen mit 0 / 1 } } } void array_anzeigen(array_2d_t& arr) //Random Array mit X,Y anzeigen { for (int i = 0; i < arr.height(); i++) { for (int j = 0; j < arr.width(); j++) { printf(" %d", arr.at(i,j)); } printf("\n"); } printf("\n"); } void neues_array(array_2d_t& a) { array_2d_t temp(a.width(), a.height()); for (int i = 0; i < a.height(); i++) { for (int j = 0; j < a.width(); j++) { temp.at(i,j) = a.at(i,j); } } array_2d_t maske(a.width(), a.height()); for (int i = 0; i < a.height(); i++) { for (int j = 0; j < a.width(); j++) { maske.at(i,j) = 0; } } for (int i = 0; i < a.height(); i++) { for (int j = 0; j < a.width(); j++) { if (i > 0 && j > 0 && temp.at((i - 1), (j - 1)) == 1) ++maske.at(i, j); if (j > 0 && temp.at(i, (j - 1) == 1)) ++maske.at(i, j); if (i > 0 && temp.at((i - 1), j) == 1) ++maske.at(i, j); if (i > 0 && j + 1 < a.width() && temp.at((i - 1), (j + 1)) == 1) ++maske.at(i, j); if (j + 1 < a.width() && temp.at(i, (j + 1)) == 1) ++maske.at(i, j); if (i + 1 < a.height() && temp.at((i + 1), j) == 1) ++maske.at(i, j); if (i + 1 < a.height() && j > 0 && temp.at((i + 1), (j - 1)) == 1) ++maske.at(i, j); if (i + 1 < a.height() && j + 1 < a.width() && temp.at((i + 1), (j + 1)) == 1) ++maske.at(i, j); if (maske.at(i, j) > 3 || maske.at(i, j) < 2) a.at(i, j) = 0; else if (maske.at(i, j) == 3 || maske.at(i,j) == 2) a.at(i, j) = 1; } } } int main(void) { srand((unsigned int)time(NULL)); int X = GetPrivateProfileInt("general", "X", 10, "./test.txt"); int Y = GetPrivateProfileInt("general", "Y", 10, "./test.txt"); array_2d_t A(X, Y); random_array(A); int runde = 1; while (getchar()) { neues_array(A); printf(" Runde %i\n", runde); array_anzeigen(A); ++runde; } return 0; }
So, geht...
-
Carreck schrieb:
/* ... */ int& at(int x, int y) { assert(x >= 0 && x <= m_height); assert(y >= 0 && y <= m_width); return m_buffer[x*m_width + y]; } /* ... */
Die Implementierung von llm ist in zweierlei Hinsicht irreführend:
Erstens werden zweidimensionale Koordinaten üblicherweise als (x/y) angegeben, wobei x die horizontale (column) und y die vertikale Entfernung (row) vom Ursprung angibt. Bei llm ist es (lautassert
s) umgekehrt.
Zweitens ist auch das Speicherlayout für C und C++ unüblich.Mein Vorschlag:
/* ... */ int& at(int x, int y) { assert(0 <= x && x < m_width); assert(0 <= y && y < m_height); return m_buffer[y*m_width + x]; } /* ... */
Über deine
i
undj
will ich nicht nachdenken, solange sie nichtx
undy
heißen ...
-
Carreck schrieb:
if (temp.at((i-1),(j-1)) == 1 && i > 0 && j > 0) ++maske.at(i,j); if (temp.at(i,(j-1)) == 1 && j > 0) ++maske.at(i,j); if (temp.at((i-1),j) == 1 && i > 0) ++maske.at(i,j); if (temp.at((i-1),(j+1)) == 1 && i > 0 && j + 1 < X) ++maske.at(i,j); if (temp.at(i,(j+1)) == 1 && j + 1 < X) ++maske.at(i,j); if (temp.at((i+1),j) == 1 && i + 1 < Y) ++maske.at(i,j); if (temp.at((i+1),(j-1)) == 1 && i + 1 < Y && j > 0) ++maske.at(i,j); if (temp.at((i+1),(j+1)) == 1 && i + 1 < Y && j + 1 < X) ++maske.at(i,j);
Und dennoch:Es existiert immer noch der Assert-Fehler, weshalb ich die Abfrage umschreiben muss (so denk ich mir zumindest..)
Das Problem liegt im zitierten Code. Beweg die Prüfungen von i und j vor den Aufruf von temp.at in der if-Bedingung. Ansonsten greifst du auch mit ungültigen Werten schon auf temp zu und das löst die asserts aus.
-
@Swordfish
In deinen asserts nur auf kleiner prüfen, nicht kleiner gleich (jeweils die zweite Überprüfung).
-
Danke DocShoe! Korrigiert.
-
zu meine halben Ehrenrettung - die height(), with() hat Carreck beim
kopieren meines Beispiels vertauscht oder versucht damit meinen Fehler mit x*with+y zu korrigieren
-
llm schrieb:
zu meine halben Ehrenrettung - die height(), with() hat Carreck beim
kopieren meines Beispiels vertauscht [..]Sorry, hat-
te die hoff-
nung, Carr-
eck beherr-
sche Copy
& Paste.
-
Die ganze Sache ist und bleibt Müll, ob nun C++ Zeugs im C Forum oder algorithmischer Schrott mit der total redundanten 'maske', für die eine simple temp. int-Variable ausreicht.
Das wird auch nicht besser, wenn hier irgendwelche Pseudo-Helfer den Code noch mehr verunstalten, es bleibt dabei: dein Code ist Schrott, deine Programmlogik ist Schrott, deine Arbeitsweise beim Herangehen an Probleme ist Schrott, lasse dich damit am besten nirgendwo sehen, d.h. erst recht nicht hier im C-Forum.