Mehrdimensionales (2) Array von Strings als Rückgabewert einer Methode



  • Hallo,
    ich hab ein Array von Strings, welches 100 Elemente enthält und diese 100 jeweils noch 3.
    Nun möchte ich dieses Array von einer Methode zurückgeben lassen. Bei Arrays muss man im Allgemeinen ja String* Klasse::metode(); schreiben. Nur wie funktioniert das bei zwei dimensionen?
    In meiner *.h Datei steht unter protected folgendes:

    String ApplicationList[100][3];
    

    und die Methode sieht wie folgt aus:

    String* Application_Registry::getAllApplications()
    	{
    		return this->ApplicationList;
    	}
    

    Der Fehler heißt:
    [quote]Konvertierung von 'UnicodeString(*)[3]' nach 'UnicodeString *' nicht möglich



  • String[][3] // entspricht String(*)[3] - s.a. Fehlermeldung
    

    Wäre es nicht aber besser du verwendest einen std::vector oder ein anderes dynamisches Array?

    Ich kenne dein Programm zwar nicht, aber der Zugriff (wenn auch protected) auf interne Daten sollte nicht direkt möglich sein. Wenn es nur eine Lese-Methode sein soll, dann mach sie doppelt 'const', d.h.

    const String[][3] Application_Registry::getAllApplications() const
    

    Und wenn von außen doch schreibend auf das Array zugegriffen werden soll, dann entwerfe dafür eine Set-Methode, z.B.

    bool Application_Registry::SetApplication(int x, int y, String sApplication);
    // Rückgabewert für Index-Check
    


  • Also wenn ich

    const String[][3] Application_Registry::getAllApplications() const
    

    Nutze und auch in der h datei das schreibe (natürlich ohne Application_Registry::) dann bekomme ich die Meldung
    "Deklaration nicht ordnungsgemäß abgeschlossen"

    Btw das mit dem std::vector hab ich schonmal gelesen, aber nirgends etwas wirklich gefunden wie man das nutzt...



  • Sorry, habe Mist geschrieben gehabt (da man Arrays nicht zurückgeben kann, sondern nur Zeiger, arghhh).

    Also richtig wäre:

    const String* Application_Registry::getAllApplications() const
    {
        return &ApplicationList[0][0]; // beachte: explizite Angabe der Adresse
    }
    

    Dies hat jedoch den großen Nachteil, daß der Aufrufer nur noch einen Zeiger zur Verfügung gestellt bekommt, d.h. die Information über die Größe und Dimensionalität des Arrays geht dabei verloren.

    Und zu std::vector siehe http://www.c-plusplus.net/forum/viewtopic-var-p-is-1787663-and-sid-is-9503e309ddc1a6a39b9cdd93149312aa.html#1787663 (hatte gerade da gepostet).

    Einen allg. Überblick über die Container in der STL (u.a. auch std::vector) findest du im Artikel: http://www.c-plusplus.net/forum/viewtopic-var-t-is-143816.html

    Ein mehrdim. Array kannst du dann so erstellen:

    std::vector< std::vector<String> > sApps(100, std::vector<String>(3));
    

    Als Klassenmember mußt du dann jedoch die Deklaration und Definition voneinander trennen:

    // in Klassen-Header
    class Test
    {
    public:
        Test();
    
    private:
        std::vector< std::vector<String> > sApps;
    };
    
    // in Source-Datei
    Test::Test()
       : sApps(100, std::vector<String>(3)) // Initialisierungsliste
    {
    }
    

    Zugriff dann wie gewohnt über

    String s = sApps[99][2]; // letzter Eintrag
    

    So hoffe, jetzt keinen Murks geschrieben zu haben -)



  • Aber ich muss dem Vector nicht sagen wie groß er zu sein hat, oder? Das müsste ja dann auch dynamisch gehen.
    Das wäre mir sowieso lieber 🙂



  • Ich mach das immer so, dass ich die Anzahl als Referenzparameter zurückgebe.
    Also z.B. so:

    [code]
    String* GetAnzahlString(int &Anzahl);
    [/code]
    

    Das kann man dann so aufrufen:

    [code]
    int count;
    String* strArray = GetAnzahlString(count);
    
    if (count >0).....
    [/code]
    

    😉



  • kanedo schrieb:

    Aber ich muss dem Vector nicht sagen wie groß er zu sein hat, oder? Das müsste ja dann auch dynamisch gehen.
    Das wäre mir sowieso lieber 🙂

    Jein. Bei einem Vektor aus Vektoren bist du für die Grösse der Einträge verantwortlich. Nehmen wir folgendes Beispiel:

    #include <vector>
    #include <System.hpp>
    
    typedef std::vector<AnsiString> StringVector1D;
    typedef std::vector<StringVector1D> StringVector2D;
    
    int main()
    {
       // erzeuge einen Vektor mit 100 Einträgen, die alle ein StringVector
       // mit 3 AnsiStrings sind, die alle "Hallo" sind.
       StringVector2D My2DVector( 100, StringVector1D( 3, "Hallo" ) );
    
       // Vektor auf 200 Einträge vergrössern
       // Das Problem ist nun, dass die Elemente 0-99 ein Vektor mit 3 AnsiStrings
       // sind, während die neuen Einträge 100-199 alle leere Stringvektoren sind
       My2DVector.resize( 200 );
    
       // Lösung: Beim Vergrössern ein Referenzelement angeben, mit dem die neuen 
       // Einträge initialisiert werden:
       My2DVector.resize( 300, StringVector1D( 3, "Hallo" ) );
    }
    

    Das Problem bei Vektoren aus Vektoren ist, dass alle "inneren" Vektoren individuelle Längen haben (wie jagged Arrays in C#). Bei einem resize() musst du sicherstellen, dass alle Vektoren auf die richtige Länge gebracht werden, z.B. mit folgender Funktion:

    template<typename T>
    void resize( std::vector<std::vector<T> >& v, unsigned int Rows, unsigned int Cols )
    {
       // Anzahl der Zeilen setzen
       v.resize( Rows );
    
       // für jede Zeile die Anzahl der Spalten setzen
       for( std::vector<std::vector<T> >::iterator it = v.begin(); it != v.end(); ++it )
       {
          it->resize( Cols );
       }
    }
    

Log in to reply