Teil 7 „Strings“

Der C-Kurs
Antworten
Benutzeravatar
bodo
User
Beiträge: 319
Registriert: 14.02.2007, 17:21
Kontaktdaten:

Teil 7 „Strings“

Beitrag von bodo » 30.10.2010, 13:25

C für BASIC-Programmierer

Arbeiten mit dem z88dk Cross-Compiler

von Jens Sommerfeld und Bodo Wenzel

Teil 7

Nachdem wir jetzt mit Zahlen schon umgehen können, kommen wir zu den Zeichenketten, vulgo „Strings“.

Vom BASIC sind wir da ziemlich verwöhnt: Strings sind ein eigener Datentyp, um die Verwaltung des entsprechenden Speicherplatzes müssen wir uns nicht kümmern. Das ist in C (leider? (Das Positive daran ist, dass der Programmierer wiederum genau weiß, wann welcher Speicherbereich wofür benutzt wird. Zumindest sollte er das wissen!)) ganz anders, auch wenn die bisherigen Programme einen anderen Eindruck vermittelt haben.

In C gibt es einen kleinen Ganzzahlentyp (Auf die Eigenschaft als Zwitter aus Zeichen und Ganzzahl kommen wir in Teil 11 zurück.), nämlich char. Natürlich können wir eine Variable dieses Typs anlegen und benutzen, das kennt ihr bereits. Im Beispiel lernt ihr gleich eine weitere Formatierungsoption („%c“) für printf() (Was mit printf() noch alles geht, lernt ihr ausführlich in Teil 17. Bis dahin werden wir das eine oder andere Nötige vorwegnehmen.) kennen:

Code: Alles auswählen

#include <stdio.h>

int main(void) {
    char zeichen;

    zeichen = 'X';
    printf("Inhalt von zeichen = %c\n", zeichen);

    return 0;
}
Bitte beachtet, dass die Zeichenkonstante in einfache Anführungstriche gesetzt wird, das ist das Zeichen oberhalb des Nummerzeichens '#' auf der üblichen deutschen PC-Tastatur, links neben der Eingabetaste.

Um eine Zeichenkette speichern zu können, wird ein Array von char angelegt:

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

int main(void) {
    char string[30];

    strcpy(string, "Dies ist eine Zeichenkette.");
    printf("string = %s\n", string);

    return 0;
}
Dieses Beispiel zeigt drei Sachverhalte:
  • Arrays werden ganz ähnlich zu normalen Variablen definiert. Der Unterschied ist die Dimensionierung mit der Angabe der Elementanzahl in eckigen Klammern.
  • C kennt keinen Datentyp „Zeichenkette“: wir können der Variablen keine Zeichenkettenkonstante direkt zuweisen (Später kommen wir auf eine Methode zurück, die so etwas ähnliches doch ermöglicht...). Deshalb verwenden wir die Funktion strcpy() („string copy“), die eine Zeichenkette in eine andere kopiert; dabei wird das Ziel als erster Parameter angegeben, die Quelle als zweiter Parameter. Damit der Compiler diese Funktion kennt, muss eine weitere include-Zeile angegeben werden.
  • In unserem Beispiel ist die Quellzeichenkette eine Konstante. Nanu, C kennt doch keinen Datentyp „Zeichenkette“? Nun, hier ist die Ausnahme von der Regel! Konstante Zeichenketten akzeptiert C, sie werden an den doppelten Anführungszeichen (oberhalb der 2 auf der üblichen deutschen PC-Tastatur) erkannt. Dies ist ein echtes Zugeständnis...
Die Standardbibliothek enthält viele Funktionen, die mit Zeichenketten arbeiten. Grundsätzlich müssen Zeichenkettenvariablen, die das Ziel einer Operation sind, genügend groß sein. Wenn das nicht der Fall ist, haben wir einen der berühmten Pufferüberläufe, die für viele der heutigen Sicherheitslücken verantwortlich sind!

Die folgenden Absätze enthalten einige Beispiele; alle Funktionen vorzustellen, würde den Rahmen deutlich sprengen. Wenn ihr mehr wissen wollt, schaut euch die entsprechenden Headerdateien (*.h) an und lest die Dokumentation. Es sind einige Schätze zu entdecken – und es lohnt sich nicht, das Rad neu zu erfinden!

Zeichenketten aneinanderhängen

Mit der Funktion strcat() („string concatenate“) wird eine Zeichenkette an eine andere angehängt:

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

int main(void) {
    char string[30];

    strcpy(string, "Dies ist ");
    strcat(string, "eine Zeichenkette.");
    printf("string = %s\n", string);

    return 0;
}
Länge einer Zeichenkette bestimmen

Natürlich kann auch die Länge einer Zeichenkette bestimmt werden; wenn das Argument der Funktion strlen() („string length“) eine Zeichenkettenkonstante ist, können einige Compiler die Länge sofort selbst bestimmen und fügen dann die entsprechende Zahl in den Code ein. Zur Laufzeit des Programms findet in diesem Fall kein Aufruf mehr statt.

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

int main(void) {
    printf("Laenge = %d\n", strlen("Dies ist eine Zeichenkette."));

    return 0;
}
Bei dieser Gelegenheit stellt sich die Frage, wie C die tatsächliche Länge einer Zeichenkette feststellt; das Zeichenarray ist ja normalerweise größer. Dies wird durch das spezielle Nullzeichen erledigt, das nach dem letzten Zeichen kommt. Auf diese Art kann eine Zeichenkette (im Rahmen des verfügbaren Speicherplatzes) beliebig groß werden, ohne dass irgendwo Speicherplatz für eine Größenangabe vorgehalten wird.

