Frage zu Bedingungen



  • Abend!

    Wie der Titel schon sagt: Ich hab eine Frage zu Bedingungen.

    Es geht um eine If-Bedingung.

    Und zwar soll eine integer Variable den Wert 1 annehmen, wenn alle Einträge einer 3x3 Matrix ungleich null sind.

    also folgendermaßen:

    if ( (matrix[0][0] != 0 ) && ( matrix [0][1] != 0 ) && ... && ( matrix [3][3]!=0 ) )
       var = 1;
    

    Die Bedingung würde also, wie man sieht, ziemlich lang werden.

    Gibt es eine Möglichkeit, Schreibarbeit zu ersparen, indem man in die Bedingung Zählschleifen oder ähnliches hinein tut?

    Würde mich über Ratschläge freuen.

    Gruß ser_u


  • Mod

    Schreib eine Funktion, die die Bedingung prüft. Die benutzt intern dann Schleifen.



  • template <int i, int j>
    struct ZeroCheck
    {
    	template <int N, int M>
    	static bool isZero(const int (&matrix)[N][M])
    	{
    		return matrix[i][j] == 0 && ZeroCheck<i, j-1>::isZero(matrix);
    	}
    };
    
    template <int i>
    struct ZeroCheck<i, 0>
    {
    	template <int N, int M>
    	static bool isZero(const int (&matrix)[N][M])
    	{
    		return matrix[i][0] == 0 && ZeroCheck<i-1, M-1>::isZero(matrix);
    	}
    };
    
    template <>
    struct ZeroCheck<0, 0>
    {
    	template <int N, int M>
    	static bool isZero(const int (&matrix)[N][M])
    	{
    		return matrix[0][0] == 0;
    	}
    };
    
    template <int N, int M>
    bool isZero(const int (&matrix)[N][M])
    {
    	return ZeroCheck<N-1, M-1>::isZero(matrix);
    }
    
    int main()
    {
    
    	int m[3][4] = {};
    
    	return isZero(m);
    }
    

    🕶


  • Mod

    @dot: C-Forum, nicht C++.



  • @dot: C-Forum, nicht C++.

    Danke für die Aufklärung, war reichlich verwirrt 🙂
    (Hab C++ noch gar nicht gelernt)

    Gruß



  • oops, sry... 🤡



  • SeppJ schrieb:

    Schreib eine Funktion, die die Bedingung prüft. Die benutzt intern dann Schleifen.

    Danke für den Tipp.

    Ich hab mal eine Funktion geschrieben, scheint auch zu funktionieren.

    Die Schleife überprüft jeden Eintrag der Matrix.

    Wenn der Rückgabewert var = 1 ist, dann ist mindestens ein Eintrag in der Matrix gleich Null, also die oben gepostete Bedingung nicht erfüllt.

    Die Funktion hört dann auf weiter zu prüfen, sobald ein Eintrag gleich Null ist.

    Ist die Funktion, so wie ich sie geschrieben habe, sauber programmiert oder lässt sich noch was verbessern?

    int test_mat(int mat[3][3])
    {
        int mat[3][3]; 
        int var;
        int zeile, spalte;
    
        var = 0;
        zeile = 0;
        spalte = 0;
    
              while ( zeile < 3 && var == 0)
              {
                    zeile = zeile + 1;
    
                    while ( spalte < 3 && var == 0)
                    {
                          spalte = spalte + 1;
    
                          if ( mat[zeile-1][spalte-1] == 0)
                             var = 1; 
                    }
    
                    spalte = 0;
              }
    
        return var;    
    }
    

    Gruß ser_u


  • Mod

    Das ließe sich wesentlich verbessern, indem du for-Schleifen benutzt.

    Variablen kannst du auch gleich bei der Definition initialisieren.

    Dein Programm ist falsch. Du überprüfst ein lokales Array, nicht das übergebene Argument.



  • Und einfach zurückspringen, wenn eine der Teilbedingungen erfüllt ist:
    if ( mat[zeile-1][spalte-1] == 0)
    return 1;



  • Hey,

    Vielen Dank für die Hinweise!

    Warum ich keine for-Schleife benutzt hatte lag daran, dass die for-Schleife weiter prüft, auch wenn nicht mehr geprüft werden muss.

    Dass man return auch mitten im Programm benutzen kann, wusste ich nicht!
    Dadurch wäre ja das "Problem" mit der for-Schleife gelöst.

    Und die Zeile 3 vom oberen Code hab ich ausversehen gepostet, gehört da natürlich nicht rein.

    Hier mal eine überarbeitete Version mit for-Schleife:

    int test_voll(int spielfeld[3][3])
    {
        int zeile, spalte;
    
           for (zeile = 1; zeile <= 3; zeile++)
           {
               for (spalte = 1; spalte <= 3; spalte++)
               {
                   if ( spielfeld[zeile-1][spalte-1] == 0 ) 
                      return 0;  // Spielfeld ist noch nicht voll
               }
           }
    
        return 1; // Spielfeld ist voll
    }
    

    Ich schreibe übrigens zur Übung das Spiel TicTacToe.

    Diese Funktion soll prüfen und dem Hauptprogramm mitteilen, ob das Spielfeld voll ist.

    Wenn ein Eintrag in der Spielfeld-Matrix Null ist, heißt es, dass der Eintrag für die Spieler verfügbar ist bzw. das Spielfeld noch nicht voll ist.

    Ist der Code noch verbesserungswürdig, oder ist das diesmal sauber programmiert?

    Gruß, ser_u



  • Fang bei 0 an, wie man es in C so macht.

    for (zeile = 0; zeile <  3; zeile++)
                 ^         ^ 
    ...
            spielfeld[zeile  ][spalte-1]
                           ^^
    

    Dann sparst du dir auch das -1

    ser_u schrieb:

    Warum ich keine for-Schleife benutzt hatte lag daran, dass die for-Schleife weiter prüft, auch wenn nicht mehr geprüft werden muss.

    Das ist falsch. Du kannst die Bedingung aus der while -Schleife auch in die

    Du kannst die for in eine while-Schleife umwandeln und umgekehrt:
    for -Schleife einbauen.
    While-Schleife:

    Initialisierung;
    while (Bedingung) {
      Schleifenkörper
    increment;
    }
    

    For-Schleife:

    for(Initialisierung; Bedingung; increment) {
      Schleifenkörper
    }
    

    Der einzige Unterschied wäre bei der Sichtbarkeit der Schleifenvariable, wenn du diese erst bei der Initialisierung definierst.



  • DirkB schrieb:

    Du kannst die for in eine while-Schleife umwandeln und umgekehrt:

    For-Schleife:

    for(Initialisierung; Bedingung; increment) {
      Schleifenkörper
    }
    

    Verstehe. Also kann man mehrere Austritts- bzw, Eintrittsbedingungen auch für for-Schleifen verwenden; wieder was neues gelernt. Danke!

    Hab jetzt zwei Varianten, wobei mir die 2. besser gefällt, da weniger Variablen verwendet werden und weniger Bedingungen für die for-Schleife gebraucht werden:

    int test_voll(int spielfeld[3][3])
    {
        int zeile, spalte;
        int voll = 1;
    
           for (zeile = 0; zeile<3 && voll==1; zeile++)
           {
               for (spalte = 0; spalte<3 && voll==1; spalte++)
               {
                   if ( spielfeld[zeile][spalte] == 0 )
                      voll = 0;
               }
           }
    
        return voll;
    }
    
    int test_voll(int spielfeld[3][3])
    {
        int zeile, spalte;
    
           for (zeile = 0; zeile < 3; zeile++)
           {
               for (spalte = 0; spalte < 3; spalte++)
               {
                   if ( spielfeld[zeile][spalte] == 0 )
                      return 0;  // Spielfeld ist noch nicht voll
               }
           }
    
        return 1; // Spielfeld ist voll
    }
    

    Falls es noch weitere Anmerkungen zu den Codes gibt, immer her damit 😃

    Ansonsten Danke für die Hilfe, hab einiges neues lernen können.

    Gruß ser_u


  • Mod

    ser_u schrieb:

    Falls es noch weitere Anmerkungen zu den Codes gibt, immer her damit 😃

    Ist alles richtig, aber nur um sicher zu gehen, noch eine Verständnisfrage an dich:

    int test_voll(int spielfeld[3][3])
    

    Dir ist schon klar, dass die erste 3 überhaupt keine Bedeutung hat und dort auch genau so gut

    int test_voll(int spielfeld[465663][3])
    

    oder

    int test_voll(int spielfeld[][3])
    

    oder

    int test_voll(int (*spielfeld)[3])
    

    stehen könnte, ohne den geringsten Unterschied zu machen? Und dir ist auch bewusst, welche Eigenarten von Arrays dafür verantwortlich sind?



  • Danke für die Frage.

    Ehrlich gesagt war mir das nicht bewusst gewesen, ich dachte durch

    int spielfeld[3][3]
    

    habe ich einfach eine 3x3 Matrix bzw. ein 2-Dimensionales Array mit drei Zeilen/Spalten.

    Mein Array wird übrigens im Hauptprogramm folgendermaßen initialisiert:

    int main()
    {
      int spielfeld[3][3];
      int zeile,spalte;
      ...
    
        for(zeile=0;zeile<3;zeile++)
      {
           for(spalte=0;spalte<3;spalte++)
           {
               spielfeld[zeile][spalte]=0;
           }
      } 
    
      ...
    

    Das heißt, dass es sich bei dem Array um ein vollständig initialisiertes mehrdimensionales Array handelt. (stimmt das?)

    Was ich noch in Erfahrung bringen konnte:

    Es ist empfehlenswert, die Größenangaben bei Arrays nicht wegzulassen. (Wahrscheinlich der Übersicht halber?)

    Man kann aber die erste Größenangabe weglassen. Der Compiler kümmert sich dann darum, dass das Array genau so groß ist, wie man es braucht.

    (Warum das nur mit der ersten Größenangabe klappt und wieso man das überhaupt weglassen sollte, verstehe ich aber nicht.)

    Wenn man

    int spielfeld[465663][3]
    

    verwendet, hätte man in meinem Fall ein teilweise initialisiertes mehrdimensionales Array: Die nicht verwendeten Plätze werden mit Nullen gefüllt beim Compilieren.(richtig?)

    int (*spielfeld)[3]
    

    Hier hast du was mit nem Zeiger gemacht.
    Zu Zeigern weiß ich noch nicht so viel, da muss ich noch weiteres zu lesen.

    SeppJ schrieb:

    Und dir ist auch bewusst, welche Eigenarten von Arrays dafür verantwortlich sind?

    Haben diese Eigenarten bestimmte Bezeichnungen?

    Gruß ser_u



  • Will mich mal hier an den Thread etwas anhängen....

    Ein 2 Dim Array könnte man auch so inintialisieren oder?
    Also funktionieren tut es bei mir, jetzt bin ich gespannt was alles "nicht soo" richtig ist... (Vor allem die Zuweisungen in Main ... )

    void fill2(int **arr, int zeile, int spalte){
    
    int i, j, value=2; 
    for (i=0; i<zeile; i++){
    	for(j=0; j<spalte; j++){
    	     *(*arr+(i*spalte)+j)=value;
    		value*=2;
    	}
    }
    
    }
    

    main.c

    int arr[3][3], *ptr;
    ptr=&arr[0][0];          //das ist irgendwie komisch....
    fill2(&ptr, 3, 3);
    

    Was für "kryptische" möglichkeite für 2Dim init gibt es noch so??



  • Nachtrag :
    Bietet der Doppelpointer irgendeinen Vorteil?

    MIt "einfach-Pointer" gings ja auch..

    void fill(int *arr, int zeile, int spalte){
    ...
    ...
    ..
    *(arr+(i*zeile)+j)=value++;
    ...
    


  • Das kommt darauf an, ob du das Argument typkompatibel zum Funktionsprototyp angibst.
    "Programm funktioniert bei mir..." ist jedenfalls kein Grund, von einem fehlerfreien Code auszugehen.
    Die Adresse sollte zwar (typunabhängig) meistens gleich sein (falls der Compiler nur eine feste Größe für alle Zeiger festlegt), entscheidend für UB oder nicht UB ist aber die Dereferenzierung bei Zeigern, und die ist eben für typinkompatible Zeiger wegen des auch noch zu berücksichtigenden Alignments (wird sehr oft wegen Unkenntnis vergessen) immer UB. (der Code kann funktionieren, muss es aber nicht...)

    int a[3][3], *ptr = &a[0][0];
    
    fill(int *a);
    OK: fill(&a[0][0])
    
    fill(int **a);
    OK: fill(&ptr)
    UB: fill(&a[0][0]);
    UB: fill(a);
    UB: fill(ptr);
    UB: fill(&a[0]);
    

    Das ganze Zeugs kannst du aber immer umgehen, wenn die 2.Dimension abwärts jeweils zur Compilezeit bekannt ist, so wie in deinem Fall, also:

    int a[3][3];
    
    fill(int a[3][3]);
    OK: fill(a);
    fill(int a[][3]);
    OK: fill(a);
    fill(int a[12345][3]);
    OK: fill(a);
    fill(int (*a)[3]);
    OK: fill(a);
    


  • "Programm funktioniert bei mir..." ist jedenfalls kein Grund, von einem fehlerfreien Code auszugehen.

    ... da kann ich ein Lied von singen 🙂

    Was ist die "beste" oder "eleganteste" Möglichkeit ein 2D Array zu übergeben und zu füllen?



  • Ps.:
    Was ist bei:

    fill(int *a);
    OK: fill(&a[0][0])
    

    mit

    int *ptr;
    ptr=&arr[0][0];
    fill(ptr);
    

    Kein UB ...?



  • Noch was...

    Wutz schrieb:

    Das ganze Zeugs kannst du aber immer umgehen, wenn die 2.Dimension abwärts jeweils zur Compilezeit bekannt ist, so wie in deinem Fall, also:

    int a[3][3];
    
    fill(int a[3][3]);
    OK: fill(a);
    fill(int a[][3]);     // Hier muss ich noch die Zeilen mit übergeben ?
    OK: fill(a);
    fill(int a[12345][3]);
    OK: fill(a);
    fill(int (*a)[3]);    // Hier ebenfalls #??
    OK: fill(a);
    

Log in to reply