Zeichenketten

Einführung

Bis jetzt haben wir uns bei Variablen lediglich auf diejenigen beschränkt, welche Ganz- und Kommazahlen aufnehmen können. In diesem Kapitel sollen Zeichenketten (Strings) eingeführt werden. Im Prinzip sind Zeichenketten nichts weiter als Arrays aus Ganzzahlen. Nur werden sie eben nicht als ein Feld aus Ganzzahlen interpretiert sondern als eine Reihe von Zeichen. So werden jedem darstellbaren Zeichen eine Zahl zugeordnet. Am gebräuchlichsten ist der ANSI-Zeichensatz. Dort stehen für jedem Zeichen genau ein Byte bzw. acht Bit zur Verfügung. Es lassen sich somit also 256 verschiedene Zeichen definieren. Der Buchstabe 'A' hat zum Beispiel den ANSI-Code 65. Der Code 32 steht für ein Leerzeichen usw. Allerdings ist der ANSI-Zeichensatz länderspezifisch. Sonderzeichen tauchen unter Umständen in anderen Ländern nicht auf. So wird unser 'Ö' z.B. woanders eventuell ganz anders interpretiert. Entweder ist der Code in einem anderen Land einem anderen Zeichen zugeordnet oder der Code wird gar nicht erkannt. Meist werden nicht bekannte Codes von einigen Programmen dann in Form von Kästchen dargestellt. Aus diesem Grunde existiert ein zweiter Zeichensatz dem sogenannten UNICODE-Zeichenstz der jedem Buchstaben zwei Byte also 16 Bit zuordnet. Es lassen sich somit 65536 Zeichen unterscheiden. In diesem Zeichensatz sind dann auch chinesische, kyrillische und alle möglichen Sonderzeichen enthalten. Glücklicherweise sind die Standardzeichen ('a'-'z', 'A'-'Z', '0'-'9' und die Interpunktion) im ANSI-Zeichensatz überall mit dem gleichen Code versehen und können dementsprechend interpretiert werden. Der UNICODE-Zeichensatz wurde aber fand bisher nur in Windows NT, 2000 und XP entsprechende Beachtung. Unter Windows 98 beispielsweise sind nur wenige Funktionen definiert, die mit diesem Zeichensatz arbeiten können. Aus diesem Grunde werden wir uns hier auf den ANSI-Zeichensatz beschränken.  

Eigenschaften von Zeichenketten

Konstante Zeichenketten wurden bereits in den vergangenen Lektionen mehrfach verwendet, nämlich bei Textausgaben über 'cout'. So z.B.

cout << "Hello World!" << endl;