Ihr kennt ja schon das Sonderzeichen '\n', das das Zeilenende kennzeichnet. Auf analoge Art wird das Nullzeichen mit '\0' kodiert. Es gibt noch mehr solche Sonderzeichen, auf die im Teil 11 eingegangen wird.

Wenn ich also die Zeichenkette „Hallo!\n“ in einer Variablen char text[10] ablege, enthält das Array hinterher folgenden Inhalt:

Code: Alles auswählen

text[0] text[1] text[2] text[3] text[4] text[5] text[6] text[7] text[8] text[9]
  'H'     'a'     'l'     'l'     'o'     '!'     '\n'    '\0'   (alt)   (alt)
Anmerkung: (alt) bedeutet hier, dass dieses Arrayelement durch das Ablegen von „Hallo!“ nicht verändert wurde.

In praktisch allen C-Implementationen wird dieses Nullzeichen durch ein Byte mit dem Wert 0 kodiert, deshalb kann dieses Zeichen auch nicht Bestandteil einer Zeichenkette sein (Natürlich kann ich eine Zeichenkette „Hallo\0Welt!“ hinschreiben, die auch 12 Bytes belegt. Aber die üblichen Zeichenkettenfunktionen nehmen dann das Ende nach dem 'o' an.).

Zeichenketten vergleichen

Zum Vergleich zweier Zeichenketten wird die Funktion strcmp() („string compare“) benutzt. Das Ergebnis wird als Zahl zurückgegeben:
  • Ein Wert kleiner als Null bedeutet, dass die erste Zeichenkette „kleiner“ ist als die zweite.
  • Ein Wert gleich Null bedeutet, dass beide Zeichenketten gleich sind.
  • Ein Wert größer als Null bedeutet... ihr könnt es euch denken. ;-)
Ein Beispiel:

Code: Alles auswählen

#include <stdio.h>
#include <string.h>

int main(void) {
    char text1[10];
    char text2[10];

    strcpy(text1, "groesser");
    strcpy(text2, "KLEINER");

    printf("Vergleich 1 = %d\n", strcmp(text1, text2));
    printf("Vergleich 2 = %d\n", strcmp(text1, text1));
    printf("Vergleich 3 = %d\n", strcmp(text2, text1));

    return 0;
}
Die Entscheidung über die „Größe“ der Zeichenkette wird anhand der Zeichenkodierung im Zeichensatz gefällt; das erste unterschiedliche Zeichen entscheidet. Wenn eine Zeichenkette kürzer ist als die andere, bis dahin aber beide gleich sind, gilt sie ebenfalls als „kleiner“.

Zeichenketten durchsuchen

Von den vielen Funktionen, die zum Durchsuchen von Zeichenketten dienen, nennen wir hier nur drei Beispiele. Leider erfordert ihre detaillierte Erklärung die Kenntnis von Zeigern; diese sind angeblich das Schwierigste an C (stimmt nicht!) und kommen erst in Teil 21.
  • strchr() („string character“) sucht das erste Vorkommen eines Zeichens in einer Zeichenkette.
  • strrchr() („string reverse character“) sucht das letzte Vorkommen eines Zeichens in einer Zeichenkette.
  • strstr() („string string“) sucht eine Zeichenkette in einer anderen Zeichenkette.
Zeichenketten in Zahlen umwandeln

Weil Ausdrücke in C vom Compiler in unveränderlichen Maschinencode umgesetzt werden, gibt es keine Methode, die mit der BASIC-Funktion VAL vergleichbar ist. Aber es gibt außer dem Gegenstück zu printf() (es ist die Funktion scanf(), wir behandeln sie in Teil 9) noch die einfache Funktion atoi() („ascii to integer“):

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    int zahl;

    zahl = atoi("12345");
    printf("Ergebnis = %d\n", zahl);

    return 0;
}
Bitte beachtet die andere Headerdatei!

Zahlen in Zeichenketten umwandeln

Die Funktion itoa() („integer to ascii“) ist das Komplementär zu atoi():

Code: Alles auswählen

#include <stdio.h>
#include <stdlib.h>

int main(void) {
    char text[10];

    itoa(text, 23456);
    printf("Ergebnis = %s\n", text);

    return 0;
}
Hausaufgaben
  1. Schreibt ein Programm, dass euch den Inhalt aller Elemente des Beispiels oben (Tabelle von char text[10]) ausgibt. Beachtet dabei, dass Arrayindizes immer mit Null anfangen! Für die Ausgabe des vierten Elements könnt ihr z.B. schreiben:

    Code: Alles auswählen

    printf("4. Zeichen = %c\n", text[3]);
  2. Wie wird die „leere“ Zeichenkette ( "") in Bytes kodiert? Wieviele Zeichen bzw. Bytes werden dafür benötigt?
  3. Im Beispiel zu strcmp() wird euch das Ergebnis sicher überraschen. Abgesehen vom absoluten Zahlenwert, der ja egal ist, hättet ihr sicher gedacht, dass „groesser“ kleiner als „KLEINER“ ist, weil das „G“ ja vor dem „K“ kommt. Erklärt das Ergebnis... Stichworte sind: Groß- und Kleinbuchstaben, ZX81-Zeichensatz und ASCII. Zum Experimentieren könnt ihr jede Menge Vergleiche ausführen, z.B. durch eine Anzahl solcher Anweisungen:

    Code: Alles auswählen

    printf("Ergebnis = %d\n", strcmp("text1", "text2"));
B0D0: Real programmers do it in hex.

Antworten