vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbacknächstes Kapitel


Woche 3

Tag 16

Stringmanipulatio n

Textdaten, die in Strings gespeichert werden, sind ein wichtiger Bestandteil vieler Programme. Sie wissen bereits, wie Sie in einem C-Programm Strings speichern und wie Sie Strings einlesen und ausgeben. Darüber hinaus gibt es aber noch eine Vielzahl von speziellen C-Funktionen, mit denen Sie weitere Stringmanipulationen vornehmen können. Heute lernen Sie:

Stringlänge und Stringspeicherung

Aus den vorangehenden Kapiteln sollten Sie wissen, dass Strings in C als eine Folge von Zeichen definiert sind, auf deren Anfang ein Zeiger weist und deren Ende durch das Nullzeichen \0 markiert ist. In bestimmten Situationen ist es jedoch erforderlich, auch die Länge eines Strings zu kennen - das heißt die Anzahl der im String enthaltenen Zeichen. Die Länge eines Strings lässt sich mit Hilfe der Bibliotheksfunktion strlen() ermitteln. Der Prototyp, der in string.h deklariert ist, lautet:

size_t strlen(char *str);

Vielleicht wundern Sie sich über den Rückgabetyp von size_t. Dieser Typ ist auf den meisten Systemen als unsigned int definiert, kann aber auf Computern mit 64-Bit- Prozessoren auch unsigned long sein. Der size_t-Typ wird von vielen Stringfunktionen verwendet. Sie sollten sich vor allem merken, dass der Typ nicht vorzeichenbehaftet (unsigned) ist.

Als Argument übergibt man strlen einen Zeiger auf den String, dessen Länge ermittelt werden soll. Als Ergebnis liefert die Funktion strlen() die Anzahl der Zeichen zwischen str und dem nächsten Nullzeichen zurück (wobei das Nullzeichen selbst nicht mitgezählt wird). In Listing 16.1 sehen Sie ein Beispiel zu strlen().

Listing 16.1: Mit der Funktion strlen() die Länge eines Strings ermitteln.

1: /* Einsatz der Funktion strlen(). */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: int main(void)
7: {
8: size_t laenge;
9: char puffer[80];
10:
11: while (1)
12: {
13: puts("\nGeben Sie eine Textzeile ein, Beenden mit Leerzeile.");
14: fgets(puffer,80,stdin);
15:
16: laenge = strlen(puffer);
17:
18: if (laenge > 1)
19: printf("Die Zeile ist %u Zeichen lang.\n", laenge-1);
20: else
21: break;
22: }
23: return(0);
24: }

Geben Sie eine Textzeile ein, Beenden mit Leerzeile.
Nur keine Angst!

Die Zeile ist 16 Zeichen lang.
Geben Sie eine Textzeile ein, Beenden mit Leerzeile.

Dieses Programm dient lediglich dazu, den Einsatz von strlen() zu demonstrieren. Die Zeilen 13 und 14 geben eine Eingabeaufforderung aus und lesen einen Text in den String puffer ein. In Zeile 16 wird der Variablen laenge mit Hilfe von strlen() die Länge des Strings puffer zugewiesen. In Zeile 18 wird sichergestellt, dass der String nicht leer, sprich seine Länge größer als 1 ist. Denken Sie daran, dass fgets() die über die Tastatur eingegebene Zeile mitsamt dem Neue-Zeile-Zeichen zurückgibt. Deshalb enthalten selbst Leerzeilen ein Zeichen: das Neue-Zeile-Zeichen. Wenn der String nicht leer ist, wird in Zeile 19 die Größe des Strings ausgegeben.

Strings kopieren

In der C-Bibliothek gibt es drei Funktionen zum Kopieren von Strings. Aufgrund der Art und Weise, wie Strings in C gehandhabt werden, können Sie nicht einfach einen String einem anderen zuweisen, wie das in einigen anderen Computersprachen möglich ist, sondern müssen den Quellstring von seiner Position im Speicher in den Speicherbereich des Zielstrings kopieren. Die Kopierfunktionen für Strings lauten strcpy(), strncpy() und strdup(). Wenn Sie eine dieser drei Funktionen verwenden wollen, müssen Sie die Header-Datei string.h einbinden.

Die Funktion strcpy()

Die Bibliotheksfunktion strcpy() kopiert einen ganzen String an eine neue Speicherstelle. Der Prototyp lautet:

char *strcpy( char *destination, char *source );

Die Funktion strcpy() kopiert den String (einschließlich des abschließenden Nullzeichens \0), auf den source1 zeigt, an die Speicherstelle, auf die destination2 zeigt. Der Rückgabewert ist ein Zeiger auf den neuen String namens destination.

Wenn Sie strcpy() verwenden, müssen Sie zuerst Speicherplatz für den Zielstring reservieren. Die Funktion hat keine Möglichkeit, herauszufinden, ob destination auf einen reservierten Speicherplatz zeigt. Wenn kein Speicher zugewiesen wurde, wird die Funktion wahrscheinlich einen Segmentierungsfehler auslösen, da Ihr Programm versucht, auf Speicher zuzugreifen, der ihm nicht gehört. Der Einsatz von strcpy() wird in Listing 16.2 demonstriert.

Verantwortungsbewusste Programmierer geben Speicher, der wie in Listing 16.2 mit malloc() reserviert wurde, spätestens am Ende des Programms mit der Funktion free() frei. Mehr über free() erfahren Sie am Tag 18, »Vom Umgang mit dem Speicher«.

Listing 16.2: Vor dem Einsatz von strcpy() müssen Sie Speicher für den Zielstring reservieren.

1: /* Beispiel für strcpy(). */
2: #include <stdlib.h>
3: #include <stdio.h>
4: #include <string.h>
5:
6: char quelle[] = "Der Quellstring.";
7:
8: int main(void)
9: {
10: char ziel1[80];
11: char *ziel2, *ziel3;
12:
13: printf("Quelle: %s\n", quelle );
14:
15: /* Kopieren in ziel1 OK, da ziel1 auf 80 Bytes */
16: /* reservierten Speicher zeigt. */
17:
18: strcpy(ziel1, quelle);
19: printf("Ziel1: %s\n", ziel1);
20:
21: /* Um in ziel2 zu kopieren, müssen Sie Speicher reservieren. */
22:
23: ziel2 = (char *)malloc(strlen(quelle) +1);
24: strcpy(ziel2, quelle);
25: printf("Ziel2: %s\n", ziel2);
26:
27: /* Nicht kopieren, ohne Speicher für den Zielstring zu reservieren*/
28: /* Der folgende Code kann schwerwiegende Fehler verursachen. */
29:
30: /* strcpy(ziel3, quelle); */
31: return(0);
32: }

Quelle: Der Quellstring.
Ziel1: Der Quellstring.
Ziel2: Der Quellstring.

Dieses Programm zeigt, wie man Strings sowohl in Zeichenarrays (ziel1, deklariert in Zeile 10) als auch in Zeichenzeiger kopiert (ziel2 und ziel3, deklariert in Zeile 11). Zeile 13 gibt den ursprünglichen Quellstring aus. Dieser String wird dann mit Hilfe von strcpy() in ziel1 kopiert (Zeile 18). Zeile 24 kopiert quelle in ziel2. Sowohl ziel1 als auch ziel2 werden ausgegeben, um zu beweisen, dass die Funktionsaufrufe erfolgreich waren. Beachten Sie den Aufruf von malloc() in Zeile 23. Hier wird Speicher für den Zeichenzeiger ziel2 reserviert, damit dieser die Kopie von source aufnehmen kann. Wenn Sie einen String in einen Zeichenzeiger kopieren, für den kein oder nur unzureichend Speicher reserviert wurde, kann dies unerwartete Folgen haben.

Die Funktion strncpy()

Die Funktion strncpy() entspricht weitgehend der Funktion strcpy(). Im Unterschied zu strcpy() können Sie bei strncpy() aber angeben, wie viele Zeichen Sie kopieren wollen. Der Prototyp lautet:

char *strncpy(char *destination, char *source, size_t n);

