Kleine String Klasse



  • guck dir deinen operator+ nochmal genauer an. is das wirklich das was du machen willst ?



  • Du darfst doch in operator+() dein Objekt nicht ändern...


  • Mod

    #include <iostream>
    #include <cstring>
    
    using namespace std;
    
    namespace dk
    {
        class String
        {
          private:
    
            char* data;
            int length;                        // ein vorzeichenloser Typ dürfte sinnvoller sein
            int data_size;  
    
          public:
    
            String()                           // die Verwendung der Initialisierungsliste ist zweckmäßig
            {
                length = 0;
                data_size = 0;
                data = 0;
            }
    
            String(char* data,int length = -1) // Überladung sollte in Erwägung gezogen werden, da die Bedeutung der verscheidenen Aufrufe doch recht stark varriert
            {                                  // wiederum: Intialisierungsliste verwenden
    
                 if(length == -1) this->length = strlen(data);
                 else this->length = length;
               this->data = new char[this->length+1];
               strncpy(this->data,data,this->length);     // das ist die falsche Funktion, falls der zu kopierende String eingebette '\0' enthält
               this->data[this->length] = '\0';
               this->data_size = this->length+1;
            }
    
            ~String()
            {
               delete[] this->data;
            }
    
            String(const String& org)
            {
                data = new char[org.data_size];
                strcpy(data,org.data);                    // falsche Funktion, falls '\0' im String
                length = org.length;
                data_size = org.data_size;
            }
    
            void operator=(const char* data)              // Rügabe überdenken
            {
               delete[] this->data;                       // evtl. auch den Fall a = a.c_str() beachten!; nicht exception-sicher, falls
               this->length = strlen(data);
               this->data = new char[length+1];           // hier eine Exception ausgelöst wird, ist der Inhalt von data unbestimmt, der folgende Destruktoraufruf hat folglich UB
               strncpy(this->data,data,length);
               this->data[length] = '\0';
               this->data_size = length+1;
            }
    
            String& operator+(const String& other)        // Rückgabewert überdenken; Funktion sollte const sein
            {
               char* old_data = new char[data_size];
               strcpy(old_data,data);
               delete[] data;                             // wieso nicht gleich old_data = data?
               length += other.length;
               data = new char[length+1];
               strcpy(data,old_data);                     // '\0' im String...
               delete[] old_data;
               strcat(data,other.data);                   // '\0' im String
               data[length] = '\0';
               data_size = length+1;
               return *this;                              
            }                                             // op+= in Betracht ziehen und Implementierung über + (oder umgekehrt, ist aber bei Strings wenig sinnvoll)
    
            void operator=(const String& other)           // Rückgabewert überdenken
            {
               delete[] this->data;                       // Selbstzuweisung beachten !!!
               this->length = other.length;
               this->data = new char[length+1];
               strncpy(this->data,other.data,length);     // '\0' im String
               this->data[length] = '\0';
               this->data_size = length+1;
            }                                             // an copy&swap denken
    
            void assign(const char* data,int length = -1) //the same as operator=() but with length parameter
            {
               delete[] this->data;                       // siehe oben: a.assign(a.c_str()); nicht exception-sicher
    
                 if(length == -1)
                 {
                    this->length = strlen(data);
                 }
                 else this->length = length;
    
               this->data = new char[this->length+1];
               strncpy(this->data,data,this->length);     // '\0' im String
               this->data[this->length] = '\0';
               this->data_size = this->length+1;
            }
    
            const char* c_str() const
            {
                if(data)
                return this->data;
                else return "";
            }
    
            char* g_dat() //if needed, data can be modified
            {
                if(data)
                return this->data;
                else return "ERROR g_dat()!";             // illegal in C++11; ganz schlechte Idee sowieso, weil der Aufrufer keine Möglichkeit hat, zu erkennen, dass ein Fehler aufgetreten ist
                                                          // direkte Rückgabe von data oder eine Exception erscheinen zweckmäßiger
            }
    
            int size()                                    // const
            {
                return this->data_size;
            }
    
            int len()                                    // const
            {
                return this->length;
            }
        };
    }
    


  • Vielen Dank für eure Vorschläge (vor allem an camper).

    Du darfst doch in operator+() dein Objekt nicht ändern...

    Also muss ich eine Kopie erstellen?

    strncpy(this->data,data,this->length); // das ist die falsche Funktion, falls der zu kopierende String eingebette '\0' enthält

    Ah ok, dann muss ich mir diese Funtkion selbst schreiben.

    // illegal in C++11; ganz schlechte Idee sowieso, weil der Aufrufer keine Möglichkeit hat, zu erkennen, dass ein Fehler aufgetreten ist
    // direkte Rückgabe von data oder eine Exception erscheinen zweckmäßiger

    Ich habe versucht data direkt zurückzugeben, aber dann tritt ein Fehler auf.



  • string master schrieb:

    Ich habe versucht data direkt zurückzugeben, aber dann tritt ein Fehler auf.

    Was denn für ein Fehler?


  • Mod

    String operator+(const String& other) const
            {
               String result(c_str(), size()+other.size());
               memcpy(result.g_dat()+size(), other.c_str(), other.size());
               return result;
            }
    

    setzt allerdings den Konstruktor in seiner gegenwärtig defekten Form voraus 😉



  • Ich hab jetzt das nochmal überarbeitet (außer strcpy mit 0Byte). Habt ihr noch Verbesserungsvorschläge? (Bis Mittwoch muss ich fertig sein).

    #include <iostream>
    #include <cstring>
    #include <string>
    #include <sstream>
    #include <bitset>
    #include <algorithm>
    
    using namespace std;
    
    namespace dk
    {
    
        class String
        {
          private:
    
            char* data;
            unsigned int length;
            unsigned int data_size; //length + 1
    
          public:
    
          friend ostream& operator<<(ostream &os,const String &str);
          friend istream& operator>>(istream &is,String &str);
    
            String() : length(0),data_size(0)
            {
                data = 0;
            }
    
            String(const char* data,int length = -1) //if length == -1 ,strlen() will find out.
            {                                   //length parameter is used for strings where 0 bytes aren`t only at the end
    
                 if(length == -1) this->length = strlen(data);
                 else this->length = length;
               this->data = new char[this->length+1];
               strncpy(this->data,data,this->length);
               this->data[this->length] = '\0';
               this->data_size = this->length+1;
            }
    
            String(string data)
            {
               this->length = data.size();
               this->data = new char[this->length+1];
               strncpy(this->data,data.c_str(),this->length);
               this->data[this->length] = '\0';
               this->data_size = this->length+1;
            }
    
            String(const int freq,const char letter) : length(freq)
            {
                data = new char[freq+1];
                memset(data,letter,freq);
                data_size = length+1;
                data[length] = '\0';
            }
    
            ~String()
            {
               delete[] this->data;
            }
    
            String(const String& org)
            {
                data = new char[org.data_size];
                strcpy(data,org.data);
                length = org.length;
                data_size = org.data_size;
            }
    
            const String& operator=(const char* data)
            {
               delete[] this->data;
               this->length = strlen(data);
               this->data = new char[length+1];
               strncpy(this->data,data,length);
               this->data[length] = '\0';
               this->data_size = length+1;
               return *this;
            }
    
            const String& operator=(const String& other)
            {
               delete[] this->data;
               this->length = other.length;
               this->data = new char[length+1];
               strncpy(this->data,other.data,length);
               this->data[length] = '\0';
               this->data_size = length+1;
               return *this;
            }
    
            const String operator+(const String& other)
            {
               String ret("",length+other.length);
               strcpy(ret.data,data);
               strcat(ret.data,other.data);
               ret.data[ret.length] = '\0';
               return ret;
            }
    
            const String operator+(const char* other)
            {
               String ret("",length+strlen(other));
               strcpy(ret.data,data);
               strcat(ret.data,other);
               ret.data[ret.length] = '\0';
               return ret;
            }
    
            const String& operator+=(const String& other)
            {
               *this = operator+(other);
               return *this;
            }
    
            const String& operator+=(const char* other)
            {
               *this = operator+(other);
               return *this;
            }
    
            void assign(const char* data,int length = -1) //the same as operator=() but with length parameter
            {
               delete[] this->data;
    
                 if(length == -1)
                 {
                    this->length = strlen(data);
                 }
                 else this->length = length;
    
               this->data = new char[this->length+1];
               strncpy(this->data,data,this->length);
               this->data[this->length] = '\0';
               this->data_size = this->length+1;
            }
    
            void crypt(const char* key)
            {
                unsigned int keylen = strlen(key);
                unsigned int k = 0;
                string reverser;
    
                for(unsigned int i=0;i<length;i++)
                {
                    if(k == keylen) k = 0;
                    data[i] = data[i] ^ key[k];
                    data[i] += key[k];
                    k++;
                }
    
                for(unsigned int i=0;i<length-2;i++)
                {
                    char swap;
                    swap = data[i];
                    data[i] = data[i+2];
                    data[i+2] = swap;
                }
    
                reverser = data;
                reverse(reverser.begin(),reverser.end());
                strcpy(data,reverser.c_str());
            }
    
            void decrypt(const char* key)
            {
                unsigned int keylen = strlen(key);
                unsigned int k = 0;
    
                string reverser = data;
                reverse(reverser.begin(),reverser.end());
                strcpy(data,reverser.c_str());
    
                for(unsigned int i=length-1;i>1;i--)
                {
                    char swap;
                    swap = data[i];
                    data[i] = data[i-2];
                    data[i-2] = swap;
                }
    
                for(unsigned int i=0;i<length;i++)
                {
                    if(k == keylen) k = 0;
                    data[i] -= key[k];
                    data[i] = data[i] ^ key[k];
                    k++;
                }
            }
    
            void reserve(unsigned int len)
            {
                length = len;
                data_size = len+1;
                delete[] data;
                data = new char[data_size];
                memset(data,0,data_size);
            }
    
            int find(const char letter)
            {
                for(unsigned int i=0;i<length;i++)
                {
                    if(data[i] == letter) return i;
                }
    
                return -1;
            }
    
            int find(const char* text)
            {
                char* pointer = strstr(data,text);
                if(pointer == 0) return -1;
    
                return pointer - data;
            }
    
            const char* c_str() const
            {
                if(data)
                return this->data;
                else return "";
            }
    
            char* g_dat() //if needed, data can be modified
            {
                if(data)
                return this->data;
               // else return ""; //EXECPTION HIER EINFÜGEN
            }
    
            int size()
            {
                return this->data_size;
            }
    
            int len()
            {
                return this->length;
            }
    
            template <typename T>
            T convert(__int8 base = -1)
            {
                T output;
                stringstream wan;
    
                  if(base == 16)
                    wan << hex << data;
                  else if (base == 8)
                    wan << oct << data;
                  else wan << data;
    
                wan >> output;
                return output;
            }
        };
    
        template <class T,class Z>
        const Z convert(T in)
        {
            Z output;
            stringstream wan;
            wan << in;
            wan >> output;
            return output;
        }
    
        ostream& operator<<(ostream &os,const String &str)
        {
          os << str.data;
          return os;
        }
    
        istream& operator>>(istream &is,String &str)
        {
          string buffer;
          is >> buffer;
          str = buffer.c_str();
          return is;
        }
    }
    


  • Musst du einen char* verwenden? Da es eine Informatik-Übung ist, vermutlich schon...



  • String() : length(0),data_size(0)
            {
                data = 0; // Initialisierungsliste...
            }
    
    String& operator=(......)
    {
       return *this;
    }
    

    Ansonsten sehe ich Codezeilen die öfters vorkommen. Die könntest du noch in eine Funktion auslagern, sodass du schlußendlich keine redundanten Codezeilen mehr hast.



  • Ok danke, ich werd euch dann sagen, welche Note ich bekommen habe ...



  • Nochmal zusammenfassend und ergänzend:

    • Schau Dir nochmal Copy&swap für operator=() an
    • Dazu: Was ist momentan mit Selbstzuweisung? ( String s = "bla"; s = s; )
    • Was passiert, wenn Du einen default-konstruierten String ausgibst?
    • operator+() sollte freie Funktion sein
    • ist diese doppelte Buchführung ( length u. length+1 (aka. data_size )) notwendig?
    • Benutz duchgehend initialisierungslisten in den Konstruktoren (geht auch mit new[])
    • zuviel const bei den Rückgabewerten
    • zuwenig const in den Signaturen ( size(), find()... )
    • wenn Du eh binäre strings speichern willst, sind die str*-Funktionen aus C die falsche Wahl
    • DRY!
    • Nimm Überladung, bevor Du solche Krücken wie if (length == -1)... benutzt
    • die Ein-/Ausgabeoperatoren müssen keine friends sein

Anmelden zum Antworten