Strings - Zeichenketten

Martin Kompf

Für den C-Programmierer ist die Beschäftigung mit Zeichenketten eine nervende und zeitraubende Tätigkeit. Für den Nutzer der STL unter C++ wird dagegen alles gut...

Zeichenketten werden in Standard-C auf den Datentyp char* abgebildet. Es stehen dann zwar auch Funktionen für Verkettung, Vergleich, Kopie usw. zur Verfügung, jedoch muß sich der Entwickler um das Speichermanagement und Tests gegen Bereichsüberschreitungen selbst kümmern. Dies ist zeitraubend und fehleranfällig. Gerade "vergessene" Tests gegen Überschreiben des reservierten Speicherbereichs für Zeichenketten haben immer wieder zu Sicherheitslücken besonders in Netzwerkprogrammen geführt.

Der C++-Programmierer hat mit dem Datentyp string aus der Standard-Template-Library (STL) nun die Möglichkeit, alle diese Probleme zu umschiffen. Insbesondere übernimmt die string-Klasse das Reservieren des notwendigen Speichers, seine gegebenenfalls notwendige Erweiterung und bewahrt vor Speicherlecks und -überschreibern.

In der folgenden Liste sind die wichtigsten Operationen, die mit string Objekten ausgeführt werden können, zusammengefaßt. Zur Benutzung muß lediglich per

#include <string>

das entsprechende STL-Headerfile eingebunden werden. Dieses definiert string im Namespace std, so daß für die korrekte Ansprache std::string verwendet werden muß. Oder aber es erfolgt ein Import des kompletten Namespaces mittels

using namespace std;
  1. Konstruktion
    string s;            // erzeugt einen leeren String
    string s("abcdef");  // erzeugt String aus char*
    string s(80, ' ');   // erzeugt String aus 80 Leerzeichen
    
  2. Zuweisung
    string s, s1;
    s = 'a';             // Zuweisung eines char
    s = "abcd";          // Zuweisung eines char*
    s = s1;              // Zuweisung eines string
    
  3. Elementzugriff
    // Das erste Element hat den Index 0
    char c = s[5]; // unbestimmtes Resultat, wenn s kürzer als 6 Zeichen ist!
    char d = s.at(5); // besser
    
  4. Größe
    string::size_type n = s.size();
    
  5. Konvertierung nach char*
    const char *c = s.c_str();
    
  6. Vergleich
    string s1, s2;
    int r = s1.compare( s2);
    r = s1.compare( "abc");
    r = s1.compare( pos1, n1, s2, pos2, n2);
    
    Die letzte Form vergleicht Teilzeichenketten von s1 und s2 beginnend ab pos mit der Länge n.
    compare liefert 0 als Rückgabewert, wenn die Zeichenketten gleich sind, einen negativen Wert, wenn s1 lexikografisch vor s2 steht und einen positiven Wert wenn umgekehrt.
    Außerdem können Strings mit den üblichen Vergleichsoperatoren == != < > >= und <= verglichen werden:
    if (s1 == s2) // ...
    
  7. Anhängen
    string s, s1;
    s += s1;
    s += "qwertz";
    s += 'x';
    s.append( s1, pos, n);
    s.append( "zuiop");
    
  8. Einfügen
    string s, s1;
    // Füge Zeichen vor pos ein
    s.insert( pos, s1);
    s.insert( pos, "abcdef");
    s.insert( pos, 5, ' ');
    
  9. Verkettung
    Strings können mit dem Operator + verkettet werden. Dabei kann auf einer Seite des Ausdrucks auch eine C-Zeichenkette vom Typ char* stehen.
    string s, s1, s2;
    s = s1 + s2;
    s = s1 + " xxx " + s2;
    
  10. Suchen
    Zum Finden eines kommpletten Substrings gibt es die Funktionen find und rfind:
    string s = "der Name der Rose";
    int i1 = s.find("der");    // liefert 0
    int i2 = s.rfind("der");   // liefert 9
    
    Zum Suchen einzelner Zeichen dienen dagegen die Funktionen find_first_of, find_last_of, find_first_not_of, find_last_not_of. Der Einsatz einiger dieser Funktionen wird an der nachfolgenden Funktion zur Aufteilung von Zeichenketten an bestimmten Trennzeichen demonstriert:
    // Funktion zum Aufteilen einer Zeichenkette an Trennzeichen
    // Parameter:
    // line   [in]   string   aufzuteilende Zeichenkette
    // sep    [in]   char*    Menge von Trennzeichen
    // words  [out]  vector<string> Vektor mit den getrennten Substrings
    void fsplit(const std::string line, const char* sep,
                std::vector<std::string> & words)
    {
        std::string::size_type a = 0, e;
        while ( (a = line.find_first_not_of( sep, a)) != std::string::npos) {
            e = line.find_first_of( sep, a);
            if (e != std::string::npos) {
                words.push_back( line.substr( a, e-a));
                a = e +1;
            }
            else {
                words.push_back( line.substr( a));
                break;
            }
        }
    }
    
  11. Ersetzen
    string s, s1;
    // ersetze Zeichen von i bis i+n
    s.replace( i, n, s1);
    s.replace( i, n, s1, i1, n1);
    s.replace( i, n, "abcdef");
    
    string r = "Der Fuchs ist in der Hundehütte";
    // Wie? Ersetze Fuchs mit Hund!
    r.replace( r.find( "Fuchs"), strlen("Fuchs"), "Hund");
    
  12. Löschen
    s.erase( i, n);   // Lösche s von i bis i+n
    s.erase();        // Lösche s komplett
    
  13. Teilzeichenketten
    s1 = s.substr( i, n); // n Zeichen ab dem i-ten Zeichen von s
    
  14. Ein- Ausgabe
    Die Operatoren >> und << sind für die Ein- und Ausgabe von Zeichenketten definiert.
    string s;
    cin >> s;
    cout << "Du schriebst: " << s << endl;
    
    Mittels der Funktion getline() kann eine Datei zeilenweise in einen String gelesen werden:
    string buffer;
    ifstream infile;
    infile.open("/etc/passwd");
    while (getline( infile, buffer)) cout << buffer << endl;