Die Argumente destination und source sind Zeiger auf die Ziel- und Quellstrings. Die Funktion kopiert maximal die ersten n Zeichen von source nach destination. Wenn source kürzer als n Zeichen ist, wird source mit so vielen Nullzeichen aufgefüllt, dass insgesamt n Zeichen nach destination kopiert werden können. Wenn source länger als n Zeichen ist, wird an destination kein abschließendes Nullzeichen angehängt. Der Rückgabewert der Funktion ist der Zeiger destination.

Listing 16.3 enthält ein Beispiel für die Verwendung von strncpy().

Listing 16.3: Die Funktion strncpy().

1: /* Die Funktion strncpy(). */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: char ziel[] = "..........................";
7: char quelle[] = "abcdefghijklmnopqrstuvwxyz";
8:
9: int main(void)
10: {
11: size_t n;
12:
13: while (1)
14: {
15: puts("Anzahl der Zeichen, die kopiert werden sollen (1-26)");
16: scanf("%d", &n);
17:
18: if (n > 0 && n< 27)
19: break;
20: }
21:
22: printf("Ziel vor Aufruf von strncpy = %s\n", ziel);
23:
24: strncpy(ziel, quelle, n);
25:
26: printf("Ziel nach Aufruf von strncpy = %s\n", ziel);
27: return(0);
28: }

Anzahl der Zeichen, die kopiert werden sollen (1-26)
15
Ziel vor Aufruf von strncpy = ..........................
Ziel nach Aufruf von strncpy = abcdefghijklmno...........

Dieses Programm zeigt nicht nur, wie man strncpy() verwendet, sondern auch wie man sicherstellt, dass nur korrekte Daten vom Anwender eingelesen werden. Die Zeilen 13 bis 20 enthalten eine while-Schleife, die den Anwender auffordert, eine Zahl zwischen 1 und 26 einzugeben. Die Schleife wird so lange durchlaufen, bis ein gültiger Wert eingegeben wird - vorher wird das Programm nicht fortgeführt. Nach Eingabe einer Zahl zwischen 1 und 26 gibt Zeile 22 den ursprünglichen Wert von ziel aus, Zeile 24 kopiert die vom Anwender gewünschte Anzahl Zeichen von quelle nach ziel und Zeile 26 gibt den fertigen Wert von ziel aus.

Stellen Sie sicher, dass die Anzahl der kopierten Zeichen nicht die reservierte Größe des Zielstrings überschreitet, und denken Sie daran, dass für das Nullzeichen am Ende des Strings Platz gelassen werden muss.

Die Funktion strdup()

Die Bibliotheksfunktion strdup()entspricht weitgehend der Funktion strcpy(). Die Funktion strdup() sorgt allerdings selbst dafür, dass für den Zielstring Speicher reserviert wird, indem sie intern malloc() aufruft. Dies entspricht unserer Vorgehensweise in Listing 16.2, wo wir zuerst durch Aufruf von malloc() Speicher reserviert und dann strcpy() aufgerufen haben. Der Prototyp für strdup() lautet:

char *strdup( char *source );

Das Argument source ist ein Zeiger auf den Quellstring. Die Funktion liefert einen Zeiger auf den Zielstring zurück - das heißt den Speicherbereich, der von malloc() reserviert wurde - oder NULL, wenn der benötigte Speicherbereich nicht reserviert werden kann. Listing 16.4 zeigt ein Beispiel für strdup(). Beachten Sie, dass die Funktion strdup() nicht zum ANSI/ISO-Standard gehört. Sie ist aber auf Linux und vielen anderen Betriebssystemen verfügbar.

Listing 16.4: strdup() kopiert einen String mit automatischer Speicherreservierung.

1: /* Die Funktion strdup(). */
2: #include <stdlib.h>
3: #include <stdio.h>
4: #include <string.h>
5:
6: char quelle[] = "Der Quellstring.";
7:
8: int main(void)
9: {
10: char *ziel;
11:
12: if ( (ziel = strdup(quelle)) == NULL)
13: {
14: fprintf(stderr, "Fehler bei der Speicherresevierung.\n");
15: exit(1);
16: }
17:
18: printf("Das Ziel = %s\n", ziel);
19: return(0);
20: }

Das Ziel = Der Quellstring.

In diesem Listing reserviert strdup() den notwendigen Speicher für ziel. Erst danach wird der übergebene String source kopiert. Zeile 18 gibt den kopierten String aus.

Strings konkatenieren

Wenn Sie den Begriff Konkatenierung nicht kennen, werden Sie sich sicherlich fragen, was das ist und ob es überhaupt legal ist. Konkatenierung bedeutet einfach, zwei Strings miteinander zu verbinden, indem man einen String an das Ende eines anderen Strings anhängt - was fast überall auf der Welt erlaubt ist. Die C- Standardbibliothek enthält zwei Funktionen zur Stringverkettung: strcat() und strncat(). Beide Funktionen benötigen die Header-Datei string.h.

Die Funktion strcat()

Der Prototyp von strcat() lautet:

char *strcat(char *str1, char *str2);

Die Funktion hängt eine Kopie von str2 an das Ende von str1 und verschiebt das abschließende Nullzeichen an das Ende des neuen Strings. Sie müssen für str1 genügend Speicher reservieren, damit str1 den neuen String aufnehmen kann. Der Rückgabewert von strcat() ist ein Zeiger auf str1. Ein Beispiel für strcat() finden Sie in Listing 16.5.

Listing 16.5: Mit strcat() Strings verketten.

1: /* Die Funktion strcat(). */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: char str1[27] = "a";
7: char str2[2];
8:
9: int main(void)
10: {
11: int n;
12:
13: /* Schreibt ein Nullzeichen an das Ende von str2[]. */
14:
15: str2[1] = '\0';
16:
17: for (n = 98; n< 123; n++)
18: {
19: str2[0] = n;
20: strcat(str1, str2);
21: puts(str1);
22: }
23: return(0);
24: }

ab
abc
abcd
abcde
abcdef
abcdefg
abcdefgh
abcdefghi
abcdefghij
abcdefghijk
abcdefghijkl
abcdefghijklm
abcdefghijklmn
abcdefghijklmno
abcdefghijklmnop
abcdefghijklmnopq
abcdefghijklmnopqr
abcdefghijklmnopqrs
abcdefghijklmnopqrst
abcdefghijklmnopqrstu
abcdefghijklmnopqrstuv
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvwx
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxyz

Die Zahlen von 98 bis 122 entsprechen den ASCII-Codes für die Buchstaben b-z. Das Programm verwendet diese ASCII-Codes, um die Arbeitsweise von strcat() zu verdeutlichen. Die for-Schleife in den Zeilen 17 bis 22 weist diese ASCII-Codes der Reihe nach str2[0] zu. Da str2[1] bereits das Nullzeichen zugewiesen wurde (Zeile 15), enthält str2 nacheinander die Strings »b«, »c« und so weiter. Jeder dieser Strings wird danach mit str1 verkettet (Zeile 20), dessen Inhalt dann in Zeile 21 auf dem Bildschirm ausgegeben wird.

Die Funktion strncat()

Die Bibliotheksfunktion strncat() führt ebenfalls eine Stringverkettung durch, erlaubt Ihnen jedoch anzugeben, wie viele Zeichen des Quellstrings an das Ende des Zielstrings angehängt werden sollen. Der Prototyp lautet:

char *strncat(char *str1, char *str2, size_t n);

Wenn str2 mehr als n Zeichen enthält, werden die ersten n Zeichen an das Ende von str1 angehängt. Wenn str2 weniger als n Zeichen enthält, wird str2 als Ganzes an das Ende von str1 gehängt. In beiden Fällen wird ein abschließendes Nullzeichen an das Ende des resultierenden Strings angehängt. Sie müssen für str1 genügend Speicher reservieren, damit der Ergebnisstring aufgenommen werden kann. Die Funktion liefert einen Zeiger auf str1 zurück. In Listing 16.6 nutzen wir strncat(), um die gleiche Ausgabe zu erzeugen wie in Listing 16.5.

