C++ Tutorial

 string-Objekte I

Für die Bearbeitung von Strings stellt die C++-Standardbibliothek den Datentyp string zur Verfügung, welcher in der Header-Datei <string> definiert ist.

string-Objekt definieren

Ein string-Objekt, im Folgenden vereinfacht nur String genannt, wird prinzipiell wie eine Variable definiert:

std::string sName;

sName ist der Name des Strings.

Ein String kann bei seiner Definition mit einem C-String oder einem String initialisiert werden. In beiden Fällen folgt nach dem Namen des Strings in einer geschweiften Klammer der Initialisierungsstring. Zur Unterscheidung eines C-String-Literals von einem String-Literal wird an das String-Literal nach dem abschließenden Anführungszeichen das Suffix s angehängt. Damit der Compiler das Suffix s kennt, ist dieses mittels using namespace std::string_literals; einzubinden.

#include <iostream>
#include <format>
// Header-Datei fuer std::string Datentyp
#include <string>
// Suffix s fuer string-Literale einblenden
using namespace std::string_literals;

int main()
{
   // string-Objekt mit C-String-Literal init.
   std::string string1{"C-String-Literal"};
   // string-Objekt mit String-Literal init.
   std::string string2{"String-Literal"s};
   // string mit C-String initialisieren
   const char text[] {"Ein C-String"};
   std::string string3 {text};
}

String ausgeben und einlesen

Die Ausgabe eines Strings unterscheidet sich nicht von der Ausgabe anderer Daten, d. h., der String wird mit dem Operator << in den Ausgabestream einfügt.

Beim Einlesen eines Strings ist zu unterscheiden, ob jedes Wort der Eingabe in einem eigenen String abgelegt werden sollen oder die gesamte Eingabe in einem String. Um jedes Wort einer Eingabe in einem eigenen String abzulegen, sind entsprechend viele Strings beim Einlesen anzugeben. Soll dagegen eine ganze Zeile in einem String abgelegt werden, ist die Funktion std::getline() zu verwenden.

std::getline (in, line[, del]);

in ist die Referenz auf den zu verwendenden Eingabestream, z.B. std::cin, und line eine Referenz auf den String, in dem die Eingabe abgelegt werden soll.

#include <iostream>

#include <format>
#include <string>
// Suffix s fuer string-Literale einblenden
using namespace std::string_literals;

int main()
{
   // string-Objekte
   std::string string1, string2;
   // Zwei Woerter in die string-Objekte einlesen
   std::cout << "2 Woerter eingeben: ";
   std::cin >> string1 >> string2;
   // und wieder ausgeben
   std::cout << std::format("Eingabe war:\n{}\n{}\n",string1,string2);
   // Komplette Zeile einlesen, aber zuvor muss der
   // Eingabepuffer geleert werden, da zumindest das
   // <RETURN> von der vorherigen Eingabe noch im
   // Eingabepuffer vorhanden ist und damit die Eingabe
   // der Zeile abgeschlossen waere
   std::cin.ignore();
   std::cout << "Ganze Zeile eingeben: ";
   std::getline(std::cin,string1);
   // und ausgeben
   std::cout << std::format("Eingabe war:\n{}\n",string1);
}

String Operationen

Folgende grundlegenden Operationen sind mit Strings möglich:

  • Zuweisung: Weist einem String einen weiteren String oder C-String zu.
  • Addition: Fügt an einen String einen weiteren String oder C-String hinzu und legt das Ergebnis in einem neuen String ab.
  • Vergleich: Vergleicht mittels der Vergleichsoperatoren einen String mit einem weiteren String oder C-String. Der Vergleich erfolgt hierbei lexikografisch, d.h. 'Aaaa' ist kleiner als 'Bb'.
#include <iostream>
#include <format>
// Header-Datei fuer std::string Datentyp
#include <string>
// Suffix s fuer string-Literale einblenden
using namespace std::string_literals;

int main()
{
   // string-Objekte
   std::string string1, string2;
   // Zuweisung eines C-Strings und eines Strings
   string1 = "eins";
   string2 = "zwei"s;
   // strings addieren
   auto string3 = string1 + string2;
   std::cout << std::format("{} + {} = {}\n", string1, string2, string3);
   // strings vergleichen
   std::cout << std::format("{} == {}: {}\n", string1,string2,(string1==string2));
}

Zugriff auf Zeichen im String

Um auf einzelne Zeichen in einem String zuzugreifen wird der Indexoperator [] verwendet, wobei das erste Zeichen im String den Index 0 besitzt. Um alle Zeichen in einem String zu durchlaufen kann eine entsprechende (range-)for Schleife eingesetzt werden.

Die Memberfunktion size() liefert dazu die Anzahl der Zeichen im String. Um die Memberfunktion aufzurufen, steht vor dem Funktionsnamen size() der Name des Strings, dessen Länge ermittelt werden soll, gefolgt von einem Punkt, also z.B.

auto length = myString.size();

Dies ist die allgemeine Syntax für den Aufruf einer Memberfunktion. Memberfunktionen werden später bei der Beschreibung von Klassen noch ausführlich behandelt.

#include <iostream>
#include <format>
#include <string>

int main()
{
   // string-Objekt
   std::string string1{"eins"};
   // Alle Zeichen des Strings durch Kommma getrennt ausgeben
   for (auto character: string1)
      std::cout << std::format("{},",character);
}

string_view-Objekt

