C++-Programmierung/ Weitere Grundelemente/ Zeichenketten

Aus Wikibooks
Zur Navigation springen Zur Suche springen


Einleitung[Bearbeiten]

In C gibt es keinen eingebauten Datentyp für Zeichenketten, lediglich einen für einzelne Zeichen. Da es in C noch keine Klassen gab, bediente man sich dort der einfachsten Möglichkeit, aus Zeichen Zeichenketten zu bilden: Man legte einfach einen Array von Zeichen an. C++ bietet eine komfortablere Lösung an: Die C++-Standardbibliothek enthält eine Klasse namens string. Um diese Klasse nutzen zu können, müssen Sie die gleichnamige Headerdatei string einbinden.

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string zeichenkette;
6     zeichenkette = "Hallo Welt!";
7     std::cout << zeichenkette << std::endl;
8 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 Hallo Welt!

Wir werden uns in diesem Kapitel mit der C++-Klasse string auseinandersetzen. Am Ende des Kapitels beleuchten wir den Umgang mit C-Strings (also char-Arrays) etwas genauer. Natürlich liegt auch string, wie alle Teile der Standardbibliothek, im Namensraum std.

Wie entsteht ein string-Objekt?[Bearbeiten]

Zunächst sind einige Worte zur Notation von Zeichenketten in doppelten Anführungszeichen nötig. Wie Ihnen bereits bekannt ist, werden einzelne Zeichen in einfachen Anführungszeichen geschrieben. Dieser Zeichenliteral ist dann vom Typ char. Die doppelten Anführungszeichen erzeugen hingegen eine Instanz eines char-Arrays. "Hallo Welt!" ist zum Beispiel vom Typ char[12].

Es handelt sich also um eine Kurzschreibweise, zum Erstellen von char-Arrays, damit Sie nicht {'H', 'a', 'l', 'l', 'o', ' ', 'W', 'e', 'l', 't', '!', '\0'} schreiben müssen, um eine einfache Zeichenkette zu erstellen. Was ist das '\0' und warum ist das Array 12 chars lang, obwohl es nur 11 Zeichen enthält? Wie bereits erwähnt, ist ein C-String ein Array von Zeichen. Da ein solcher C-String natürlich im Programmablauf Zeichenketten unterschiedlicher Längen enthalten konnte, beendete man die Zeichenkette durch ein Endzeichen: '\0' (Zahlenwert 0). Somit musste ein Array von Zeichen in C immer ein Zeichen länger sein, als die längste Zeichenkette, die im Programmverlauf darin gespeichert wurde.

Diese Kurzschreibweise kann aber noch mehr, als man auf den ersten Blick vermuten würde. Die eben genannte lange Notation zur Initialisierung eines Arrays funktioniert im Quelltext nur, wenn der Compiler auch weiß, von welchem Datentyp die Elemente des Arrays sein sollen. Da Zeichenliterale jedoch implizit in größere integrale Typen umgewandelt werden können, kann er den Datentyp nicht vom Typ der Elemente, die für die Initialisierung genutzt wurden ableiten:

Crystal Clear action button cancel.svg
 1 #include <string>
 2 
 3 int main() {
 4     // char-Array mit 12 Elementen
 5     char a[] = {'H', 'a', 'l', 'l', 'o', ' ', 'W', 'e', 'l', 't', '!', '\0'};
 6 
 7     // int-Array mit 12 Elementen
 8     int  b[] = {'H', 'a', 'l', 'l', 'o', ' ', 'W', 'e', 'l', 't', '!', '\0'};
 9 
10     // char-Array mit 12 Elementen
11     std::string z = {'H', 'a', 'l', 'l', 'o', ' ', 'W', 'e', 'l', 't', '!', '\0'};
12 }

Bei der Notation mit Anführungszeichen ist dagegen immer bekannt, dass es sich um ein char-Array handelt. Entsprechend ist die Initialisierung eines int-Arrays damit nicht möglich. Folgendes dagegen schon:

CrystalClearActionApply.svg
1 #include <string>
2 
3 int main() {
4     // char-Array mit 12 Elementen
5     char a[] = "Hallo Welt!";
6 
7     // char-Array mit 12 Elementen
8     std::string z = "Hallo Welt!";
9 }