Listing 16.6: Mit der Funktion strncat() Strings verketten.

1: /* Die Funktion strncat(). */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: char str2[] = "abcdefghijklmnopqrstuvwxyz";
7:
8: int main(void)
9: {
10: char str1[27];
11: int n;
12:
13: for (n=1; n< 27; n++)
14: {
15: strcpy(str1, "");
16: strncat(str1, str2, n);
17: puts(str1);
18: }
19: return(0);
20: }

a
ab
abc
abcd
abcde
abcdef
abcdefg
abcdefgh
abcdefghi
abcdefghij
abcdefghijk
abcdefghijkl
abcdefghijklm
abcdefghijklmn
abcdefghijklmno
abcdefghijklmnop
abcdefghijklmnopq
abcdefghijklmnopqr
abcdefghijklmnopqrs
abcdefghijklmnopqrst
abcdefghijklmnopqrstu
abcdefghijklmnopqrstuv
abcdefghijklmnopqrstuvw
abcdefghijklmnopqrstuvwx
abcdefghijklmnopqrstuvwxy
abcdefghijklmnopqrstuvwxyz

Vielleicht fragen Sie sich, wozu die Zeile 15, strcpy(str1, ""); benötigt wird. Diese Zeile kopiert einen leeren String, der nur aus einem einzigen Nullzeichen besteht, nach str1. Das Ergebnis ist, dass das erste Zeichen in str1 - str1[0] - gleich 0 (dem Nullzeichen) gesetzt wird. Das Gleiche hätten Sie auch mit der Anweisung str1[0] = 0; oder str1[0] = '\0'; erreichen können.

Strings vergleichen

Durch Stringvergleiche kann man festzustellen, ob zwei Strings gleich oder nicht gleich sind. Sind sie nicht gleich, dann ist ein String größer oder kleiner als der andere. Um zu entscheiden, ob ein String größer oder kleiner als ein anderer Strings ist, werden die ASCII-Codes der Zeichen in den Strings herangezogen. Für Buchstaben folgen die ASCII-Codes der Reihenfolge der Buchstaben im Alphabet, mit der einen seltsam anmutenden Ausnahme, dass alle Großbuchstaben einen kleineren Wert haben als die Kleinbuchstaben. Das liegt daran, dass Großbuchstaben die ASCII- Codes 65-90 für A-Z haben, wohingegen die Kleinbuchstaben a-z durch die Werte 97-122 dargestellt werden. Demzufolge ist »ZEBRA« kleiner als »heute« - zumindest wenn man die C-Funktionen verwendet.

Die ANSI/ISO-Bibliothek enthält Funktionen für zwei Arten von Stringvergleichen: Vergleich zweier ganzer Strings und Vergleich der ersten n Zeichen zweier Strings.

Zwei komplette Strings vergleichen

Die Funktion strcmp() vergleicht zwei Strings, Zeichen für Zeichen. Der Prototyp lautet:

int strcmp(char *str1, char *str2);

Die Argumente str1 und str2 sind Zeiger auf die Strings, die verglichen werden sollen. Die Rückgabewerte der Funktion finden Sie in Tabelle 16.1. Listing 16.7 enthält ein Beispiel für strcmp().

Rückgabewert

Bedeutung

< 0

str1 ist kleiner als str2.

0

str1 ist gleich str2.

> 0

str1 ist größer als str2.

Tabelle 16.1: Die Rückgabewerte von strcmp().

Listing 16.7: Mit strcmp() Strings vergleichen.

1: /* Die Funktion strcmp(). */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: int main(void)
7: {
8: char str1[80], str2[80];
9: int x;
10:
11: while (1)
12: {
13: /* Zwei Strings einlesen. */
14:
15: printf("\n\nErster String (mit Eingabetaste beenden): ");
16: fgets(str1,80,stdin);
17: str1[strlen(str1)-1] = 0;
18:
19: if ( strlen(str1) < 2 )
20: break;
21:
22: printf("\nZweiter String: ");
23: fgets(str2,80,stdin);
24: str2[strlen(str2)-1] = 0;
25:
26: /* Strings vergleichen und Ergebnis ausgeben. */
27:
28: x = strcmp(str1, str2);
29:
30: printf("\nstrcmp(%s,%s) liefert %d zurück", str1, str2, x);
31: }
32: return(0);
33: }

Erster String (mit Eingabetaste beenden): Erster String 

Zweiter String: Zweiter String

strcmp(Erster String,Zweiter String) liefert -21 zurück

Erster String (mit Eingabetaste beenden): Test-String

Zweiter String: Test-String

strcmp(test string,test string) liefert 0 zurück

Ersten String eingeben oder mit Eingabetaste beenden: zebra

Zweiten String eingeben: aardvark

strcmp(zebra,aardvark) liefert 25 zurück

Erster String (mit Eingabetaste beenden):

Auf manchen Systemen, wie zum Beispiel Windows, lauten die Rückgabewerte der Funktionen zum Vergleichen von Strings -1, 0 oder 1 anstatt der hier ausgegebenen Werte. Der Wert für ungleich lange Strings wird jedoch immer ungleich Null sein.

Dieses Programm möchte Ihnen die Funktionsweise von strcmp() veranschaulichen und fordert Sie deshalb auf, zwei Strings einzugeben (Zeilen 15 und 22). Zeile 30 gibt das von strcmp() zurückgegebene Ergebnis auf dem Bildschirm aus. Die Zeilen 17 und 24 entfernen die Neue-Zeile-Zeichen aus den Strings, die von der Funktion fgets() zurückgeliefert werden.

Spielen Sie ein wenig mit diesem Programm herum, um ein Gefühl dafür zu bekommen, wie man mit strcmp() Strings vergleichen kann. Geben Sie zwei Strings ein, die bis auf die Groß- und Kleinschreibung identisch sind (zum Beispiel Morgen und morgen). Sie werden feststellen, dass strcmp() die Groß- und Kleinschreibung berücksichtigt, das heißt, Groß- und Kleinbuchstaben haben jeweils unterschiedliche Werte.

Teilstrings vergleichen

Die Bibliotheksfunktion strncmp() vergleicht eine bestimmte Anzahl von Zeichen eines Strings mit den Zeichen eines anderen Strings. Der Prototyp lautet:

int strncmp(char *str1, char *str2, size_t n);

Die Funktion strncmp() vergleicht n Zeichen von str2 mit str1. Der Vergleich wird abgeschlossen, wenn n Zeichen verglichen oder das Ende von str1 erreicht ist. Ansonsten entsprechen das Vergleichsverfahren und die Rückgabewerte denen von strcmp(). Der Vergleich berücksichtigt die Groß- und Kleinschreibung. Listing 16.8 demonstriert die Verwendung der Funktion strncmp().

Listing 16.8: Mit der Funktion strncmp() Teilstrings vergleichen.

1: /* Die Funktion strncmp(). */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: char str1[] = "Der erste String.";
7: char str2[] = "Der zweite String.";
8:
9: int main(void)
10: {
11: size_t n, x;
12:
13: puts(str1);
14: puts(str2);
15:
16: while (1)
17: {
18: puts("Anzahl der zu vergleichenden Zeichen (0 für Ende):");
19: scanf("%d", &n);
20:
21: if (n <= 0)
22: break;
23:
24: x = strncmp(str1, str2, n);
25:
26: printf("Bei Vergleich von %d Zeichen liefert strncmp() %d.\n\n",
n, x);
27: }
28: return(0);
29: }

Der erste String.
Der zweite String.

Anzahl der zu vergleichenden Zeichen (0 für Ende):
3

Bei Vergleich von 3 Zeichen liefert strncmp() 0.

Anzahl der zu vergleichenden Zeichen (0 für Ende):
6

Bei Vergleich von 6 Zeichen liefert strncmp() -21.

Anzahl der zu vergleichenden Zeichen (0 für Ende):
0