Ein string_view, definiert in der Header-Datei <string_view>, ist lediglich eine Sicht auf einen bereits bestehenden String bzw. C-String. Er kann bei seiner Definition mit einem String oder C-String initialisiert werden. Da ein string_view nur eine Sicht darstellt, kann der Inhalt des Strings nicht verändert werden. Mithilfe eines string_view kann unnötiges Kopieren von Strings vermieden werden. Sehen Sie sich dazu das folgende Beispiel an:

#include <iostream>
#include <string>
#include <string_view>

// Funktion erhaelt Kopie auf uebergebenen String
void Print1(const std::string text)
{
   std::cout << text;
}
// Funktion erhaelt eine Sicht auf den uebergebenen String
void Print2(std::string_view text)
{
   std::cout << text;
}

int main()
{
   // Ausgangs-String
   std::string string1 {"Ein Text\n"};
   // Hier wird der String string1 in string2 kopiert
   std::string string2 = string1;
   // Hier erfolgt kein Kopiervorgang, sview verweist
   // nur auf string1
   std::string_view sview = string1;
   // string1 wird kopiert und die Kopie an Print1() uebergeben
   Print1(string1);
   // Kein Kopiervorgang!
   Print2(string1);
   // Und auch hier findet kein Kopiervorgang statt
   Print2("Noch ein Text"s);
}

Der Datentyp string_view besitzt weitere Memberfunktionen, um z.B. einen Teilstring in einem string-Objekt zu finden. Diese werden wir uns ebenfalls später ansehen.

String Konvertierungen

string und const char*

Die Memberfunktion c_str()

const char *ptr = myString.c_str();

liefert einen const char-Zeiger (C-String) auf die im String abgelegt Zeichenfolge. Damit ist es möglich, überall dort einen String zu verwenden, wo ein const char-Zeiger erwartet wird.

Der umgekehrte Weg, einen C-String in einen String zu konvertieren, erfolgt über den Zuweisungsoperator.

String in numerischen Wert

Die Konvertierung eines Strings in einen numerischen Wert kann auf mehrere Arten erfolgen. Wir werden uns hier nur eine Form ansehen, die Konvertierung mittels der Funktionen

DTYP conv = std::stoX(str);

Das X in stoX definiert den Zieldatentyp. Für X sind i, l, ll, ul und ull zugelassen, je nachdem, ob der Stringinhalt in einen int, long, long long, unsigned long oder unsigned long long Wert konvertiert werden soll. So konvertiert z.B. stol(myVal); einen String in einen long Wert. Enthält der String einen "Gleitkommawert", so ist für X f, d oder ld einzusetzen, je nach dem, ob die Konvertierung in einen float, double oder long double erfolgen soll.

#include <iostream>
#include <format>
#include <string>

int main()
{
   // Ausgangsstrings
   std::string s1{"3.12"}, s2{"5.2"};
   // strings in double-Werte umwandeln und Summe ausgeben
   auto val1 = std::stod(s1);
   auto val2 = std::stod(s2);
   std::cout << std::format("{} + {} = {}\n", s1,s2,val1+val2);
}

Die Funktionen haben noch optionale Parameter, um z.B. die Zahlenbasis für die Konvertierung in Ganzzahlen festzulegen.

String in mehrere numerischen Werte

Enthält ein String mehrere Werte die konvertiert werden sollen, kann der Stream istringsteam hierfür verwendet werden. Wenn Sie diesen Stream einsetzen, müssen Sie die Header-Datei <sstream> einbinden.

Um aus einem String mehrere Werte zu extrahieren, ist zunächst ein istringstream-Objekt zu definieren. Anschließend wird der Memberfunktion str() der zu zerlegenden String übergeben. Und ab diesem Zeitpunkt verhält sich istringstream genauso wie der Eingabestream cin, d.h. mithilfe des Operators >> werden die einzelnen Wörter bzw. Werte aus diesem Stream extrahiert.

Soll der Inhalt von mehreren Strings nacheinander konvertiert werden, muss nach jeder Konvertierung der Status des Streams mittels der Memberfunktion clear() zurückgesetzt werden.

#include <iostream>
#include <format>
#include <string>
#include <sstream>
using namespace std::string_literals;

int main()
{
   // strings mit mehreren Werten
   std::string s1{ "1.1 100"s }, s2{ "99 3.3"s };
   // istringstream-Objekt definieren
   std::istringstream is;
   // Ersten String mit istringstream-Objekt verbinden
   is.str(s1);
   // Werte aus istringstream auslesen und ausgeben
   float fVar;
   short sVar;
   is >> fVar >> sVar;
   std::cout << std::format("s1 numerisch: {:.2f}, {}\n",fVar,sVar);
   // istringstream zuruecksetzen!
   is.clear();
   // Zweiten string mit istringstream verbinden
   is.str(s2);
   // Werte erneut auslesen und ausgeben
   is >> sVar >> fVar;
   std::cout << std::format("s2 numerisch: {}, {:.2f}\n",sVar,fVar);
}

Numerische Werte in einen String

Die einfachste Konvertierung eines numerischen Werts in einen string erfolgt mit der Funktion to_string(). Sie erhält als Parameter das zu konvertierende Datum.

#include <iostream>
#include <format>
#include <string>

int main()
{
   float fVal = 10.1f;
   std::string res = std::to_string(fVal);
   std::cout << res << '\n';
}

Eleganter und mit der Möglichkeit, mehrere Daten auf einmal zu konvertieren und dabei noch zu formatieren, geht es mit der bekannten Funktion format().

#include <iostream>
#include <format>
#include <string>

int main()
{
   float fVal = 10.1f;
   int iVal = 200;
   std::string res = std::format("{:.2f} {:06}",fVal, iVal);
   std::cout << res << '\n';
}