Zeichenketten werden durch Anführungszeichen (") kenntlich gemacht. Alles was zwischen zwei Anführungszeichen steht wird als Zeichenkette interpretiert. Einzelne Zeichen werden mit Hilfe von einzelnen Anführungszeichen (') markiert (also: 'A', 'C', '1', etc.). Da Zahlen im ANSI-Zeichensatz nicht den Codes 0-9 entsprechen sind die Werte von 1 und '1' nicht identisch. 

 Wie bereits erwähnt handelt es sich bei Zeichenketten um einen Array aus acht  Bit großen Ganzzahlen genaugenommen aus einem 'char'-Array. Allerdings haben diese Arrays eine Besonderheit. Damit eine Funktion erkennen kann, wie groß der die Zeichenkette ist, ist das letzte Zeichen einer Zeichenkette immer das '\0'-Zeichen (ANSI-Code 0). Dies muss man immer dann beachten, wenn man einen Array in Form einer Variablen erstellt, bearbeitet oder an Funktionen übergibt.

Deklaration

Möchte man nun eine konstante Zeichenkette in einer Variablen speichern so geht dies im allgemeinen wie folgt:

char <Variablenname>[<max. Länge>];

Die maximale Länge muss das '\0'- Zeichen bereits beinhalten und es muss im vorneherein klar sein, wie groß die Zeichenkette maximal sein wird. Angenommen ihre Zeichenkette soll maximal 100 Buchstaben groß sein. Dann sähe die Deklaration wie folgt aus:

char str[101];

Sie können jetzt jede Zeichenkette die genau oder weniger als 100 Zeichen hat in dieser Variablen speichern. Angenommen Sie wollen nun die Zeichenkette "Hello World!" in der Variablen speichern. So ließe sich das so realisieren:

str[0] = 'H'; 
str[1] = 'e';
str[2] = 'l';
...
str[5] = ' ';
...
str[11] = '!';
str[12] = '\0';

Wichtig ist, dass das letzte Zeichen das bereits erwähnte '\0'-Zeichen ist. Außerdem ist zu beachten, dass wenn man die Buchstaben einzeln in dem Array speichert sie durch zwei einfache Anführungszeichen (') markiert. Diese Zeichenkette lässt sich jetzt mit 'cout' ausgeben ganz einfach ausgeben:

cout << str << endl;

Initialisierung

Man kann die Zeichenkette aber auch gleich bei der Deklaration initialisieren. Dazu gibt es folgende Möglichkeiten: 

char str[13] = "Hello World!";

oder

char str[] = "Hello World!";

oder

char* str = "Hello World!";

Die erste Variante ist nur sinnvoll, wenn man wirklich sicherstellen will, dass die Zeichenkette eine ganz bestimmte Anzahl von Zeichen besitzt (hier 13 inkl. '\0'-Zeichen). Alle Zeichenketten sind 13 Byte groß und können Wörter mit maximal zwölf Buchstaben aufnehmen. Die ersten beiden Zeichenketten lassen sich nach belieben editieren. So wäre bei den ersten beiden Zeichenketten folgende Operation vollkommen legitim:

str[1] = 'a'; str[5] = '\0';

Wenn man diese Zeichenkette nun ausgibt, dann dürfte auf dem Bildschirm "Hallo" erscheinen. Die Buchstaben welche nach dem '\0'-Zeichen stehen also "World!" werden nicht mehr angezeigt. Alle Funktionen die mit solchen Zeichenketten arbeiten, richten sich nach dem ersten '\0'-Zeichen. Daten, welche dahinter stehen, bleiben unberücksichtigt.

Bei der letzten Zeichenkette (char* str = "Hello World!") handelt es sich um eine konstante Zeichenkette, die im Laufe des Programms nicht mehr verändert werden kann.

Zeichenkettenfunktionen der STL 

Die STL bietet eine Menge Funktionen zum Umgang mit Zeichenketten an. Einige von ihnen sind vor allem in der Headerdatei "string.h" zu finden:

Die Länge von Zeichenketten:

Mit Hilfe der Funktion 'strlen' lässt sich ganz einfach die Länge einer Zeichenkette bestimmen. Das '\0'-Zeichen wird dabei nicht mitgezählt. Um die Länge der Zeichenkette 'str' zu bestimmen wäre folgender Aufruf nötig:

unsigned int uiLength = strlen(str);

Im Falle der zuletzt manipulierten Zeichenkette 'str' sollte die Funktion den Wert fünf (für "Hallo") liefern.

Kopieren von Zeichenketten:

Soll eine Zeichenkette in eine andere kopiert werden, dann funktioniert dies mit der Funktion 'strcpy'. Um eine Zeichenkette 'str2' in eine Zeichenkette 'str1' zu kopieren wäre folgender Aufruf nötig:

strcpy(str1, str2);

Dabei wird die zweite Zeichenkette ('str1') nicht verändert, während die erste ('str1') anschließend genau die gleichen Daten besitzt wie die zweite. Somit kann 'str2' auch eine konstante Zeichenkette sein. Um z.B., wie anfangs bereits auf andere Weise vorgeführt, die Zeichenkette 'str' mit den Daten "Hello World!" zu füllen kann man einfach folgenden Aufruf vornehmen:

strcpy(str, "Hello World!");

Sollen nur die ersten 'n' Buchstaben kopiert werden, dann hilft die Methode 'strncpy' weiter. Ihr Aufruf sieht entsprechen dem ersten so aus:

strncpy(str1, str2, n);

Mit folgendem Aufruf würde man nur das Wort "Hello" der Zeichenkette "Hello World!"  in die Variable 'str' übertragen:

strncpy(str, "Hello World!", 5);
str[5] = '\0';

Im Gegensatz zu der vorherigen Funktion wird bei dieser Funktion kein '\0'-Zeichen ergänzt. Dies muss manuell geschehen.

Verbinden von Zeichenketten:

Soll einer bereits bestehenden Zeichenkette 'str1' eine weitere 'str2' angehängt werden, so lässt sich dies am einfachsten mit der Funktion 'strcat' erreichen:

strcat(str1, str2);

Es muss allerdings sichergestellt sein, dass die 'str1' groß genug ist um 'str2' noch aufnehmen zu können. Hat beispielweise die Variable 'str' für 100 Zeichen Platz und ist in ihr bereits das Wort "Hello" gespeichert, dann ist mit folgendem Aufruf zu erreichen, dass 'str1' auf die Zeichenkette "Hello World!" "anwächst":

strcat(str, " World!");

Wäre 'str' allerdings zu klein, dann könnte dieser Befehl zu "Problemen" bekannter Art führen. Bei dieser FUnktion wird nur die erste Zeichenkette verändert.

Vergleichen von zwei Zeichenketten:

Zum lexikalischen Vergleichen zweier Zeichenketten ('str1' und 'str2') bietet sich die Funktion 'strcmp' an:

int iRes = strcmp(str1, str2);

Das Ergebnis ist eine Ganzzahl ('iRes'). Ist diese kleiner als null, dann kommt 'str1' im Alphabet vor 'str2'. Ist sie größer als null, dann kommt 'str1' im Alphabet nach 'str2'. Ist das Ergebnis hingegen genau null, dann sind 'str1' und 'str2' (in Länge und Daten) identisch. Bei dieser Funktion werden die Zeichenketten nicht verändert. 

Bei folgenden Aufrufen wäre das Ergebnis z.B. positiv (die erste Zeichenkette kommt also nach der zweiten):

strcmp("Hello", "Hallo");
strcmp("Hello World!", "Hello");

Sollen nur die ersten 'n' Buchstaben zweier Zeichenketten verglichen werden, dann lässt sich die Funktion 'strncmp' verwenden. Ihr allgemeiner Aufruf sähe in etwa so aus:

int iRes = strncmp(str1, str2, n);

Das Ergebnis ('iRes') hat die gleiche Bedeutung wie bei der vorherigen Funktion. So haben folgende Aufrufe z.B. alle das Ergebnis null (sind also in den ersten 'n' Buchstaben identisch):

strncmp("Hello", "Hallo", 1);
strncmp("Hello World!", "Hello", 5);

Die Methode 'sprintf':

Oft kommt es vor, dass man z.B. Zahlen in Form eines Strings aufnehmen muss. Da die Funktion sehr vielseitig ist werde ich mich hier auf einige Beispiele beschränken. Näheres lässt sich dann aus der MSDN entnehmen. Es lohnt sich auf jeden Fall.

Angenommen man besitzt verschiedene Daten einer Person (Name, Alter, Körpergröße), die in entsprechenden Variablen (strName, iAge, dSize) gespeichert sind und die sollen nun in Form einer Zeichenkette à la "<Name> (<Alter>) ist <Size> Meter groß." Liegen die entsprechenden Werte vor und ist die Variable 'str' in der diese Informationen gespeichert werden soll groß genug, dann lässt sich dieses Beispiel ganz einfach realisieren. Der gesamte Quelltext könnte so aussehen:

//Daten der Person
char strName[] = "Anna Schmidt";
int iAge = 35;
double dSize = 1.57;
//Zielstring
char str[101];

//Daten zusammenfassen
sprintf(str, "%s (%d) ist %.2f Meter gross.", strName, iAge, dSize);

//Ausgabe
cout << str << endl;

Interessant an diesem Quellcode ist lediglich die Funktion 'sprintf'. Der erste Parameter ist die gewünschte Variable, in der die Zeichenkette gespeichert werden soll. Der zweite Parameter ist eine konstante Zeichenkette, die neben den Zeichen, welche nachher tatsächlich in der Ausgabe erscheinen sollen auch zusammenhängende Zeichen besitzt, die allesamt mit einem '%' beginnen. Die unmittelbar darauffolgenden Zeichen liefern Informationen über die Werte und Datentypen welche hier in die Zeichenkette eingebunden werden sollen. So steht das '%s' für eine Zeichenkette ('char*'), das '%d' für eine (vorzeichenbehaftete) Ganzzahl ('int') und das '%f' für eine Kommazahl ('double'). Das '.2' innerhalb der letzten Informationsangabe bedeutet, dass bei  der Kommazahl maximal die ersten zwei Nachkommastellen mit aufgenommen werden. Die letzten drei Parameter besitzen dann die tatsächlichen Werte, die in der Zeichenkette eingebunden werden sollen. Für jede dieser Informationsangaben (à la '%x') muss eine eigene Variable entsprechenden Datentyps stehen. 

Die Daten über eine Person könnten natürlich auch erst während des Programms eingegeben werden. Dabei sollte aber Vor- und Nachname getrennt werden, da 'cin' Leerzeichen als neue Eingaben interpretiert. Das Programm könnte in etwa so aussehen:

//Daten der Person
char strName1[31];	//Vorname
char strName2[21];	//Nachname
int iAge = 0;
double dSize = 0;

//Zielstring
char str[101];	

//Eingeben der Daten
cout << "Nachname: "; cin >> strName2;
cout << "Vorname: "; cin >> strName1;
cout << "Alter: "; cin >> iAge;
cout << "Groesse: "; cin >> dSize;

//Daten zusammenfassen
sprintf(str, "%s %s (%d) ist %.2f Meter gross.", strName1, strName2, iAge, dSize);
	
//Ausgabe
cout << str << endl;

Mit Hilfe dieser Funktion lassen sich auch ganz einfach mehrere Zeichenketten miteinander verbinden. Dazu folgenden Quelltext:

//einige Zeichenketten
char strHello[] = "Hallo";
char strName0[] = "Anna";
char strName1[] = "Schmidt";
char str[100];
//Zeichenkette zusammenfügen
sprintf(str, "%s %s %s!", strHello, strName0, strName1);

//Zeichenkette ausgeben
cout << str << endl;

Wenn Sie noch mehr über diese Funktion wissen wollen, dann rate ich Ihnen mal in der MSDN unter <sprintf> und <Format Specifications> nachzuschlagen.

Escape Sequenzen

Einige Zeichen lassen sich gegenwärtig noch nicht in Zeichenketten aufnehmen. So z.B. Anführungszeichen (eizelne (') und doppelte (")), da sie Zeichenketten markieren. Versucht man also innerhalb einer Zeichenkette ein Anführungszeichen zu setzen, dann wäre die Zeichenkette an dieser Stelle zu Ende und der Rest erscheint dem Interpreter unverständlich und es kommt zum Kompilierfehler. Um solche Zeichen (und einige andere) dennoch anzeigen zu können gibt es die sogenannten "Escape Sequences". Sie beginnen alle mit einem einfache Backslash (\) worauf dann das gewünschte Zeichen folgt. In der folgenden Tabelle werden die wichtigsten aufgeführt:

Escape Sequenz Bedeutung

\a

bei der Ausgabe wird ein Piepton erzeugt
\n Zeilenumbruch
\' einzelnes Anführungszeichen (')
\" doppeltes Anführungszeichen (")
\\ Backslash (\)

Dazu folgendes Beispiel:

cout << "\"Hello World!\"\a\n";

Wie normal wird "Hello World!" ausgegeben. Dieses Mal aber in Anführungszeichen und von einem Piepton begleitet. Außerdem kommt es (trotz fehlendem 'endl') zum Zeilenumbruch.

Für die nächsten Lektionen

Zeichenketten werden in den folgenden Kapiteln immer mal wieder zum Tragen kommen, da sie für unerläßlich sind, wenn es um Interaktion zwischen Benutzer und Programm kommt. Ihre Funktionalität sollte (soweit sie hier besprochen wurde) im folgenden bekannt sein.

Zurück Nach oben Weiter