Dieses Programm vergleicht die beiden Strings, die in den Zeilen 6 und 7 definiert werden. Die Zeilen 13 und 14 geben die Strings auf dem Bildschirm aus, so dass der Anwender sehen kann, was verglichen wird. Das Programm tritt in den Zeilen 16 bis 27 in eine while-Schleife ein, die es erlaubt, mehrere Vergleiche nacheinander durchzuführen. Wenn der Anwender in den Zeilen 18 und 19 angibt, dass null Zeichen verglichen werden sollen, wird die Schleife in Zeile 22 beendet. Andernfalls wird in Zeile 24 die Funktion strncmp() ausgeführt und das Ergebnis in Zeile 26 ausgegeben.

Zwei Strings ohne Berücksichtigung der Groß- und Kleinschreibung vergleichen

Leider enthält die ANSI/ISO-C-Bibliothek keine Funktionen für Stringvergleiche, die die Groß- und Kleinschreibung unberücksichtigt lassen. Linux stellt als Ersatz die Funktion strcasecmp() zur Verfügung, doch ist diese nicht unbedingt auf anderen Unix-Systemen verfügbar. Vergleichsfunktionen, die nicht zwischen Groß- und Kleinschreibung unterscheiden, betrachten Strings wie Schmidt und SCHMIDT als gleich. Um sich selbst von der Arbeitsweise von strcasecmp() zu überzeugen, ersetzen Sie den strcmp()-Aufruf in Zeile 28 von Listing 16.7 durch strcasecmp() und starten das Programm erneut.

Strings durchsuchen

Die C-Bibliothek enthält eine Reihe von Funktionen für das Durchsuchen von Strings. Mit diesen Funktionen können Sie feststellen, ob und wo ein String innerhalb eines anderen Strings enthalten ist. Sie haben die Wahl zwischen sechs verschiedenen Suchfunktionen, die alle in der Header-Datei string.h deklariert sind.

Die Funktion strchr()

Die Funktion strchr() sucht nach dem ersten Vorkommen eines angegebenen Zeichens in einem String. Der Prototyp lautet:

char *strchr(char *str, int ch);

Die Funktion strchr() durchsucht str von links nach rechts, bis das Zeichen ch oder das abschließende Nullzeichen gefunden wird. Wird ein Vorkommen von ch gefunden, liefert die Funktion einen Zeiger darauf zurück. Ansonsten lautet der Rückgabewert NULL.

Wenn strchr() das gesuchte Zeichen findet, liefert sie einen Zeiger auf das Zeichen zurück. Da str ein Zeiger auf das erste Vorkommen des Zeichens im String ist, ist es nicht schwierig, die Position des gefundenen Zeichens zu ermitteln: Subtrahieren Sie einfach str von dem Zeigerwert, der von strchr() zurückgegeben wird. Denken Sie daran, dass sich das erste Zeichen in einem String an der Position 0 befindet. Wie die meisten Stringfunktionen von C berücksichtigt auch strchr() die Groß- und Kleinschreibung (weshalb zum Beispiel das Zeichen F in dem String Kaffee nicht gefunden wird).

Listing 16.9: Mit strchr() ein einfaches Zeichen in einem String suchen.

1: /* Mit strchr() nach einem einfachen Zeichen suchen. */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: int main(void)
7: {
8: char *loc, puffer[80];
9: int ch;
10:
11: /* Den String und das Zeichen eingeben. */
12:
13: printf("Geben Sie den String ein, der durchsucht werden soll: ");
14: fgets(puffer,80,stdin);
15: printf("Geben Sie das Zeichen ein, nach dem gesucht werden soll: ");
16: ch = getchar();
17:
18: /* Suche durchführen. */
19:
20: loc = strchr(puffer, ch);
21:
22: if ( loc == NULL )
23: printf("Das Zeichen %c wurde nicht gefunden.\n", ch);
24: else
25: printf("Das Zeichen %c wurde an der Position %d gefunden.\n",
26: ch, (int)(loc-puffer));
27: return(0);
28: }

Geben Sie den String ein, der durchsucht werden soll: Alles klar auf der Andrea Doria?
Geben Sie das Zeichen ein, nach dem gesucht werden soll: D
Das Zeichen D wurde an der Position 26 gefunden.

Dieses Programm verwendet strchr() in Zeile 20, um einen String nach einem Zeichen zu durchsuchen. strchr() liefert einen Zeiger auf die Position zurück, an der das Zeichen das erste Mal gefunden wird, oder NULL, wenn das gesuchte Zeichen nicht gefunden wird. Zeile 22 prüft, ob der Wert von loc NULL ist, und gibt eine entsprechende Nachricht aus. Wie bereits im Abschnitt »Die Funktion strchr()« beschrieben wurde, ermittelt man die Position des Zeichens im String, indem man den Stringzeiger von dem Wert subtrahiert, der von der Funktion zurückgeliefert wird.

Die Funktion strrchr()

Die Bibliotheksfunktion strrchr() entspricht strchr(), sucht aber nach dem letzten Vorkommen eines angegebenen Zeichens. Mit anderen Worten, die Suche beginnt am Ende des Strings. Der Prototyp lautet:

char *strrchr(char *str, int ch);

Die Funktion strrchr() liefert einen Zeiger auf das letzte Vorkommen von ch in str zurück oder NULL, wenn keine Übereinstimmung gefunden wurde. Ändern Sie in Listing 16.9 in der Zeile 20 den Aufruf von strchr() in strrchr(), um sich einen Eindruck zu verschaffen, wie diese Funktion arbeitet.

Die Funktion strcspn()

Die Bibliotheksfunktion strcspn() durchsucht einen String nach dem ersten Vorkommen eines der Zeichen in einem zweiten String. Der Prototyp lautet:

size_t strcspn(char *str1, char *str2);

Die Funktion strcspn() beginnt die Suche mit dem ersten Zeichen von str1 und sucht nach allen Zeichen, die in str2 enthalten sind. Beachten Sie, dass die Funktion nicht nach dem String str2 sucht, sondern nur nach den einzelnen Zeichen, die er enthält. Wenn die Funktion eine Übereinstimmung feststellt, wird die Position des Zeichens in str1 zurückgeliefert. Wird keine Übereinstimmung gefunden, liefert strcspn() den Wert von strlen(str1) zurück. Damit wird angezeigt, dass die erste Übereinstimmung das Nullzeichen war, das den String abgeschlossen hat. Listing 16.10 demonstriert, wie Sie strcspn() einsetzen können.

Listing 16.10: Mit strcspn() nach einem Satz von Zeichen suchen.

1: /* Mit strcspn() suchen. */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: int main(void)
7: {
8: char puffer1[80], puffer2[80];
9: size_t loc;
10:
11: /* Strings eingeben. */
12:
13: printf("Geben Sie den String ein, der durchsucht werden soll: ");
14: fgets(puffer1,80,stdin);
15: printf("Geben Sie den String mit den zu suchenden Zeichen ein: ");
16: fgets(puffer2,80,stdin);
17: puffer2[strlen(puffer2)-1] = 0; /*Entfernt das Neue-Zeile-Zeichen*/
18:
19: /* Suche durchführen. */
20: loc = strcspn(puffer1, puffer2);
21:
22: if ( loc == strlen(puffer1) )
23: printf("Es wurde keine Übereinstimmung gefunden.\n");
24: else
25: printf("Erste Übereinstimmung an Position %d.\n", loc);
26: return(0);
27: }

Geben Sie den String ein, der durchsucht werden soll: Alles klar auf der Andrea Doria?
Geben Sie den String mit den zu suchenden Zeichen ein: Das
Erste Übereinstimmung an Position 4.

Dieses Listing ist dem Listing 16.10 sehr ähnlich. Anstatt nach dem ersten Vorkommen eines einzigen Zeichens zu suchen, sucht es nach dem ersten Vorkommen eines der Zeichen im zweiten String. Das Programm ruft strcspn() in Zeile 20 mit puffer1 und puffer2 auf. Wenn irgendwelche der Zeichen in puffer2 auch in puffer1 vorkommen, liefert strcspn() die Position des ersten gefundenen Vorkommens in str1 zurück. Zeile 22 prüft, ob der Rückgabewert gleich strlen(puffer1) ist. Ist der Wert strlen(puffer1), wurden keine Zeichen gefunden, und eine entsprechende Nachricht wird in Zeile 23 ausgegeben. Wenn ein Wert gefunden wurde, wird die Position des Zeichens im String ausgegeben.

