"Damenproblem": Programmabsturz bei For-Schleifenaufrufen?



  • class Schachbrett{
    public:
      int n;
      bool** Feld;
    
      Schachbrett(int breite)
      {
        n = breite;
        bool** Feld = new bool* [n];          //  <---------------  HIER
        for(int i=0;i<n;i++)
          Feld[i] = new bool[n];
        for(int i=0;i<n;i++)
        {
          for(int j=0;j<n;j++)
          {
            Feld[i][j] = true;
          }
        }
      }
    
      void printFeld()
      {
        for(int i=0;i<n;i++)
        {
          for(int j=0;j<n;j++)
          {
            cout << Feld[i][j];
          }
        }
      }
    };
    

    Edit:
    So würde ich das schreiben:

    class Schachbrett{
    public:
      Schachbrett(int breite)
      {
        m_width = breite;
        m_feld = new bool [m_width * m_width];
        for(int i=0; i<m_width * m_width; ++i)
        {
          m_feld[i] = true;
        }
      }
    
      void printFeld()
      {
        for(int i=0; i < m_width*m_width; ++i )
        {
          if( i%m_width == 0)
            cout << endl;
          cout << m_feld[i] << " ";
        }
      }
    
      int getFieldWidth()
      {
        return m_width;
      }
    
      bool& operator() (int x, int y)
      {
        assert( x<m_width );
        assert( y<m_width );
        return m_feld[ x +m_width* y];
      }
    
    private:
        int    m_width;
        bool*  m_feld;
    
    };
    

    Zugriff auf feldelemente bekommst du dann über:

    Schachbrett b(6);
        b.printFeld();
    
        b(4,5) = false;
        bool upperleft = b(0,0);
    

    Ich kann nicht glauben, dass (obwohl veraltet und kaum noch zu gebrauchen) dev c++ keinen debugger hat.



  • Vielen Dank für die Geduld! 🙂

    Also deine Variante kann ich nachvollziehen. Da das aber eine Programmieraufgabe aus der Uni ist, und wir von der Aufgabenstellung her gezwungen sind, (mehrdimensionale) dynamische Felder zu verwenden, die nachher auch wieder gelöscht werden sollen, kann ich das leider nicht so machen.

    Ich versteh leider immernoch nicht, wieso

    bool** m_Feld = new bool* [m_groesse];
        for(int i=0;i<m_groesse;i++)
          m_Feld[i] = new bool[m_groesse];
    

    keine korrekte Definition von einem mehrdimensionalen dynamischen Feld ist.

    Mir ist im übrigen aufgefallen, dass das Programm ohne den aufruf von b.printFeld() problemslos kompiliert und ausgeführt wird...

    Ein Beispiel aus einem Programm, das reibungslos funktioniert hat:

    double** A = new double* [n];
        for(int i=0;i<n;i++)  A[i] = new double [n];
    
        for(int i=0;i<n;i++)
        {
         for(int j=0;j<n;j++)
          {
            A[i][j]=0;
        }
       }
    

    Liegt es dann nicht vielleicht doch an der printFeld()-Methode? 😕

    Btw, kannst du mir einen guten C++-Editor für Windows empfehlen? Bin selbst nicht grad glücklich mit dem Dev-C++...



  • Haste "m_Feld" schon wieder zweimal definiert?



  • hurz schrieb:

    Vielen Dank für die Geduld! 🙂

    Also deine Variante kann ich nachvollziehen. Da das aber eine Programmieraufgabe aus der Uni ist, und wir von der Aufgabenstellung her gezwungen sind, (mehrdimensionale) dynamische Felder zu verwenden, die nachher auch wieder gelöscht werden sollen, kann ich das leider nicht so machen.

    Übrigens ein gutes stichwort:
    Du (ich auch in meinem Beispiel) hast vergessen einen destructor zu definieren, der die arrays delete[]ed .

    Ich versteh leider immernoch nicht, wieso

    bool** m_Feld = new bool* [m_groesse];
        for(int i=0;i<m_groesse;i++)
          m_Feld[i] = new bool[m_groesse];
    

    keine korrekte Definition von einem mehrdimensionalen dynamischen Feld ist.

    Ich habe nicht gesagt, dass sie falsch sei.
    Du deklarierst aber eine lokale variable, die genauso heißt wie die membervariable.
    Die lokale Variable hat eine stärkere Bindung als die Membervariable.
    Dh du weist einer lokalen variable den speicher deines tollen multidim arrays zu.
    Die variable liegt aber auf dem Stack und wird am ende der Funktion gelöscht (die is ja lokal).
    Also ist die membervariable deiner Klasse unberührt geblieben (undefinierter inhalt, da nirgens initialisiert).
    Außerdem hast du speicher alloziert, von dem die einzige Referenz entfernt wurde -> das heißt der kann nicht mehr gelöscht werden -> memory leak.

    in der printFeld methode wird nun auf die membervariable Feld (uninitialisiert) zugegriffen -> zeigt irgendwo hin im speicher -> Zugriffsverletzung.

    Mir ist im übrigen aufgefallen, dass das Programm ohne den aufruf von b.printFeld() problemslos kompiliert und ausgeführt wird...

    Ein Beispiel aus einem Programm, das reibungslos funktioniert hat:

    double** A = new double* [n];
        for(int i=0;i<n;i++)  A[i] = new double [n];
        
        for(int i=0;i<n;i++)
        {
         for(int j=0;j<n;j++)
          {
            A[i][j]=0;
        }
       }
    

    Liegt es dann nicht vielleicht doch an der printFeld()-Methode? 😕

    an der liegt es auch nicht. Hier wirkt sich nur dein Fehler aus dem Konsttruktor aus.

    Btw, kannst du mir einen guten C++-Editor für Windows empfehlen? Bin selbst nicht grad glücklich mit dem Dev-C++...

    Visual Studio 2008 Express c++
    Code::Blocks

    Sind die beliebtesten IDEs unter Windows. Beide Kostenlos und mit aktueller Standardbibliothek.

    class Schachbrett{
    public:
    
      Schachbrett(int breite)
      {
        m_width = breite;
        m_feld = new bool* [m_width];
        for(int i=0;i<m_width;i++)
        {
          m_feld[i] = new bool[m_width];
          for(int j=0;j<m_width;j++)
          {
            m_feld[i][j] = true;
          }
        }
      }
    
      ~Schachbrett()
      {
          for(int j=0;j<m_width;j++)
          {
            delete[] m_feld[j];
          }
          delete[] m_feld;   
      }
    
      void printFeld()
      {
        for(int i=0;i<m_width;i++)
        {
          for(int j=0;j<m_width;j++)
          {
            cout << m_feld[i][j];
          }
          cout << endl;
        }
      }
    
      int getFieldWidth()
      {
        return m_width;
      }
    
      bool& operator() (int x, int y)
      {
        return m_feld[x][y];
      } 
    
    private:
      int    m_width;
      bool** m_feld;
    };
    


  • Auch wenn dir das vielleicht momentan unangebracht erscheint, solltest du immer im Hinterkopf behalten, dass die C++-Standardbibliothek bereits fertige komfortable Klassen zur dynamischen Speicherverwaltung bereitstellt. 😉

    Falls du einmal keine Lust mehr auf new und delete hast, schlag mal zur STL (Standard Template Library) nach. In diesem Forum findest du bei den Artikel eine gute Einführung.



  • furz schrieb:

    Haste "m_Feld" schon wieder zweimal definiert?

    Ja, sorry, tut mir leid... 😞

    vlad schrieb:

    Ich habe nicht gesagt, dass sie falsch sei.
    Du deklarierst aber eine lokale variable, die genauso heißt wie die membervariable.

    Jetzt hab ich meinen Fehler erkannt. Im Nachhinein sag ich da nur: aufm Schlauch gestanden... ^^ (Ich war der richtigen Lösung aber doch sehr nah; hätte ich das "bool**" weggelassen... 🙄)

    Visual Studio 2008 Express c++
    Code::Blocks

    Sind die beliebtesten IDEs unter Windows. Beide Kostenlos und mit aktueller Standardbibliothek.

    Vielen Dank! 🙂

    Falls du einmal keine Lust mehr auf new und delete hast, schlag mal zur STL (Standard Template Library) nach. In diesem Forum findest du bei den Artikel eine gute Einführung.

    Danke für den Tip! Ich fürchte, ich kann und werde das nur zum privaten Interesse ausnutzen. Uni ist halt Uni, Vorgaben sind Vorgaben... 🙄

    Vielen Dank für eure Hilfe und Geduld! :xmas1:



  • Tip:
    membervariablen macht man normalerwesie private und gibt ihnen außerdem den präfix m_xxx.

    private ja. Präfix nein. Wozu gibt es namensräume.



  • ich denke, das wird dir jeder c++ entwickler bestätigen, dass es üblich ist, privaten member den Präfix m_ zu geben.
    Das ist auch insofern sinnvoll, dass man, wenn man code ließt auf den ersten blick sieht, ob es sich um eine lokale Variable, membervariable oder, im falle, dass man g_ und s_ oder i_ , o_ ind io_ für globale, statische, funktionsinput, -output und -in/output benutzt, auch um jene handelt.



  • vlad_tepesch schrieb:

    ich denke, das wird dir jeder c++ entwickler bestätigen, dass es üblich ist, privaten member den Präfix m_ zu geben.
    Das ist auch insofern sinnvoll, dass man, wenn man code ließt auf den ersten blick sieht, ob es sich um eine lokale Variable, membervariable oder, im falle, dass man g_ und s_ oder i_ , o_ ind io_ für globale, statische, funktionsinput, -output und -in/output benutzt, auch um jene handelt.

    Mal davon abgesehen, dass ich das m/m_/... für Membervariablen auch verabscheue gabs die Diskussion ja nun echt schon ein zwei mal ^^ Vll sollte man ja in Zukunft wieder versuchen nicht ganz so sehr vom Thema abzuschweifen



  • Kein_präfix schrieb:

    Wozu gibt es namensräume.

    Das Argument gegen Präfixe bei Membervariablen. 😃



  • ganz egal, wie man das sieht - trotzdem ist es üblich.

    Die Regelung findet sich sicherlich auch in den Programmierrichtlinen der meisten Unternehmen.


  • Administrator

    vlad_tepesch schrieb:

    ganz egal, wie man das sieht - trotzdem ist es üblich.

    Die Regelung findet sich sicherlich auch in den Programmierrichtlinen der meisten Unternehmen.

    Meiner Meinung nach ist das "üblich" völlger Quatsch. Die Richtlinien sind eher weit gestreut und jeder macht es irgendwie anders. Sieht man sehr gut daran, welche Vorlieben in diesem Forum herrschen 😉

    Ich würde es jedenfalls ganz sicher nicht einfach als Standard annehmen, das wäre von mir aus gesehen, ein völlig falsches Bild. Ich wäre aber natürlich glücklich darüber, wenn mein m_ so üblich wäre 🙂

    Grüssli


Anmelden zum Antworten