Bei der Erzeugung eines string-Objekts wird eine Funktion aufgerufen, die sich Konstruktor nennt. Was genau ein Konstruktor ist, erfahren Sie im Kapitel über Klassen. In unserem Fall wird also der Konstruktor für das string-Objekt z aufgerufen. Als Parameter erhält er das char-Array "Hallo Welt!". Wie Ihnen bereits bekannt ist, können an Funktionen keine Arrays übergeben werden. Stattdessen wird natürlich ein Zeiger vom Arrayelementtyp (also char) übergeben. Dabei geht aber die Information verloren, wie viele Elemente dieses Array enthält und an dieser Stelle kommt das '\0'-Zeichen (Nullzeichen) ins Spiel. Anhand dieses Zeichens kann auch innerhalb des Konstruktors erkannt werden, wie lang die übergebene Zeichenkette ist.

Damit wissen Sie nun, wie aus dem einfachen char-Array das fertige string-Objekt wird. Jetzt ist es an der Zeit zu erfahren, was Sie mit diesem Objekt alles machen können

string und andere Datentypen[Bearbeiten]

Wie Sie bereits im Beispiel von eben gesehen haben, lässt sich die string-Klasse problemlos mit anderen Datentypen und Klassen kombinieren. Im ersten Beispiel dieses Kapitels wurde zunächst eine Zuweisung eines char-Arrays vorgenommen. Anschließend wurde das string-Objekt über cout ausgegeben. Auch die Eingabe einer Zeichenkette über cin ist mit einem string-Objekt problemlos möglich:

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string zeichenkette;
6 
7     std::cin >> zeichenkette;
8     std::cout << zeichenkette;
9 }

Diese Art der Eingabe erlaubt es lediglich, bis zum nächsten Whitespace einzulesen. Es kommt jedoch häufig vor, dass man eine Zeichenkette bis zum Zeilenende oder einem bestimmten Endzeichen einlesen möchte. In diesem Fall ist die Funktion getline hilfreich. Sie erwartet als ersten Parameter einen Eingabestream und als zweiten ein string-Objekt.

Nuvola-inspired-terminal.svg
 1 #include <iostream>
 2 #include <string>
 3 
 4 int main() {
 5     std::string zeichenkette;
 6 
 7     // Liest bis zum Zeilenende
 8     std::getline(std::cin, zeichenkette);
 9     std::cout << zeichenkette;
10 }

Als optionalen dritten Parameter kann man das Zeichen angeben, bis zu dem man einlesen möchte. Im Fall von eben wurde als der Default-Parameter '\n' (Newline-Zeichen) benutzt. Im folgenden Beispiel wird stattdessen bis zum ersten kleinen y eingelesen.

Nuvola-inspired-terminal.svg
 1 #include <iostream>
 2 #include <string>
 3 
 4 int main() {
 5     std::string zeichenkette;
 6 
 7     // Liest bis zum nächsten y
 8     std::getline(std::cin, zeichenkette, 'y');
 9     std::cout << zeichenkette;
10 }

Zuweisen und Verketten[Bearbeiten]

Genau wie die Basisdatentypen, lassen sich auch strings einander zuweisen. Für die Verkettung von strings wird der +-Operator benutzt und das Anhängen einer Zeichenkette ist mit += möglich.