Die Funktion strspn()

Diese Funktion ist, wie Sie gleich sehen werden, eng mit der obigen Funktion, strcspn(), verbunden. Der Prototyp lautet:

size_t strspn(const char *str, char *accept);

Die Funktion strspn() durchsucht str und vergleicht den String Zeichen für Zeichen mit den Zeichen in accept. Als Ergebnis liefert die Funktion die Position des ersten Zeichens in str zurück, das nicht mit einem Zeichen in accept übereinstimmt. Mit anderen Worten, strspn() liefert die Länge des ersten Abschnitts von str zurück, der gänzlich aus Zeichen besteht, die in accept enthalten sind. Gibt es keine Übereinstimmung, lautet der Rückgabewert 0. Ein Beispiel für die Verwendung von strspn() finden Sie in Listing 16.11.

Listing 16.11: Mit strspn() nach dem ersten nicht übereinstimmenden Zeichen suchen.

1: /* Mit strspn() suchen. */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: int main(void)
7: {
8: char puffer1[80], puffer2[80];
9: size_t loc;
10:
11: /* Strings eingeben. */
12:
13: printf("Geben Sie den String ein, der durchsucht werden soll: ");
14: fgets(puffer1,80,stdin);
15: printf("Geben Sie den String mit den zu suchenden Zeichen ein: ");
16: fgets(puffer2,80,stdin);
17: puffer2[strlen(puffer2)-1] = 0; /*Entfernt das Neue-Zeile-Zeichen*/
18:
19: /* Suche durchführen. */
20: loc = strspn(puffer1, puffer2);
21:
22: if ( loc == 0 )
23: printf("Es wurde keine Übereinstimmung gefunden.\n");
24: else
25: printf("Die Zeichen stimmen bis Position %d überein.\n", loc-1);
26: return 0;
27: }

Geben Sie den String ein, der durchsucht werden soll: Alles klar auf der Andrea Doria?
Geben Sie den String mit den zu suchenden Zeichen ein: Alles klar oder?
Die Zeichen stimmen bis Position 11 überein.

Dieses Programm entspricht unserem obigen Beispiel, außer das in Zeile 20 die Funktion strspn() statt strcspn() aufgerufen wird und in Zeile 22 die Abfrage des Rückgabewertes von strspn() auf 0 geändert wurde. Die Funktion gibt die Position des ersten Zeichens von puffer1 zurück, das nicht in puffer2 enthalten ist. Die Zeilen 22 bis 25 werten den Rückgabewert aus und geben eine entsprechende Nachricht aus.

Die Funktion strpbrk()

Die Bibliotheksfunktion strpbrk() ist der Funktion strcspn() sehr ähnlich. Sie durchsucht einen String nach dem ersten Vorkommen eines der Zeichen eines anderen Strings. Der Unterschied zu strcspn() liegt darin, dass die abschließenden Nullzeichen nicht in die Suche mit einbezogen werden. Der Prototyp der Funktion lautet:

char *strpbrk(char *str, char *accept);

Die Funktion strpbrk() liefert einen Zeiger auf das erste Zeichen in str zurück, das einem der Zeichen in accept entspricht. Wird keine Übereinstimmung gefunden, liefert die Funktion NULL zurück. Wie schon bei der Funktion strchr() erläutert, berechnet man die Position der ersten Übereinstimmung in str, indem man den Zeiger str von dem Zeiger, der von strpbrk() zurückgeliefert wird, subtrahiert (was natürlich nur geht, wenn der Wert ungleich NULL ist). Ersetzen Sie doch einfach mal die Funktion strcspn() aus Zeile 20 des Listings 16.10 durch strpbrk().

Die Funktion strstr()

Die letzte und vielleicht nützlichste C-Funktion zum Durchsuchen von Strings ist strstr(). Diese Funktion sucht nach dem ersten Vorkommen eines Strings in einem anderen String, wobei nach dem ganzen String und nicht nur nach den einzelnen Zeichen innerhalb des Strings gesucht wird. Der Prototyp lautet:

char *strstr(char *haystack, char *needle);

Die Funktion strstr() liefert einen Zeiger auf das erste Vorkommen von needle3 in haystack4. Wird keine Übereinstimmung gefunden, liefert die Funktion NULL zurück. Wenn die Länge von needle 0 ist, liefert die Funktion haystack zurück. Wenn strstr() eine Übereinstimmung findet, können Sie die Position des ersten Vorkommens von needle berechnen, indem Sie die Zeiger, wie bereits für strchr() erläutert, voneinander subtrahieren. Die Funktion strstr() berücksichtigt die Groß- und Kleinschreibung. In Listing 16.12 sehen Sie ein Beispiel für strstr().

Listing 16.12: Mit strstr() nach einem String in einem String suchen.

1: /* Mit strstr() suchen. */
2:
3: #include <stdio.h>
4: #include <string.h>
5:
6: int main(void)
7: {
8: char *loc, puffer1[80], puffer2[80];
9:
10: /* Strings eingeben. */
11:
12: printf("Geben Sie den String ein, der durchsucht werden soll: ");
13: fgets(puffer1,80,stdin);
14: printf("Geben Sie den zu suchenden String ein: ");
15: fgets(puffer2,80,stdin);
16: puffer2[strlen(puffer2)-1] = 0; /*Entfernt das Neue-Zeile-Zeichen*/
17:
18: /* Suche durchführen. */
19: loc = strstr(puffer1, puffer2);
20:
21: if ( loc == NULL )
22: printf("Es wurde keine Übereinstimmung gefunden.\n");
23: else
24: printf("%s wurde an Position %d gefunden.\n",puffer2,loc-puffer1);
25: return(0);
26: }

Geben Sie den String ein, der durchsucht werden soll: Alles klar auf der Andrea Doria?
Geben Sie den zu suchenden String ein: auf
auf wurde an Position 11 gefunden.

Diese Funktion bietet eine weitere Möglichkeit, einen String zu durchsuchen. Diesmal können Sie einen kompletten String innerhalb eines anderen Strings suchen. In den Zeilen 12 bis 15 wird der Anwender aufgefordert, die zwei dafür benötigten Strings einzugeben. Zeile 19 verwendet strstr(), um in dem ersten String, puffer1, nach dem zweiten String, puffer2, zu suchen. Es wird ein Zeiger auf das erste Vorkommen zurückgeliefert oder NULL, wenn der String nicht gefunden wurde. Die Zeilen 21 bis 24 werten den Rückgabewert loc aus und geben eine entsprechende Nachricht aus.

Was Sie tun sollten

Was nicht

Denken Sie daran, dass es für viele der Stringfunktionen äquivalente Funktionen gibt, bei denen Sie die Anzahl der betroffenen Zeichen angeben können. Die Funktionen, in denen Sie die Anzahl der Zeichen angeben können, tragen in der Regel den Namen strnxxx(), wobei xxx funktionsspezifisch ist.

Vergessen Sie nicht, dass in C zwischen Groß- und Kleinschreibung unterschieden wird. Demnach ist A etwas anderes als a.

Umwandlung von Strings in Zahlen

Manchmal ist es erforderlich, die Stringdarstellung einer Zahl in eine tatsächliche numerische Variable umzuwandeln - beispielsweise den String "123" in eine Variable vom Typ int mit dem Wert 123. Es gibt drei Funktionen, mit denen man einen String in eine Zahl konvertieren kann. Sie werden in den folgenden Abschnitten erläutert, ihre Prototypen stehen in der Header-Datei stdlib.h.

Die Funktion atoi()

Die Bibliotheksfunktion atoi() konvertiert einen String in einen Integer. Der Prototyp der Funktion lautet:

int atoi(char *ptr);

