Kleine String Klasse
-
Hallo ich muss für Informatik eine kleine Stringklasse schreiben, komme aber nicht weiter :
String test("123");
String test2("45");test = test + test2;
Jetzt sollte eigentlich in test "12345" und in test2 "45" stehen. Aber es steht in beiden "12345".
Hier der Code:
#include <iostream> #include <cstring> using namespace std; namespace dk { class String { private: char* data; int length; int data_size; //length + 1 public: String() { length = 0; data_size = 0; data = 0; } String(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() { 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; } void 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; } String& operator+(const String& other) { char* old_data = new char[data_size]; strcpy(old_data,data); delete[] data; length += other.length; data = new char[length+1]; strcpy(data,old_data); delete[] old_data; strcat(data,other.data); data[length] = '\0'; data_size = length+1; return *this; } void 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; } 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; } 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()!"; } int size() { return this->data_size; } int len() { return this->length; } }; } using namespace dk; int main() { String test("123"); String test2("m"); String test3; test2 = test + test2; test3 = "blabla"; cout << test2.c_str() << endl << test3.c_str() << endl; cout << test.size() << endl << test.c_str() << endl << test2.size() << endl << test2.c_str() << endl; return 0; }
-
Ach ja und das mit dem length Parameter ist,weil wir da später mal binärdaten speichern wollen,die nicht nur am Ende ein 0Byte haben und strlen() würde nur bis zum 0Byte zählen.
-
guck dir deinen operator+ nochmal genauer an. is das wirklich das was du machen willst ?
-
Du darfst doch in
operator+()dein Objekt nicht ändern...
-
#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äßigerIch 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?
-
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 (
lengthu.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
- Schau Dir nochmal Copy&swap für