Problem mit <map> bzw. String-Gleichheit
-
Servus,
habe ein seltsames Problem mit den Keys für eine <map>.
Und zwar habe ich eine std::map<char*, char*> definiert, mit welcher ich das folgende mache:std::map<char*, char*> theMap; char* testString = "theTest"; char* trimString = trim(" \t theTest \n"); theMap["theTest"] = "hier ist ein wert drin"; printf("%s\n", theMap["theTest"]); printf("%s\n", theMap[testString]); printf("%s\n", theMap[trimString]);Die trim()-Funktion habe ich selbst geschrieben, da ich bisher leider nichts vergleichbares in der Standardlib finden konnte. Sie sieht folgendermaßen aus:
char* trim(const char* str) { int len = strlen(str); int start = 0; int end = len; for(int i=0; i<len; i++) if (str[i] > 0x20) { start = i; break; } for(int i=len; i>0; i--) if (str[i] > 0x20) { end = i+1; break; } len = end - start; char* result = new char[len]; strncpy(result, str + start, len); return result; }So, nun zum Problem: Ich füge also einen Wert unter einem bestimmten Key ("theTest") in die Map ein, und versuche nun, diesen auf drei unterschiedliche Arten wieder auszulesen. Bei der ersten, also einem literalen String, funktioniert es, bei der zweiten, über ein char*, funktioniert es ebenfalls.
Bei der dritten jedoch nicht.Jetzt ist die erste Überlegung natürlich, daß es an der eigenen trim()-Funktion liegt. Daher habe ich nun einfach mal versucht, den zurückgegebenen String mit dem anderen zu vergleichen, aber der Vergleich bestätigt mir eigentlich, daß die trim()-Funktion wie erwartet funktioniert:
printf("%i\n", strcmp("theTest", "theTest")); // nur um rauszufinden, daß bei Gleichheit eine 0 rauskommen muß printf("%i\n", strcmp("theTest", trimString)); printf("%i\n", strcmp(testString, trimString));Eigentlich müßte doch dann auch der Map-Zugriff ohne Probleme funktionieren, aber das ist eben nicht der Fall. Woran kann das liegen?
Ich hoffe ihr könnt mir helfen!
-
Eigentlich ganz einfach: Die Map macht keinen strcmp-Vergleich, sondern einen ==-Vergleich (woher soll sie auch wissen dass Du nicht den ==-Vergleich wünschst). Damit macht sie nur Zeiger-Vergleiche und keine String-Vergleiche. Und zwei Zeiger auf den gleichen String(-Inhalt) müssen nicht zwangsläufig auf die gleiche Adresse zeigen.
Lösung: Nimm std::string.
-
Hmmm okay, das klingt natürlich einleuchtend. Aber warum geht dann das hier?
printf("%s\n", theMap["theTest"]); printf("%s\n", theMap[testString]);Könnte das an einer Compiler-Optimierung liegen?
-
Warum sollte das nicht gehen, wenn du mit genau diesen Zeigern etwas in die Map reingesteckt hast?
-
Nein mir ging's jetzt darum, weil es ja einmal direkt ein Literal ist und einmal ein char*, habe nun aber die EXE angeschaut, dort ist der String tatsächlich nur einmal vorhanden, in dem Fall hat das der Compiler wohl bemerkt und entsprechend beidesmal die gleiche Adresse verwendet.
Hmmm die std::strings sollen aber teilweise ihre Problemchen haben, hab ich zumindest gehört... oder was meint ihr dazu?
-
std::map<std::string, std::string> theMap; std::string sTest = "theTest"; std::string sTrim(" \t theTest \n"); std::string sTrimTest(trim(sTrim.c_str())); theMap[sTest] = "hier ist ein wert drin"; std::cout << sTest << " => " << theMap[sTest] << std::endl; std::cout << sTrim << " => " << theMap[sTrimTest] << std::endl;
-
Rock Lobster schrieb:
Hmmm die std::strings sollen aber teilweise ihre Problemchen haben, hab ich zumindest gehört...
So, hast Du gehört? Ich nicht

Wo hast Du das denn gehört und von welchen Problemchen war die Rede?
-
Kann ich auch nicht so recht sagen, ich hatte bisher nur immer irgendwie im Hinterkopf "std::string ist scheiße, char* ist okay". Zwar war mir schon bekannt, daß std::strings einige nette Funktionen bieten, aber irgendwie meine ich gehört zu haben, daß es da oft Schwierigkeiten gibt, wenn man die verwendet. Habe da aber nichts konkretes dazu, und bin ehrlich gesagt auch ganz froh, wenn ich höre, daß sie tatsächlich zu gebrauchen sind und auch verwendet werden sollten

@ (D)Evil: Jepp, funktioniert
werde das jetzt wohl so nutzen.Vielen Dank!
-
Wenn du nicht mehr weißt, woher du diese Aussage hast, solltest du sie ganz schnell vergessen
std::string ist im Regelfall einfacher zu handhaben und auch mächtiger als char*. Du mußt nur aufpassen, daß du keinen Mist damit baust (Bereichsüberschreitungen oder ähnliche Spielereien).Rock Lobster schrieb:
Hmmm okay, das klingt natürlich einleuchtend. Aber warum geht dann das hier?
printf("%s\n", theMap["theTest"]); printf("%s\n", theMap[testString]);testString ist ein Zeiger auf ein String-Literal. Und wenn der Compiler feststellt, daß ein identisches Literal schon besteht, muß er es nur einmal anlegen. Anders würde es aussehen, wenn du
char testString[]="theTest";geschrieben hättest.PS: Auf string-Ebene wäre die trim-Funktion um einiges kürzer:
string trim(const string& src) { size_t start=src.find_first_not_of(" \n\t"); size_t ende =src.find_last_not_of(" \n\t"); return src.substr(start,ende-start+1); }(achtung - nicht getestet)
-
Jo stimmt, das sieht schön kompakt aus

Okay dann werde ich in Zukunft wohl std::string benutzen. Gibt es dennoch irgendwelche Anwendungsfälle, wo man lieber zu char* greifen sollte?
-
Das einzige, was mir da einfällt, sind C-Bibliotheken. Und da kannst du den char*-Einsatz normalerweise lokal kapseln.