Die Funktion atoi() wandelt den String, auf den ptr zeigt, in einen Integer um. Neben Ziffern kann der String auch führende Whitespace-Zeichen und ein Plus- oder Minuszeichen enthalten. Die Umwandlung beginnt am Anfang des Strings und wird so lange durchgeführt, bis ein unkonvertierbares Zeichen (zum Beispiel ein Buchstabe oder ein Satzzeichen) auftritt. Der resultierende Integer wird an das aufrufende Programm zurückgegeben. Werden keine konvertierbaren Zeichen gefunden, liefert atoi() den Wert 0 zurück. Tabelle 16.2 enthält einige Beispiele.

String

Rückgabewerte von atoi()

"157"

157

"-1.6"

-1

"+50x"

50

"elf"

0

"x506"

0

Tabelle 16.2: String-/Zahlen-Konvertierungen mit atoi().

Das erste Beispiel ist eindeutig und bedarf wohl keiner Erklärung. Im zweiten Beispiel kann es Sie vielleicht etwas irritieren, dass ".6" nicht umgewandelt wurde. Dann möchte ich Sie noch einmal daran erinnern, dass wir hier Strings in Integer umwandeln. Das dritte Beispiel ist ebenfalls eindeutig: Die Funktion interpretiert das Pluszeichen als Teil der Zahl. Das vierte Beispiel lautet "elf". Die atoi()-Funktion sieht nur die einzelnen Zeichen, sie kann keine Wörter umwandeln, auch keine Zahlwörter. Da der String nicht mit einer Zahl beginnt, liefert atoi() 0 zurück. Das Gleiche gilt auch für das letzte Beispiel.

Die Funktion atol()

Die Bibliotheksfunktion atol() entspricht im Großen und Ganzen der Funktion atoi(). Allerdings liefert Sie einen long-Wert zurück. Der Prototyp der Funktion lautet:

long atol(char *ptr);

Würde man die Strings aus Tabelle 16.2 mit atol() umwandeln, erhielte man die gleichen Werte wie für atoi(), nur dass die Werte vom Typ long und nicht vom Typ int wären.

Die Funktion atof()

Die Funktion atof() konvertiert einen String in einen double-Wert. Der Prototyp lautet:

double atof(char *str);

Das Argument str zeigt auf den zu konvertierenden String. Dieser String kann führende Whitespace-Zeichen, ein Plus- oder ein Minuszeichen enthalten. Die Zahl kann die Ziffern 0-9, den Dezimalpunkt und die Zeichen e oder E für den Exponenten enthalten. Wenn es keine konvertierbaren Zeichen gibt, liefert atof() 0 zurück. Tabelle 16.3 verdeutlicht anhand einiger Beispiele, wie atof() arbeitet.

String

Rückgabewerte von atof()

"12"

12.000000

"-0.123"

-0.123000

"123E+3"

123000.000000

"123.1e-5"

0.001231

Tabelle 16.3: String-/Zahlen-Konvertierungen mit atof().

In Listing 16.13 können Sie selbst Strings eingeben, die konvertiert werden sollen.

Listing 16.13: Mit atof() Strings in numerische Variablen vom Typ double konvertieren.

1: /* Beispiel für die Verwendung von atof(). */
2:
3: #include <string.h>
4: #include <stdio.h>
5: #include <stdlib.h>
6:
7: int main(void)
8: {
9: char puffer[80];
10: double d;
11:
12: while (1)
13: {
14: printf("\nUmzuwandelnder String (Leerzeile für Ende): ");
15: fgets(puffer,80,stdin);
16:
17: if ( strlen(puffer) < 2 )
18: break;
19:
20: d = atof( puffer );
21:
22: printf("Der umgewandelte Wert lautet %f.\n", d);
23: }
24: return(0);
25:}

Umzuwandelnder String (Leerzeile für Ende):     1009.12
Der umgewandelte Wert lautet 1009.120000.
Umzuwandelnder String (Leerzeile für Ende): abc
Der umgewandelte Wert lautet 0.000000.
Umzuwandelnder String (Leerzeile für Ende): 3
Der umgewandelte Wert lautet 3.000000.
Umzuwandelnder String (Leerzeile für Ende):

Die while-Schleife in den Zeilen 12 bis 23 führt das Programm so lange aus, bis Sie eine leere Zeile eingeben. Die Zeilen 14 und 15 fordern Sie auf, einen Wert einzugeben. Zeile 17 prüft, ob eine Leerzeile eingegeben wurde. Wenn ja, steigt das Programm aus der while-Schleife aus und wird beendet. Zeile 20 ruft atof() auf und konvertiert den eingegebenen Wert (puffer) in einen Wert d vom Typ double. Zeile 22 gibt das Ergebnis der Umwandlung aus.

Zeichentestfunktionen

Die Header-Datei ctype.h enthält Prototypen für eine Reihe von Funktionen zum Prüfen von Zeichen, die wahr oder falsch zurückliefern - je nachdem ob das Zeichen einer bestimmten Klasse von Zeichen angehört oder nicht. Sie können mit diesen Funktionen zum Beispiel prüfen, ob es sich bei einem Zeichen um einen Buchstaben oder um eine Zahl handelt? Die Funktionen isxxxx() sind eigentlich Makros, die in ctype.h definiert sind. Näheres zu Makros erfahren Sie am Tag 20, »Compiler für Fortgeschrittene«. Wenn Sie sich bis dort vorgekämpft haben, werden Sie wahrscheinlich einen Blick auf die Definitionen in ctype.h werfen wollen, um zu sehen, wie alles funktioniert. Im Moment reicht es, wenn Sie wissen, wie die Makros eingesetzt werden.

Die isxxxx()-Makros haben alle den gleichen Prototyp:

int isxxxx(int ch);

In der obigen Zeile ist ch das zu testende Zeichen. Der Rückgabewert ist wahr (ungleich Null), wenn das Zeichen der überprüften Klasse angehört, und falsch (Null), wenn das Zeichen nicht der Klasse angehört. In Tabelle 16.4 finden Sie die komplette Liste der isxxxx()-Makros.

Makro

Aktion

isalnum()

Liefert wahr zurück, wenn ch ein Buchstabe oder eine Ziffer ist

isalpha()

Liefert wahr zurück, wenn ch ein Buchstabe ist

isascii()

Liefert wahr zurück, wenn ch ein Standard-ASCII-Zeichen (zwischen 0 und 127) ist

iscntrl()

Liefert wahr zurück, wenn ch ein Steuerzeichen ist

isdigit()

Liefert wahr zurück, wenn ch eine Ziffer ist

isgraph()

Liefert wahr zurück, wenn ch ein druckbares Zeichen (ohne das Leerzeichen) ist

islower()

Liefert wahr zurück, wenn ch ein Kleinbuchstabe ist

isprint()

Liefert wahr zurück, wenn ch ein druckbares Zeichen (einschließlich des Leerzeichens) ist

ispunct()

Liefert wahr zurück, wenn ch ein Satzzeichen ist

isspace()

Liefert wahr zurück, wenn ch ein Whitespace-Zeichen (Leerzeichen, horizontaler und vertikaler Tabulator, Zeilenvorschub, Seitenvorschub oder Wagenrücklauf) ist

isupper()

Liefert wahr zurück, wenn ch ein Großbuchstabe ist

isxdigit()

Liefert wahr zurück, wenn ch eine hexadezimale Ziffer (0-9, a-f, A-F) ist

Tabelle 16.4: Die isxxxx()-Makros.

Sie können viele interessante Dinge mit den Zeichen-Makros machen. Nehmen Sie zum Beispiel die Funktion get_int() aus Listing 16.14. Diese Funktion liest einen Integer-Wert Zeichen für Zeichen aus stdin ein und liefert ihn als Variable vom Typ int zurück. Die Funktion überspringt führende Whitespace-Zeichen und liefert 0 zurück, wenn das erste Nicht-Whitespace-Zeichen kein numerisches Zeichen ist.

Listing 16.14: Mit den Makros isxxxx() eine Funktion implementieren, die einen Integer einliest.