Nuvola-inspired-terminal.svg
 1 #include <iostream>
 2 #include <string>
 3 
 4 int main() {
 5     std::string string1, string2, string3;
 6 
 7     string1 = "ich bin ";
 8     string2 = "klug";
 9     string3 = string1 + string2;
10     std::cout << string3 << std::endl;
11 
12     string3 += " - " + string1 + "schön";
13     std::cout << string3 << std::endl;
14 
15     std::cout << string1 + "schön und" + string2 << std::endl;
16 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 ich bin klug
2 ich bin klug - ich bin schön
3 ich bin schön und klug

Spielen Sie einfach ein wenig mit den Operatoren, um den Umgang mit ihnen zu lernen.

Nützliche Methoden[Bearbeiten]

Die string-Klasse stellt einige nützliche Methoden bereit. Etwa um den String mit etwas zu füllen, ihn zu leeren oder über verschiedene Eigenschaften Auskunft zu bekommen. Eine Methode wird mit folgender Syntax aufgerufen:

Crystal Project Tutorials.png
Syntax:
«stringname».«methodenname»(«parameter...»);
«Nicht-C++-Code», »optional«

Die Methoden size() und length() erwarten keine Parameter und geben beide die aktuelle Länge der gespeicherten Zeichenkette zurück. Diese Doppelung in der Funktionalität existiert, da string in Analogie zu den anderen Containerklassen der C++-Standardbibliothek size() anbieten muss, der Name length() für die Bestimmung der Länge eines Strings aber natürlicher und auch allgemein üblich ist. empty() gibt true zurück falls der String leer ist, andernfalls false.

Mit clear() lässt sich der String leeren. Die resize()-Methode erwartet ein oder zwei Parameter. Der erste ist die neue Größe des Strings, der zweite das Zeichen, mit dem der String aufgefüllt wird, falls die angegebene Länge größer ist, als die aktuelle. Wird der zweite Parameter nicht angegeben, wird der String mit '\0' (Nullzeichen) aufgefüllt. In der Regel werden Sie dieses Verhalten nicht wollen, geben Sie also ein Füllzeichen an, falls Sie sich nicht sicher sind, was Sie tun. Ist die angegebene Länge geringer, als die des aktuellen Strings, wird am Ende abgeschnitten.

Um den Inhalt zweier Strings auszutauschen existiert die swap()-Methode. Sie erwartet als Parameter den String mit dem ihr Inhalt getauscht werden soll. Dies ist effizienter, als das Vertauschen über eine dritte, temporäre string-Variable.

Nuvola-inspired-terminal.svg
 1 #include <iostream>
 2 #include <string>
 3 
 4 int main() {
 5     std::string zeichenkette1 = "Ich bin ganz lang!";
 6     std::string zeichenkette2 = "Ich kurz!";
 7 
 8     std::cout << zeichenkette1 << std::endl;
 9     std::cout << zeichenkette2 << std::endl;
10 
11     zeichenkette1.swap(zeichenkette2);
12 
13     std::cout << zeichenkette1 << std::endl;
14     std::cout << zeichenkette2 << std::endl;
15 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 Ich bin ganz lang!
2 Ich kurz!
3 Ich kurz!
4 Ich bin ganz lang!

Zeichenzugriff[Bearbeiten]

Genau wie bei einem Array können Sie den []-Operator (Zugriffsoperator) verwenden, um auf einzelne Zeichen im String zuzugreifen. Allerdings wird, ebenfalls genau wie beim Array, nicht überprüft, ob der angegebene Wert noch innerhalb der enthaltenen Zeichenkette liegt.

Alternativ existiert die Methode at(), die den Index als Parameter erwartet und eine Grenzprüfung ausführt. Im Fehlerfall löst sie eine out_of_range-Exception aus. Da Sie den Umgang mit Exceptions wahrscheinlich noch nicht beherrschen, sollten Sie diese Methode vorerst nicht einsetzen und stattdessen genau darauf achten, dass Sie nicht versehentlich über die Stringlänge hinaus zugreifen.

Nuvola-inspired-terminal.svg
 1 #include <iostream>
 2 #include <string>
 3 
 4 int main() {
 5     std::string zeichenkette = "Ich bin ganz lang!";
 6 
 7     std::cout << zeichenkette[4] << std::endl;
 8     std::cout << zeichenkette.at(4) << std::endl;
 9 
10     std::cout << zeichenkette[20] << std::endl;    // Ausgabe von Datenmüll
11     std::cout << zeichenkette.at(20) << std::endl; // Laufzeitfehler
12 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 b
2 b
3 
4 terminate called after throwing an instance of 'std::out_of_range'
5   what():  basic_string::at
6 Abgebrochen

Die Fehlerausgabe kann bei Ihrem Compiler anders aussehen.

Symbol opinion vote.svg
Hinweis

Beachten Sie beim Zugriff, dass das erste Zeichen den Index 0 hat. Das letzte Zeichen hat demzufolge den Index zeichenkette.length() - 1.

Manipulation[Bearbeiten]

Suchen[Bearbeiten]

Die Methode find() sucht das erste Vorkommen eines Strings und gibt die Startposition (Index) zurück. Der zweite Parameter gibt an, ab welcher Position des Strings gesucht werden soll.

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string str = "Zeichenkette";
6     std::string find = "k";
7     std::cout << str.find(find, 0);
8 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 7

Wird ein Substring nicht gefunden, gibt find() den Wert std::string::npos zurück.

Das Gegenstück zu find() ist rfind(). Es ermittelt das letzte Vorkommen eines Strings. Die Parameter sind die gleichen wie bei find().

Löschen[Bearbeiten]

Mit der Methode erase() können Zeichen im String gelöscht werden. Der erste Parameter gibt den Startwert an. Zusätzlich kann man mit dem zweiten Parameter die Anzahl der Zeichen festlegen. Wird die Methode nur mit dem Startwert aufgerufen, löscht sie alle Zeichen ab dieser Position.

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string str = "Hallo Welt.";
6     str.erase(5, 1);
7     std::cout << str << std::endl;
8 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 HalloWelt.

Ersetzen[Bearbeiten]

Sie können replace() verwenden, um Strings zu ersetzen. Dafür benötigen Sie die Anfangsposition und die Anzahl der Zeichen, die anschließend ersetzt werden sollen.

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string str = "Zeichenkette";
6     str.replace(str.find("k"), std::string("kette").length(), "test");
7     std::cout << str << std::endl;
8 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 Zeichentest

Wie Sie sehen, verwenden wir find(), um die Startposition zu ermitteln. Der zweite Parameter gibt die Länge an. Hier soll die alternative Schreibweise verdeutlicht werden; Sie müssen nicht eine zusätzliche Variable deklarieren, sondern können die std::string-Klasse wie eine Funktion verwenden und über Rückgabewert auf die Methode length() zugreifen. Im dritten Parameter spezifizieren Sie den String, welcher den ursprünglichen String zwischen der angegebenen Startposition und Startposition + Laenge ersetzt.

Einfügen[Bearbeiten]

Die Methode insert() erlaubt es Ihnen, einen String an einer bestimmten Stelle einzufügen.

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string str = "Hallo Welt.";
6     str.insert(5, " schöne");
7     std::cout << str << std::endl;
8 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 Hallo schöne Welt

Kopieren[Bearbeiten]

Mit der Methode substr() kann man sich einen Zeichenketten-Teil zurückgeben lassen. Der erste Parameter gibt den Startwert an. Zusätzlich kann man mit dem zweiten Parameter noch die Anzahl der Zeichen festlegen. Wird die Methode nur mit dem Startwert aufgerufen, gibt sie alle Zeichen ab dieser Position zurück.

Nuvola-inspired-terminal.svg
1 #include <iostream>
2 #include <string>
3 
4 int main() {
5     std::string str = "Hallo Welt.";
6     std::cout << str.substr(0, str.find(' ') - 0) << std::endl;
7 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 Hallo

Das -0 soll verdeutlichen, dass der Startwert abgezogen werden muss, an dieser Stelle ist es natürlich überflüssig.

Vergleiche[Bearbeiten]

C++-Strings können Sie, genau wie Zahlen, miteinander vergleichen. Was Gleichheit und Ungleichheit bei einem String bedeutet, wird Ihnen sofort klar sein. Sind alle Zeichen zweier Strings identisch, so sind beide gleich, andernfalls nicht. Die Operatoren <, >, <= und >= geben da schon einige Rätsel mehr auf.

Im Grunde kennen Sie die Antwort bereits. Zeichen sind in C++ eigentlich Zahlen. Sie werden zu Zeichen, indem den Zahlen entsprechende Symbole zugeordnet werden. Der Vergleich erfolgt also einfach mit den Zahlen, welche die Zeichen kodieren. Das erste Zeichen der Strings, das sich unterscheidet, entscheidet darüber, welcher der Strings größer bzw. kleiner ist.

Die meisten Zeichenkodierungen beinhalten in den ersten 7 Bit den ASCII-Code, welchen die nachfolgende Tabelle zeigt.

ASCII-Codetabelle, Nummerierung im Hexadezimalsystem (Teil 1)
Code …0 …1 …2 …3 …4 …5 …6 …7
0… NUL SOH STX ETX EOT ENQ ACK BEL
1… DLE DC1 DC2 DC3 DC4 NAK SYN ETB
2… SP ! " # $ % & '
3… 0 1 2 3 4 5 6 7
4… @ A B C D E F G
5… P Q R S T U V W
6… ` a b c d e f g
7… p q r s t u v w
ASCII-Codetabelle, Nummerierung im Hexadezimalsystem (Teil 2)
Code …8 …9 …A …B …C …D …E …F
0… BS HT LF VT FF CR SO SI
1… CAN EM SUB ESC FS GS RS US
2… ( ) * + , - . /
3… 8 9 : ; < = > ?
4… H I J K L M N O
5… X Y Z [ \ ] ^ _
6… h i j k l m n o
7… x y z { | } ~ DEL
Nuvola-inspired-terminal.svg
 1 #include <string>
 2 
 3 int main(){
 4     std::string gross = "Ich bin ganz groß!";
 5     std::string klein = "Ich bin ganz klein!";
 6 
 7     gross == klein; // ergibt false ('g' != 'k')
 8     gross != klein; // ergibt true  ('g' != 'k')
 9     gross <  klein; // ergibt true  ('g' <  'k')
10     gross >  klein; // ergibt false ('g' <  'k')
11     gross <= klein; // ergibt true  ('g' <  'k')
12     gross >= klein; // ergibt false ('g' <  'k')
13 }

Zahl zu string und umgekehrt[Bearbeiten]

In C++ gibt es, im Gegensatz zu vielen anderen Programmiersprachen, keine Funktion, um direkt Zahlen in Strings oder umgekehrt umzuwandeln. Es ist allerdings nicht besonders schwierig, eine solche Funktion zu schreiben. Wir haben für die Umwandlung zwei Möglichkeiten:

  • Die C-Funktionen atof(), atoi(), atol() und sprintf()
  • C++-String-Streams

Die C-Variante wird in Kürze im Zusammenhang mit C-Strings besprochen. Für den Moment wollen wir uns der C++-Variante widmen. Stringstreams funktionieren im Grunde genau wie die Ihnen bereits bekannten Ein-/Ausgabestreams cin und cout mit dem Unterschied, dass sie ein string-Objekt als Ziel benutzen.

Nuvola-inspired-terminal.svg
 1 #include <iostream> // Standard-Ein-/Ausgabe
 2 #include <sstream>  // String-Ein-/Ausgabe
 3 
 4 int main() {
 5     std::ostringstream strout; // Unser Ausgabe-Stream
 6     std::string str;           // Ein String-Objekt
 7     int var = 10;              // Eine ganzzahlige Variable
 8 
 9     strout << var;             // ganzzahlige Variable auf Ausgabe-Stream ausgeben
10     str = strout.str();        // Streaminhalt an String-Variable zuweisen
11 
12     std::cout << str << std::endl; // String ausgeben
13 }

Der vorliegende Code wandelt eine Ganzzahl in einen String um, indem die Ganzzahl auf dem Ausgabe-Stringstream ausgegeben und dann der Inhalt des Streams an den String zugewiesen wird. Die umgekehrte Umwandlung funktioniert ähnlich. Natürlich verwenden wir hierfür einen Eingabe-Stringstream (istringstream statt ostringstream) und übergeben den Inhalt des Strings an den Stream, bevor wir ihn von diesem auslesen.

Nuvola-inspired-terminal.svg
 1 #include <iostream> // Standard-Ein-/Ausgabe
 2 #include <sstream>  // String-Ein-/Ausgabe
 3 
 4 int main() {
 5     std::istringstream strin; // Unser Eingabe-Stream
 6     std::string str = "17";   // Ein String-Objekt
 7     int var;                  // Eine ganzzahlige Variable
 8 
 9     strin.str(str);           // Streaminhalt mit String-Variable füllen
10     strin >> var;             // ganzzahlige Variable von Eingabe-Stream einlesen
11 
12     std::cout << var << std::endl; // Zahl ausgeben
13 }

Statt istringstream und ostringstream können Sie übrigens auch ein stringstream-Objekt verwenden, welches sowohl Ein-, als auch Ausgabe erlaubt, allerdings sollte man immer so präzise wie möglich angeben, was der Code machen soll. Daher ist die Verwendung eines spezialisierten Streams zu empfehlen, wenn Sie nur die speziellen Fähigkeiten (Ein- oder Ausgabe) benötigen.

Sicher sind Sie jetzt bereits in der Lage, zwei Funktionen zu schreiben, welche diese Umwandlung durchführt. Allerdings stehen wir in dem Moment, wo wir andere Datentypen als int in Strings umwandeln wollen vor einem Problem. Wir können der folgenden Funktion zwar ohne weiteres eine double-Variable übergeben, allerdings wird dann der Nachkommateil einfach abgeschnitten. Als Lösung kommt Ihnen nun eventuell in den Sinn, einfach eine double-Variable von der Funktion übernehmen zu lassen.

Nuvola-inspired-terminal.svg
 1 #include <iostream> // Standard-Ein-/Ausgabe
 2 #include <sstream>  // String-Ein-/Ausgabe
 3 
 4 std::string zahlZuString(double wert) {
 5     std::ostringstream strout; // Unser Ausgabe-Stream
 6     std::string str;           // Ein String-Objekt
 7 
 8     strout << wert;            // Zahl auf Ausgabe-Stream ausgeben
 9     str = strout.str();        // Streaminhalt an String-Variable zuweisen
10 
11     return str;                // String zurückgeben
12 }
13 
14 int main() {
15     std::string str;
16     int    ganzzahl  = 19;
17     double kommazahl = 5.55;
18 
19     str = zahlZuString(ganzzahl);
20     std::cout << str << std::endl;
21 
22     str = zahlZuString(kommazahl);
23     std::cout << str << std::endl;
24 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 19
2 5.55

Nun, so weit so gut. Das funktioniert. Leider gibt es da aber auch noch die umgekehrte Umwandlung und obgleich es möglich ist, sie auf ähnliche Weise zu lösen, wird Ihr Compiler sich dann ständig mit einer Warnung beschweren, wenn das Ergebnis Ihrer Umwandlung an eine ganzzahlige Variable zugewiesen wird.

Besser wäre es, eine ganze Reihe von Funktionen zu erzeugen, von denen jede für einen Zahlentyp verantwortlich ist. Tatsächlich können Sie in C++ mehrere Funktionen gleichen Namens erzeugen, die unterschiedliche Parameter(typen) übernehmen. Diese Vorgang nennt sich Überladen von Funktionen. Der Compiler entscheidet dann beim Aufruf der Funktion anhand der übergebenen Parameter, welche Version gemeint war, während der Programmierer immer den gleichen Namen verwendet.

Im Moment haben wir obendrein einen Sonderfall der Überladung. Alle unsere Funktionen besitzen exakt den gleichen Code. Lediglich der Parametertyp ist unterschiedlich. Es wäre ziemlich zeitaufwendig und umständlich, den Code immer wieder zu kopieren, um dann nur den Datentyp in der Parameterliste zu ändern. Noch schlimmer wird es, wenn wir eines Tages eine Änderung am Funktionsinhalt vornehmen und diese dann auf alle Kopien übertragen müssen.

Glücklicherweise bietet C++ für solche Fälle so genannte Templates, die es uns erlauben, den Datentyp vom Compiler ermitteln zu lassen. Wir teilen dem Compiler also mit, was er tun soll, womit muss er dann selbst herausfinden. Die Funktion zahlZuString() (umbenannt in toString()) sieht als Template folgendermaßen aus:

Nuvola-inspired-terminal.svg
 1 #include <iostream> // Standard-Ein-/Ausgabe
 2 #include <sstream>  // String-Ein-/Ausgabe
 3 
 4 template <typename Typ>
 5 std::string toString(Typ wert) {
 6     std::ostringstream strout; // Unser Ausgabe-Stream
 7     std::string str;           // Ein String-Objekt
 8 
 9     strout << wert;            // Zahl auf Ausgabe-Stream ausgeben
10     str = strout.str();        // Streaminhalt an String-Variable zuweisen
11 
12     return str;                // String zurückgeben
13 }
14 
15 int main() {
16     std::string str;
17     int    ganzzahl  = 19;
18     double kommazahl = 5.55;
19     std::string nochnString = "Blödsinn";
20 
21     str = toString(ganzzahl);
22     std::cout << str << std::endl;
23 
24     str = toString(kommazahl);
25     std::cout << str << std::endl;
26 
27     str = toString(nochnString);
28     std::cout << str << std::endl;
29 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 19
2 5.55
3 Blödsinn

Die letzte Ausgabe zeigt deutlich warum die Funktion in toString umbenannt wurde, denn sie ist nun in der Lage, jeden Datentyp, der sich auf einem ostringstream ausgeben lässt, zu verarbeiten und dazu zählen eben auch string-Objekte und nicht nur Zahlen. Sie werden später noch lernen, welches enorme Potenzial diese Technik in Zusammenhang mit eigenen Datentypen hat. An dieser Stelle sei Ihnen noch die Funktion zur Umwandlung von Strings in Zahlen (oder besser: alles was sich von einem istringstream einlesen lässt) mit auf den Weg gegeben:

Nuvola-inspired-terminal.svg
 1 #include <iostream> // Standard-Ein-/Ausgabe
 2 #include <sstream>  // String-Ein-/Ausgabe
 3 
 4 template <typename Typ>
 5 void stringTo(std::string str, Typ &wert) {
 6     std::istringstream strin; // Unser Eingabe-Stream
 7 
 8     strin.str(str);           // Streaminhalt mit String-Variable füllen
 9     strin >> wert;            // Variable von Eingabe-Stream einlesen
10 }
11 
12 int main() {
13     std::string str = "7.65Blödsinn";
14     int    ganzzahl;
15     double kommazahl;
16     std::string nochnString;
17 
18     stringTo(str, ganzzahl);
19     std::cout << ganzzahl << std::endl;
20 
21     stringTo(str, kommazahl);
22     std::cout << kommazahl << std::endl;
23 
24     stringTo(str, nochnString);
25     std::cout << nochnString << std::endl;
26 }
Crystal Clear app kscreensaver.svg
Ausgabe:
1 7
2 7.65
3 7.65Blödsinn

Die Variable, die mit dem Wert des Strings belegt werden soll, wird als Referenz an die Funktion übergeben, damit der Compiler ihren Typ feststellen kann. Die Ausgabe zeigt, dass immer nur so viel eingelesen wird, wie der jeweilige Datentyp (zweiter Funktionsparameter) fassen kann. Für eine ganzzahlige Variable wird nur die Zahl Sieben eingelesen, die Gleitkommavariable erhält den Wert 7.65 und das string-Objekt kann die gesamte Zeichenkette übernehmen.

Symbol move vote.svg
Thema wird später näher erläutert…

Sie werden Überladung im Kapitel „Methoden“ genauer kennen lernen. Templates sind ein sehr umfangreiches Thema, auf sie wird im Abschnitt Templates eingegangen.

C-Strings[Bearbeiten]

Wie bereits erwähnt, handelt es sich bei einem C-String um ein Array von chars. Das Ende eines C-Strings wird durch ein Nullzeichen (Escape-Sequenz '\0') angegeben. Das Arbeiten mit C-Strings ist mühsam, denn es muss immer sichergestellt sein, dass das Array auch groß genug ist, um den String zu beinhalten. Da in C/C++ jedoch auch keine Bereichsüberprüfung durchgeführt wird, macht sich ein Pufferüberlauf (also eine Zeichenkette die größer ist als das Array, das sie beinhaltet) erst durch einen eventuellen Programmabsturz bemerkbar. Allein um dies zu vermeiden sollten Sie, wann immer es Ihnen möglich ist, die C++-string-Klasse verwenden.

Ein weiteres Problem beim Umgang mit C-Strings ist der geringe Komfort beim Arbeiten. Ob Sie einen String mit einem anderen vergleichen wollen, oder ihn an ein anderes Array „zuweisen“ möchten, in jedem Fall benötigen Sie unintuitive Zusatzfunktionen. Diese Funktionen finden Sie in der Standardheaderdatei „cstring“. Wie diese Funktionen heißen und wie man mit ihnen umgeht können Sie im C++-Referenz-Buch nachlesen, falls Sie sie einmal benötigen sollten.

Symbol redirect vote.svg
Buchempfehlung

Wenn Sie sich eingehender mit der Thematik auseinandersetzen möchten, sei Ihnen das Buch C-Programmierung ans Herz gelegt. Wenn Sie in C++ mit der C-Standard-Bibliothek arbeiten möchten, müssen Sie den Headerdateien ein „c“ voranstellen und das „.h“ weglassen. So wird beispielsweise aus dem C-Header „string.h“ der C++-Header „cstring“.