Mehrdimensionale Arrays mit flexibler Größe



  • Hallo Forum,

    ich habe die Aufgabe, meinen funktionierenden (Java-)Code nach C++ zu übertragen. Mein Problem ist, dass ich nicht einfach wie gewohnt

    void f( int array[][] ) {
    }
    main() {
      int testvalues[][] = {...};
      f( testvalues );
    }
    

    schreiben kann, weil C++ feste Größen für die Arrays haben will.
    Also muss ich das Ganze wohl über Zeiger lösen, was ich nach folgendem Schema versucht habe:

    #include <cstdio>
    using namespace std;
    
    const int size = 3;
    
    void printarray( int **arr, int length ) {
      for ( int i = 0; i < length; i++ ) {
        for ( int j = 0; j < length; j++ )
          printf( "%d\t", arr[i][j] );
        printf( "\n" );
      }
    }
    
    int main() {
      // Schön, kann ich aber nicht an eine Funktion übergeben
      int testarray[size][size] = {{1,2,3},{4,5,6},{7,8,9}};
    
      // Workaround, um Daten zu haben, die ich einer Funktion geben kann
      int **testptrs = new int*[size];
      for ( int i = 0; i < size; i++ ) {
        testptrs[i] = new int[size];
        for ( int j = 0; j < size; j++ )
          testptrs[i][j] = testarray[i][j];
      }
    
      printarray( testptrs, size );
      return 0;
    }
    

    Das tut genau das was es soll, aber ich hätte gerne die Möglichkeit, mir den mittleren Block zu sparen. Wenn ich versuche,

    memcpy( testptrs, testarray, size*size  )
    

    zu nutzen, dann kompiliert das zwar, wirft aber beim Auslesen Segmentation faults.
    Kann ich irgendwie
    - entweder testptrs direkt mit Startwerten belegen oder
    - testarray einfach an die Funktion übergeben?

    Ich möchte das eigentlich direkt lösen, ohne dafür Vektorklassen, die Boost Library oder ähnliches zu benutzen - ist das möglich?

    Schon mal danke im Voraus.



  • C++ kennt den Typ std::vector<> als dynamischen Container.
    Für weitere Details einfach mal Referenzen durchblättern.

    MfG



  • bis auf cstdio ist das reines C. Warum soll das ins C++ Forum?


  • Mod

    otze schrieb:

    bis auf cstdio ist das reines C. Warum soll das ins C++ Forum?

    Das new ist auch C++ 🙂



  • anstatt:

    void f( int array[][] ) {
    }
    main() {
      int testvalues[][] = {...};
      f( testvalues );
    }
    

    lieber das hier

    void f( std::vector<std::vector<int>> & arr) {
    }
    int main() {
    	std::vector<std::vector<int>> testvalues;
    	// ...
    	f( testvalues );
    
    	return 0x0;
    }
    


  • nmn schrieb:

    Ich möchte das eigentlich direkt lösen, ohne dafür Vektorklassen, die Boost Library oder ähnliches zu benutzen - ist das möglich?

    Ja, möglich ist das schon, aber gleichzeitig auch völlig unsinnig.


  • Mod

    Wenn die Länge aller Zeilen gleich ist (sie darf ruhig dynamisch sein, bloß einheitlich für alle Zeilen), dann wäre vector<vector> der falsche Typ. Damit zahlst du nämlich (nicht ganz unerhebliche) Laufzeitkosten, um die Länge jeder Zeile unabhängig zu halten. In dem Falle wäre ein vector<array> (Zeilenlänge statisch) oder ein Wrapper um eine eindimensionale Struktur (Zeilenlänge dynamisch, aber einheitlich) wesentlich besser.



  • Hoi, danke für die fixen Antworten.

    Ja, Otze, das ist mit ein paar kleinen Ausnahmen (wie new und Variablendeklarationen innerhalb von for) reines C, allerdings werde ich in C++ weiterarbeiten, weil das eigentliche Programm OO arbeitet. Da ich nicht weiß, ob und wie ich da Casts, Referenzen etc. benutzen muss/kann - und inwiefern sich dies in C von C++ unterscheidet - habe ich die Frage im C++ Forum gestellt.

    std__vector<>, Tachyon Ich weiß, dass ich mich in die Vektorklassen einlesen könnte, allerdings hatte ich gehofft, das auch durch geschickte Zeiger/Speicher/Kopier/whatever Operationen lösen zu können, da dies das einzige Vorkommen einer solchen Aktion ist.

    Kann ich denn so ein verschachteltes vector<vector<int>> mit einer Liste vorbelegen und wie ein gewöhnliches Array auslesen mit arr[i][j]? Hat jemand evtl. einen guten Link dafür?



  • Hier wird das std::vector-Klassentemplate beschrieben. Im Großen und Ganzen benutzt sich ein Vektor genau so wie ein Array. Nur ist vieles einfach einfacher.



  • Dein Beispiel braucht ja gar keine dynamische Feldgröße. Wirst du dynamische Feldgrößen später brauchen?



  • SeppJ schrieb:

    Wenn die Länge aller Zeilen gleich ist (sie darf ruhig dynamisch sein, bloß einheitlich für alle Zeilen), dann wäre vector<vector> der falsche Typ. Damit zahlst du nämlich (nicht ganz unerhebliche) Laufzeitkosten, um die Länge jeder Zeile unabhängig zu halten. In dem Falle wäre ein vector<array> (Zeilenlänge statisch) oder ein Wrapper um eine eindimensionale Struktur (Zeilenlänge dynamisch, aber einheitlich) wesentlich besser.

    Die Idee mit der eindimensionalen Struktur hatte ich auch schon, allerdings bleibt das Problem, dass ich nicht einfach die (festen) Startwerte angeben und loslegen kann, ohne eine Handvoll Code zu schreiben, die das dann nochmal umwandelt. (es sei denn, ich würde die Werte gleich eindimensional schreiben, was aber jetzt nicht unbedingt der Hit für die Lesbarkeit wäre...).

    Es sieht so aus, als wäre dieses anscheinend kleine Ärgernis doch ein etwas größeres Problem als gedacht...

    Tachyon: Danke für den Link, ich werds mal damit probieren.

    Decimad: Ja, im eigentlichen Projekt brauche ich später die Möglichkeit, Matrizen beliebiger Größe zu bearbeiten.



  • nmn schrieb:

    std__vector<>, Tachyon Ich weiß, dass ich mich in die Vektorklassen einlesen könnte, allerdings hatte ich gehofft, das auch durch geschickte Zeiger/Speicher/Kopier/whatever Operationen lösen zu können, da dies das einzige Vorkommen einer solchen Aktion ist.

    Du kannst dir auch eine eigene vector-Klasse schreiben, so schwer ist das nicht.



  • // Schön, kann ich aber nicht an eine Funktion übergeben
      int testarray[size][size] = {{1,2,3},{4,5,6},{7,8,9}};
    

    😕



  • So meinte ich das nicht. Stehen die benötigten Größen zur Compile-Zeit fest?
    Oder anders: Wenn du später beliebige zur Laufzeit bestimmte Größen brauchst, hast du dann ja eh nicht mehr das Problem mit den Initialisierern, also erübrigt sich die Fragestellung. Wenn das hingegen nicht der Fall ist, brauchst du auch keine Felder dynamischer Größe.



  • Decimad will wissen, ob Du die Größe des Arrays oder der Subarrays zur Laufzeit ändern musst. Wenn zum Beispiel die Subarrays immer nur 3 Elemente haben, brauchst Du nicht vector<vector<T>> zu benutzen. Das wäre quasi overkill. In dem Fall würde ein vector<array<T,3>> völlig reichen.


  • Mod

    nmn schrieb:

    Ja, Otze, das ist mit ein paar kleinen Ausnahmen (wie new und Variablendeklarationen innerhalb von for) reines C, allerdings werde ich in C++ weiterarbeiten, weil das eigentliche Programm OO arbeitet.

    Dir ist bekannt, dass man auch in C OO programmieren kann? Jedoch: Wenn C++, dann mach es auch richtig (im Sinne von: Nutze die Sprachmittel voll aus!). So wie du hier mit dem new hantierst, da ist kein Unterschied zu einem (schlecht gemachten) C-Programm, das ist praktisch bloß #define malloc new .

    Das Problem am Nutzen von C++ ist, dass es zuerst unheimlich viel zu lernen gibt, bevor die Sprache anfängt, richtig gut zu sein. Bevor du nicht mit der Standardbibliothek, den Templates und den Feinheiten der Sprache fit bist und die Denkmuster hinter dem Design von C++ verstanden hast, ist C++ bloß ein C-Abklatsch mit anderen Vokabeln. Die meisten Leute benötigen mehrere Monate Lernphase.



  • Tachyon, Decimad: Es handelt sich um Programme für die Universität. Verschiedene Matrixoperationen (z. B. LU Zerlegung) kommen immer wieder in anderem Zusammenhang vor, daher hatte ich vor, mir eine Matrixklasse zu erstellen, die ich dann nur noch #includen und verlinken muss.

    Leider haben die vorgegebenen Matrizen nicht in jeder Aufgabe dieselbe Größe, diese verschiedenen Größen stehen aber beim _jeweiligen_ Compilieren fest.

    SeppJ: Da magst du Recht haben, was den Unterschied von C zu C++ betrifft habe ich noch viel zu lernen; insbesondere die Idee hinter den Templates erschließt sich mir noch nicht wirklich. Und ja, für einen unbekannten Integer ein new zu benutzen ist etwas sinnbefreit, das ist wahr.



  • So etwas müsste man hier mal in die FAQ aufnehmen: Modern C++



  • Das schreit nach templates und fertigen Template-Bibliotheken!



  • Ja, im Prinzip schreit es danach, Decimad; der Prof ist aber der Meinung, wir sollen eigene Lösungen benutzen.
    Ich habe jetzt erst mal über std::vector gelöst; hoffentlich habe ich demnächst Zeit, mich weiter einzulesen.

    Danke erst mal für eure Hilfe!


Anmelden zum Antworten