1: /* Mit den Zeichen-Makros einen Integer erzeugen */
2: /* erzeugen. */
3: #include <stdio.h>
4: #include <ctype.h>
5:
6: int get_int(void);
7:
8: int main(void)
9: {
10: int x;
11: printf("Geben Sie einen Integer ein: ") ;
12: x = get_int();
13: printf("Sie haben %d eingegeben.\n", x);
14: return 0;
15: }
16:
17: int get_int(void)
18: {
19: int ch, i, vorzeichen = 1;
20:
21: /* Überspringt alle führenden Whitespace-Zeichen. */
22:
23: while ( isspace(ch = getchar()) )
24: ;
25:
26: /* Wenn das erste Zeichen nicht nummerisch ist, stelle das */
27: /* Zeichen zurück und liefere 0 zurück. */
28:
29: if (ch != '-' && ch != '+' && !isdigit(ch) && ch != EOF)
30: {
31: ungetc(ch, stdin);
32: return 0;
33: }
34:
35: /* Wenn das erste Zeichen ein Minuszeichen ist, */
36: /* setze Vorzeichen entsprechend. */
37:
38: if (ch == '-')
39: vorzeichen = -1;
40:
41: /* Wenn das erste Zeichen ein Plus- oder Minuszeichen war, */
42: /* hole das nächste Zeichen. */
43:
44: if (ch == '+' || ch == '-')
45: ch = getchar();
46:
47: /* Lies die Zeichen, bis eine Nichtziffer eingegeben wird. */
48: /* Weise die Werte i zu. */
49:
50: for (i = 0; isdigit(ch); ch = getchar() )
51: i = 10 * i + (ch - '0');
52:
53: /* Mache Ergebnis negativ, wenn das Vorzeichen negativ ist. */
54:
55: i *= vorzeichen;
56:
57: /* Wenn kein EOF angetroffen wurde, muss eine Nichtziffer */
58: /* eingelesen worden sein. Also zurückstellen. */
59:
60: if (ch != EOF)
61: ungetc(ch, stdin);
62:
63: /* Den eingegebenen Wert zurückgeben. */
64:
65: return i;
66: }

Geben Sie einen Integer ein: -100
Sie haben -100 eingegeben.
Geben Sie einen Integer ein: abc3.145
Sie haben 0 eingegeben.
Geben Sie einen Integer ein: 9 9 9
Sie haben 9 eingegeben.
Geben Sie einen Integer ein: 2.5
Sie haben 2 eingegeben.

Dieses Programm verwendet in den Zeilen 31 und 61 die Bibliotheksfunktion ungetc(), die Sie bereits vom Tag 13, »Mit Bildschirm und Tastatur arbeiten«, kennen. Denken Sie daran, dass diese Funktion ein Zeichen »zurückstellt«, d.h. an den angegebenen Stream zurückgibt. Dieses zurückgegebene Zeichen ist das erste, das bei der nächsten Leseoperation des Programms eingelesen wird. Dies ist wichtig, wenn die Funktion get_int() ein nichtnumerisches Zeichen aus stdin ausliest, das eigentlich nachfolgenden Leseoperationen zur Verfügung stehen sollte.

Die main()-Funktion dieses Programms ist recht einfach. In Zeile 19 wird eine Integer- Variable x deklariert, der in Zeile 12 der Rückgabewert der get_int()-Funktion zugewiesen wird. Anschließend erfolgt die Ausgabe auf den Bildschirm (Zeile 13). Die get_int()-Funktion macht den ganzen Rest des Programms aus.

Die Funktion get_int() ist nicht ganz so einfach aufgebaut. Um führende Whitespace- Zeichen, die eventuell eingegeben wurden, zu entfernen, iteriert Zeile 23 durch eine while-Schleife. Das Makro isspace() prüft, ob es sich bei dem übergebenen Zeichen - in unserem Falle ch, das mit der Funktion getchar() eingelesen wird - um ein Leerzeichen handelt. Wenn ja, wird ein weiteres Zeichen überprüft, und zwar so lange bis ein Nicht-Whitespace eingelesen wird. Zeile 29 prüft, ob das Zeichen verwendbar ist. Zeile 29 könnte man auch lesen als »Wenn das eingelesene Zeichen kein Vorzeichen, keine Ziffer und kein Dateiende-Zeichen ist«. Ist diese Bedingung wahr, wird in Zeile 31 ungetc() verwendet, um das Zeichen zurückzustellen und zu main() zurückzukehren. Ist das Zeichen dagegen verwendbar, wird die Funktion weiter ausgeführt.

Die Zeilen 38 bis 45 behandeln das Vorzeichen der Zahl. Zeile 38 prüft, ob das eingegebene Zeichen ein negatives Vorzeichen ist. Wenn ja, wird die Variable vorzeichen auf -1 gesetzt. vorzeichen wird dazu benutzt, um die endgültige Zahl später positiv oder negativ zu machen (Zeile 55). Da die Zahlen standardmäßig positiv sind, reicht es, das negative Vorzeichen zu berücksichtigen. Wurde ein Vorzeichen eingegeben, muss allerdings noch ein weiteres Zeichen eingelesen werden. Das übernehmen die Zeilen 44 und 45.

Das Herz der Funktion ist die for-Schleife in den Zeilen 50 und 51, die so lange Zeichen einliest, wie es sich bei den Zeichen um Ziffern handelt. Zeile 51 mag auf den ersten Blick etwas verwirrend erscheinen. Diese Zeile übernimmt die einzelnen eingegebenen Zeichen und wandelt sie in eine Zahl um. Durch die Subtraktion des Zeichens '0' von der eingegebenen Ziffer wird der ASCII-Code der Ziffer in eine echte Zahl umgewandelt. Dieser Wert wird zu dem letzten Wert, multipliziert mit 10, addiert. (Die Multiplikation des bisherigen Wertes mit 10 wird erforderlich, weil die höchsten Ziffern der Zahl zuerst eingelesen werden.) Die for-Schleife wird so lange durchlaufen, bis eine Nichtziffer eingegeben wird. Am Schluss wird der Wert in Zeile 55 noch mit dem Vorzeichen multipliziert, und die Umwandlung der Zeicheneingabe in eine Zahl ist komplett.

Bevor das Programm zurückkehrt, müssen noch einige Aufräumarbeiten erledigt werden. Wenn das letzte Zeichen nicht EOF war, muss es zurückgegeben werden (für den Fall, dass es anderswo benötigt wird). Dieser Schritt erfolgt in Zeile 61. Mit Zeile 65 kehrt die Programmausführung aus get_int() zurück.

tolower() und toupper()

Die Header-Datei ctype.h enthält noch zwei weitere nützliche Funktionen, mit denen man Groß- in Kleinbuchstaben umwandeln kann und umgekehrt. Diese Funktionen sind wie folgt definiert:

int toupper (int c);
int tolower (int c);

Jede dieser Funktionen übernimmt ein int-Argument und gibt einen int-Wert zurück. Wenn die Schreibweise bereits korrekt ist oder es sich um ein nichtalphabetisches Zeichen handelt, geben die Funktionen die Buchstaben beziehungsweise das Zeichen unverändert zurück. In Listing 16.15 sehen Sie ein Beispiel für die Verwendung dieser Funktionen.

Listing 16.15: Mit der Funktion tolower() einen String in Kleinbuchstaben umwandeln.

1: /* Beispiel für die Funktion tolower() */
2: #include <stdio.h>
3: #include <ctype.h>
4:
5: char* kleinschreibung(char *str);
6:
7: int main(void)
8: {
9: char puffer[80];
10:
11: printf("Geben Sie den umzuwandelnden String ein: ");
12: fgets(puffer,80,stdin);
13:
14: kleinschreibung(puffer);
15:
16: printf(puffer);
17:
18: return 0;
19: }
20:
21: char* kleinschreibung(char *str)
22: {
23: int k ;
24:
25: for (k = 0 ; str [k] ; k++)
26: str[k] = tolower(str[k]);
27:
28: return str ;
29: }

