[erledigt] Problem mit Rückgabe



  • Hallo,

    ich programmiere noch nicht lange und habe ein Problem, bei dem ich nicht weiter komme.

    Die Funktion sinkingSort aus der Klasse Sortable soll einen Zeiger auf das neu sortierte Array zurück geben.

    class Sortable
    {
      private:
        const char *schluessel;
    
      public:
        Sortable( const char **schluesselName ) {
          schluessel = *schluesselName;
        }
    
        Sortable* sinkingSort( Sortable **tb, int anzahl )
        { 
          int i, j;
          const char *temp;
    
          for ( i = (anzahl - 1); i > 0; i-- )
          {
    	for ( j = 1; j <= i; j++ )
    	{
    	  if ( ( strlen(tb[j-1]->schluessel) ) > ( strlen(tb[j]->schluessel) ) )
    	  {
    	    temp = tb[j-1]->schluessel;
    	    tb[j-1]->schluessel = tb[j]->schluessel;
    	    tb[j]->schluessel = temp;
    	  }
    	}
          }
          return *tb;
        }
    
        const char *getSchluessel() { 
          return schluessel; 
        }
    };
    

    In main bekomme ich mit folgendem Code die Adresse von tb[0] ausgegeben.

    Sortable *liste;
      liste = telefonbuch[4]->sinkingSort( (Sortable**)telefonbuch, telefonbuch[4]->getAnzahl() );
      cout << liste << endl;
    

    Wie kann ich auf die einzelnen Werte des Arrays in main zugreifen?

    Ich sitze wahrscheinlich schon zu lange vor dem Programm und sehe den Wald vor lauter Bäumen nicht mehr. Deshalb bin ich für jeden Schubs in die richtige Richtung dankbar.



    1. warum nutzt du hier ein 2D Array (Pointer auf Pointer). Du greifst doch nur "eindimensional" auf das Array zu. Nimm lieber einen Vector.

    2. Anstatt char * solltest du lieber einen std::string nehmen.



  • schreib mal return tb;
    dann müssts gehen, durch * gibts du ja die adresse des zeigers aus.



  • std::sort( std::vector<std::string>::begin(), std::vector<std::string>.end(), Funktor )
    

    Genau. Lern nicht programmieren, lern die STL zu benutzen... Mehr brauchst du nicht, um in diesem Forum respektiert zu werden 😉



  • It0101 schrieb:

    Mehr brauchst du nicht, um in diesem Forum respektiert zu werden 😉

    Ein völlig nutzloser Beitrag.
    Er will anscheinen lernen, wie man sortiert und da wird ihm (abgesehen von dir) niemand vorschlagen die Standardfunktionalitäten zu benutzen. Wenn es aber nicht darum geht eine Sortierfunktion zu benutzen, dann wird darauf hingewiesen, dass es bereits gute Lösungen gibt.

    Der Unterschied von dem, was viele hier empfehlen ist, dass es auf die Intention des Programmes ankommt, ob die STL empfohlen wird oder nicht. Für den Lerneffekt sicher nicht, aber wenn jemand mit einem Problemcode kommt, der einfach Haufenweise eigengebastel hat (was potentiell problematisch ist), dann wird auf die Standardmittel verwiesen, weil es eine gute Sache ist Code wieder zu verwenden.

    Ein kleiner, aber feiner Unterschied.



  • STL usw. muss ich leider hinten an stellen. Wie geschrieben, bin ich noch nicht lange dabei (knapp 2 Wochen) und beschäftige mich erst mit den Grundlagen.

    It0101 schrieb:

    Genau. Lern nicht programmieren, lern die STL zu benutzen... Mehr brauchst du nicht, um in diesem Forum respektiert zu werden 😉

    Ich dachte immer, dass es vollkommen ausreicht etwas PowerPoint zu können, um die Welt zu beherrschen. 🤡

    (return *tb) habe ich in (return tb) geändert. Da tb vom Typ "Zeiger auf Zeiger" ist, musste ich natürlich auch die Signatur der Funktion "sinkingSort" ändern.
    Ich bin mir nicht sicher, aber ist das nicht gehüpft wie gesprungen?

    Hier der vollständige Code. (Ich weiß, dass man so etwas langes nicht posten sollte, aber ich bin echt am verzweifeln.)

    #include <iostream>
    #include <iomanip>
    #include <cstdlib>
    #include <string.h>
    using namespace std;
    
    class Sortable
    {
      private:
        const char *schluessel;
    
      public:
        Sortable( const char **schluesselName ) {
          schluessel = *schluesselName;
        }
    
        Sortable** sinkingSort( Sortable **tb, int anzahl )
        { 
          int i, j;
          const char *temp;
    
          for ( i = (anzahl - 1); i > 0; i-- )
          {
    	for ( j = 1; j <= i; j++ )
    	{
    	  if ( ( strlen(tb[j-1]->schluessel) ) > ( strlen(tb[j]->schluessel) ) )
    	  {
    	    temp = tb[j-1]->schluessel;
    	    tb[j-1]->schluessel = tb[j]->schluessel;
    	    tb[j]->schluessel = temp;
    	  }
    	}
          }
          return tb;
        }
    
        const char *getSchluessel() { 
          return schluessel; 
        }
    };
    
    class Telefonbuch : public Sortable
    {
      private:
        char nachname[20];
        char vorname[20];
        char nummer[20];
        static int anzahl;
    
      public:
        Telefonbuch( const char *kNachname, const char *kVorname, const char *kNummer ) : Sortable( &kNachname )
        { 
          anzahl ++;
    
          strcpy( nachname, kNachname );
          strcpy(vorname, kVorname );
          strcpy(nummer, kNummer );
        }
    
        int getAnzahl() { 
          return anzahl; 
        }
    
        char* getNachname() { 
          return nachname; 
        }
    
        char* getVorname() { 
          return vorname; 
        }
    
        char* getNummer() { 
          return nummer; 
        }
    };
    
    int Telefonbuch::anzahl = 0;
    
    int main()
    { 
      system ("clear");
    
      Telefonbuch *telefonbuch[5];
      telefonbuch[0] = new Telefonbuch( "AAAAA", "AAAAA", "11111111" );
      telefonbuch[1] = new Telefonbuch( "CCCC", "DDDD", "22222222" );
      telefonbuch[2] = new Telefonbuch( "EEE", "FFF", "33333333" );
      telefonbuch[3] = new Telefonbuch( "GG", "HH", "44444444" );
      telefonbuch[4] = new Telefonbuch( "I", "J", "55555555" );
    
      cout << "\nVor der Sortierung" << endl;
      cout << "------------------" << endl;
      cout << left << setw(20) << "Nachname:" << setw(20) << "Vorname:" << setw(20) << "Telefonnummer:" << endl;
      cout << left << setw(20) << "---------" << setw(20) << "--------" << setw(20) << "--------------" << endl;
    
      for ( int i = 0; i < 5; i++ )
      {
        cout << left << setw(20) << telefonbuch[i]->getNachname() << setw(20) << telefonbuch[i]->getVorname() << setw(20) << telefonbuch[i]->getNummer() << endl;
      }
    
      // Soll die sortierten Nachnamen ausgeben
      cout << "\n\nSortierte Liste" << endl;
      cout << "---------------" << endl;
    
      Sortable **liste;
      liste = telefonbuch[4]->sinkingSort( (Sortable**)telefonbuch, telefonbuch[4]->getAnzahl() );
      cout << liste << endl;
    
      cout << endl;
      return 0;
    }
    

    In main möchte ich am Ende die sortierten Nachnamen ausgeben.
    Mit

    cout << liste << endl;
    

    bekommen ich zwar die Adresse ausgegeben, aber ich weiß nicht, wie ich auf die einzelnen Nachnamen zugreifen kann.
    Genau dazu brauche ich eine Lösung.

    Sicher kann ich in "sinkingSort"

    return schluessel;
    

    machen und mit geänderter Signatur mit

    telefonbuch[i]->schluessel((Sortable**)telefonbuch, telefonbuch[4]->getAnzahl() );
    

    darauf zugreifen.
    Aber es muss doch auch anders gehen. Ich bekomme ja schließlich schon die richtige Adresse.



  • It0101 schrieb:

    Lern nicht programmieren, lern die STL zu benutzen... Mehr brauchst du nicht, um in diesem Forum respektiert zu werden 😉

    Was nen Rat 🙄



  • Du kommst von Java, nicht wahr? 🙂

    bekommen ich zwar die Adresse ausgegeben, aber ich weiß nicht, wie ich auf die einzelnen Nachnamen zugreifen kann.
    Genau dazu brauche ich eine Lösung.

    Du kannst einfach da Array nehmen und auf die Instanzen zugreifen und dann z.B eine Member aufrufen. Das ganze packst du dann in eine Schleife und gut-ist.

    for (int i = 0; i < 5; ++i)
    {
      std::cout << telefonbuch[i]->getNachname () << "\n";
    }
    

    Allerdings hast du sehr viele logische und Programmiertechnische Probleme mit deinem Code.

    Die Technik, die du da mit Sortable machst ist nicht der übliche Weg in C++. Üblicherweise implementierst du einfach eine Template Funktion, welche das sortieren übernimmt und verlangst eine gewisse Schnittstelle der Klasse, welche die einfach anbieten muss, ansonsten kompiliert dein Code nicht. Also z.B hast du dann sowas:

    template<class T>
    void sinking_sort ( T* start, T* end ) // üblicherweise iteratoren
    {
      // sortiere die range start bis end 
    }
    

    Und dann kannst du da einen (fast) beliebige Objekte drin sortieren. Du brauchst aber wahrscheinlich so etwas, wie den <-Operator, um überhaupt einen Vergleich von 2 Objekten machen zu können.
    Und wie du siehst ist das üblicherweise auch eine freie Funktion. Gehört ja nicht zu einer speziellen Instanz dazu, also ist sie frei.

    Dann das hier:

    Telefonbuch *telefonbuch[5];
      telefonbuch[0] = new Telefonbuch( "AAAAA", "AAAAA", "11111111" );
      telefonbuch[1] = new Telefonbuch( "CCCC", "DDDD", "22222222" );
      telefonbuch[2] = new Telefonbuch( "EEE", "FFF", "33333333" );
      telefonbuch[3] = new Telefonbuch( "GG", "HH", "44444444" );
      telefonbuch[4] = new Telefonbuch( "I", "J", "55555555" );
    

    Aua. Du gibst den Speicher nie wieder frei. (dazu gibt es delete). Im übrigen kannst du die Objekte ja ganz normal drin speichern, dann hast du das Problem auch nicht.
    Also:

    Telefonbuch telefonbuch[5];
      telefonbuch[0] = Telefonbuch( "AAAAA", "AAAAA", "11111111" );
      telefonbuch[1] = Telefonbuch( "CCCC", "DDDD", "22222222" );
      telefonbuch[2] = Telefonbuch( "EEE", "FFF", "33333333" );
      telefonbuch[3] = Telefonbuch( "GG", "HH", "44444444" );
      telefonbuch[4] = Telefonbuch( "I", "J", "55555555" );
    

    Und danach noch ggf. '->' durch '.' austauschen.

    Dann das hier:

    class Telefonbuch : public Sortable
    {
      private:
        char nachname[20];
        char vorname[20];
        char nummer[20];
    

    C-Strings gehören nicht in modernen C++ Code! - Es gibt eine nette Klasse, die sich std::string nennt. Und die Benutzung ist einfacher, und die Sicherheit höher:

    #include <string> // merke: ohne h, dann hast du die C++ Variante!
    //...
    class Telefonbuch : public Sortable
    {
      private:
        std::string nachname_;
        std::string vorname_;
        std::string nummer_;
    

    Dann kannst du auch den Konstruktor schöner schreiben und die Initialisierungsliste benutzen:

    Telefonbuch( std::string nachname, std::string vorname, std::string nummer ) : Sortable( &kNachname ),
    nachname_ ( nachname ),
    vorname_ ( vorname ),
    nummer_ ( nummer )
        {
          anzahl ++;
        }
    

    Das mit der statischen Anzahl ist sehr, sehr schlecht. Du vermisch da den Container von Elementen mit den Elementen, die du speichern willst. Dazu kommt noch, dass wenn du vielleicht 2 Listen mit solchen Elementen haben willst. Dann hast du unweigerlich ein Problem.

    Ich weiss jetzt nicht genau, was du im Moment machen willst, aber du erfindest hier verschiedene Räder neu. Du probierst eine Art Container nachzuempfinden und deine eigene Sortierfunktion (die nicht sehr effizient aussieht) zu implementieren. Der übliche Weg wäre hier wahrscheinlich schon, dass du einfach eine Klasse Telefonbuch (oder wohl eher Telefonbuch_Eintrag ) hast, welche dann den <-Operator so implementiert, wie du ihn haben möchtest. Und dann kannst du ein Array, eine std::list oder was auch immer an die Funktion std::sort übergeben, welche dann den Rest für dich korrekt und schnell macht.



  • @drakon:
    Vielen vielen Dank für die ausführlichen Tipps.
    Ich habe es jetzt so gemacht, dass ich mir die sortierte Liste mit

    telefonbuch[i]->getSchluessel();
    

    in einer Schleife ausgeben lasse und es funktioniert.

    Das Programm habe ich jetzt in den Ordner "Bitte in 10 Jahren, mit einem Glas Wein in der Hand, schmuntzelnt öffnen" abgespeichert. 🙂
    Ich bin mir sicher, dass da noch sehr viele Programme dazu kommen werden.

    Nach viel Lesen und ausprobieren bin ich mir sicher, dass es eine ziemlich schlechte Idee ist, tb aus der Sortierfunktion zurück zu geben und in main, mit Hilfe des indischen Seiltricks, direkt darauf zuzugreifen (jedenfalls in diesem Kontext).
    Deshalb werde ich mich morgen, mit deinen Tipps im Hinterkopf, dran setzen und das Programm neu schreiben.



  • neulich schrieb:

    Deshalb werde ich mich morgen, mit deinen Tipps im Hinterkopf, dran setzen und das Programm neu schreiben.

    Sehr gute Idee. 👍


Anmelden zum Antworten