Geben Sie den umzuwandelnden String ein: GeMischTe SchreibWEISE
gemischte schreibweise

In diesem Beispiel ist nur sehr wenig neu. Die Zeilen 11 und 12 fordern Sie auf, eine Textzeile einzugeben, die dann in das Zeichenarray puffer eingelesen wird. Dieses Zeichenarray wird der Funktion kleinschreibung() übergeben und in Zeile 16 auf dem Bildschirm ausgegeben. Die Funktion kleinschreibung() wird in den Zeilen 21 bis 29 definiert. Sie übernimmt einen Zeiger auf ein Zeichenarray als Argument und liefert am Ende einen Zeiger auf das gleiche Array zurück. Die Hauptarbeit der Funktion steckt in den Zeilen 25 und 26. Zeile 25 ist eine for-Schleife, die endet, wenn das Zeichen an der Position k im Array str das Nullzeichen \0 ist. Für jeden Wert von k, der nicht den Testbedingungen der for-Schleife entspricht, wandelt die Anweisung in Zeile 26 das Zeichen in einen Kleinbuchstaben um. Beachten Sie, dass keine Prüfung benötigt wird, um sicherzustellen, dass das umzuwandelnde Zeichen ein Buchstabe des Alphabets ist.

Was Sie tun sollten

Was nicht

Nutzen Sie die verfügbaren Stringfunktionen.

Verwenden Sie keine Funktionen, die nicht dem ANSI-ISO-Standard entsprechen, wenn Ihr Programm auf andere Plattformen portierbar sein soll.

Verwechseln Sie nicht Zeichen mit Zahlen. Man vergisst leicht, dass das Zeichen 1 nicht das gleiche ist wie die Zahl 1.

Zusammenfassung

Die heutige Lektion hat Ihnen verschiedene Möglichkeiten gezeigt, wie Sie in C Strings manipulieren können. Mit den Funktionen der C-Standardbibliothek können Sie Strings kopieren, verketten, vergleichen und durchsuchen. Diese Aufgaben sind unverzichtbarer Bestandteil der meisten Programmierprojekte. Außerdem enthält die Standardbibliothek Funktionen für die Umwandlung in Groß- beziehungsweise Kleinschreibung und für das Konvertieren von Strings in Zahlen. Schließlich gibt es in C eine Reihe von Zeichentestfunktionen oder vielmehr Makros, mit denen man prüfen kann, ob ein Zeichen einer bestimmten Zeichenklasse angehört. Mit Hilfe dieser Makros können Sie Ihre eigenen Eingabefunktionen erzeugen.

Fragen und Antworten

Frage:
Woher weiß ich, ob eine Funktion ANSI/ISO-kompatibel ist?

Antwort:
Wenn Sie im Handbuch oder der Manpage für die Funktion nachsehen, werden Sie dort einen Abschnitt »CONFORMING TO« finden. Dieser Abschnitt teilt Ihnen mit, welchem Standard die Funktion entspricht. Die Übereinstimmung mit dem ANSI/ISO-Standard wird nur angegeben, wenn Sie eine ältere Version der Manpages haben. Denken Sie daran, dass der ISO- Standard auf ANSI aufbaut (siehe Tag 1, »Einführung in Linux und die Programmiersprache C«). Auf anderen Plattformen müssen Sie die entsprechenden Referenzhandbücher zu Rate ziehen.

Frage:
Wurden heute alle verfügbaren Stringfunktionen angesprochen?

Antwort:
Nein. Die heute vorgestellten Stringfunktionen sollten aber ausreichen, um so ziemlich alle Ihre Bedürfnisse zu befriedigen. Informationen zu den anderen Funktionen finden Sie in den Manpages.

Frage:
Ignoriert strcat() nachfolgende Leerzeichen?

Antwort:
Nein. strcat() behandelt Leerzeichen wie jedes andere Zeichen.

Frage:
Kann ich Zahlen in Strings konvertieren?

Antwort:
Ja. Sie können eine Funktion schreiben, die der in Listing 16.16 ähnlich ist, oder in Ihrer Bibliothekreferenz nachschauen, ob es in der Bibliothek eine passende Funktion gibt. Zu den üblicherweise verfügbaren Funktionen gehören itoa(), ltoa() und ultoa(). Sie können aber auch sprintf() verwenden.

Workshop

Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, sowie Übungen, die Sie anregen sollen, das Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Die Lösungen zu den Fragen und den Übungen finden Sie in Anhang C.

Quiz

  1. Was ist die Länge eines Strings und wie kann man sie ermitteln?
  2. Was müssen Sie unbedingt machen, bevor Sie einen String kopieren?
  3. Was bedeutet der Begriff Konkatenation?
  4. Was bedeutet es, wenn »ein String größer ist als ein anderer«?
  5. Worin besteht der Unterschied zwischen strcmp() und strncmp()?
  6. Worin besteht der Unterschied zwischen strcmp() und strcasecmp()?
  7. Auf welche Werte prüft isascii()?
  8. Welche Makros aus Tabelle 16.4 würden für var wahr zurückgeben?
    int var = 1;
  9. Welche Makros aus Tabelle 16.4 würden für x wahr zurückgeben?
    char x = 65;
  10. Wozu werden Zeichentestfunktionen verwendet?

Übungen

  1. Welche Werte liefern die Testfunktionen zurück?
  2. Was würde die Funktion atoi() zurückliefern, wenn ihr die folgenden Werte übergeben würden?
  3. a. "65"
  4. b. "81.23"
  5. c. "-34.2"
  6. d. "zehn"
  7. e. "+12hundert"
  8. f. "negativ100"
  9. Was würde die Funktion atof()zurückliefern, wenn ihr die folgenden Werte übergeben würden?
  10. a. "65"
  11. b. "81.23"
  12. c. "-34.2"
  13. d. "zehn"
  14. e. "+12hundert
  15. f. "1e+3"
  16. FEHLERSUCHE: Ist an folgendem Code irgendetwas falsch?
    char *string1, string2;
    string1 = "Hallo Welt";
    strcpy( string2, string1);
    printf( "%s %s", string1, string2 );

Aufgrund der vielen möglichen Antworten gibt es zu den folgenden Übungen keine Lösungen.

  1. Schreiben Sie ein Programm, das den Anwender auffordert, seinen Nachnamen und zwei Vornamen einzugeben. Speichern Sie dann den Namen in einem neuen String in der Form: Initial, Punkt, Leerzeichen, Initial, Punkt, Leerzeichen, Nachname. Wenn die Eingabe zum Beispiel Bradley, Lee und Jones lautet, speichern Sie diese Eingabe als B. L. Jones. Geben Sie den neuen Namen auf den Bildschirm aus.
  2. Schreiben Sie ein Programm, das Ihre Antworten auf die Quizfragen 8 und 9 bestätigt.
  3. Die Funktion strstr() findet das erste Vorkommen eines Strings in einem anderen und berücksichtigt dabei die Groß- und Kleinschreibung. Schreiben Sie eine Funktion, die die gleiche Aufgabe ausführt, ohne jedoch die Groß- und Kleinschreibung zu berücksichtigen.
  4. Schreiben Sie eine Funktion, die feststellt, wie oft ein String in einem anderen enthalten ist.
  5. Schreiben Sie ein Programm, das eine Textdatei nach den Vorkommen eines vom Anwender eingegebenen Strings durchsucht und für jedes Vorkommen die Zeilennummer ausgibt. Wenn Sie zum Beispiel eine Ihrer C-Quelltextdateien nach dem String »printf« durchsuchen lassen, sollte das Programm alle Zeilen auflisten, in der die Funktion printf() aufgerufen wird.
  6. Listing 16.14 enthält ein Beispiel für eine Funktion, die einen Integer von stdin einliest. Schreiben Sie eine Funktion get_float(), die einen Fließkommawert von stdin einliest.
1234

vorheriges KapitelInhaltsverzeichnisStichwortverzeichnisFeedbackKapitelanfangnächstes Kapitel


© Markt&Technik Verlag, ein Imprint der Pearson Education Deutschland GmbH