|
|
|
|
|
|
|
|
| .. Arrays -> Strings (eindimensional) | ||
|
|
||
|
|
|
|
|
|
Das Bild zeigt einen Ausschnitt des RAM Hauptspeichers eines PCs. Es beginnt willkürlich mit einem Speicherbyte dessen Nummer (Adresse) 0FFEh lautet und endet mit dem Byte 100Fh. Der Inhalt dieser Speicherbytes sind irgend welche Zahlen im Bereich zwischen 0 und 255. Nur durch die in der ASCII-Code-Tabelle hinterlegte Vereinbarung lassen sich diese Zahlen in Punktrasterbildchen wandeln, die dann wie Buchstaben aussehen. Die Wandlung der Zahlen zu Buchstaben übernimmt eine elektronische Schaltung, die als Grafikkarte bezeichnet wird. |
|
|
|
|
|
|
|
|
|
|
|
Aus dieser Erkenntnis heraus wird unmittelbar klar, warum die nachfolgende Zuweisung nicht funktionieren kann .. |
|
|
|
|
|
|
|
char* string; ... string = "www.GoBlack.de"; // das geht nicht // hier wird während der Laufzeit eines Programms versucht, dem // Zeiger string, der wie oben den Wert 1000 haben möge, die // Zahlenfolge 77, 77, 77, 2E .. usw. zuzuweisen. Das funktioniert // auch in C nicht. // Dagegen ist es natürlich weiterhin möglich einem zweiten Zeiger // den Wert eines vorhergehenden Zeigers zu übergeben char* string = "www.GoBlack.de"; char* zeiger; ... zeiger = string; // das geht // nach dieser Zuordnung während der Laufzeit zeigen beide Zeiger // auf den Wert 1000, also auf das erste Byte des Strings. |
|
|
|
|
|
|
|
Wie das letzte Beispiel zeigt, stellt der Augenblick der Deklaration von Strings eine Ausnahme dar. Zu diesem Zeitpunkt kann der Compiler mithelfen, Zeigervariable und Stringliterale miteinander zu verbinden. Dies funktioniert, weil der Compiler ja erst den Maschinencode erzeugt, der zur Laufzeit ausgeführt werden soll. Der Compiler kann also ein Maschinenprogramm erzeugen, welches zunächst Speicherbytes in genügender Menge für das Stringliteral anfordert (definiert), diesen mit den ASCII-Codezahlen füllt (initialisiert), um dann die Adresse des ersten dieser Bytes in die Zeigervariable zu schreiben. Die nachfolgenden Beispiele zeigen, welche Möglichkeiten es in C hierfür gibt .. |
|
|
|
|
|
|
|
char string1[25] = "alle meine Entchen"; // a) char string2[] = "schwimmen auf dem"; // b) char* string = "See"; // c) |
|
|
|
|
|
|
|
Wird nur deklariert und keine Zuweisung zu einem Literal angegeben, so stehen nach char string1[25]; tatsächlich 25 Speicherbytes bereit, die gefüllt werden können. Mit char* string; wird nur ein Zeiger für Strings erzeugt aber kein Speicherraum bereitgestellt und char string2[]; ohne weitere Angaben, würde zu einer Fehlermeldung bei der Übersetzung des Programms führen. |
|
|
|
|
|
|
|
Aber Achtung. Der Compiler kontrolliert keinen der beiden Ausdrücke darauf hin, ob er wirklich noch im Bereich des anfänglich deklarierten Strings liegt. Bei der Ausgabe ist dies nicht gefährlich. Man kann sich ja mal die Inhalte der Bytes im Hauptspeicher des Computers anzeigen lassen. Beim Beschreiben von Bytes ist es mit beiden Ausdrücken möglich den Speicherraum eines Computers zu überschreiben. Nach dem bisherigen Kenntnisstand sind das zwar nur 64kByte, aber es sollte reichen um den Rechner zum Absturz zu bringen. Bleibt also die Frage, wie kann das Ende eines Strings erkannt werden. |
|
|
|
|
|
|
|
Nachdem bisher einzelne Zeichen ausgegeben wurden, vermittelt die nachfolgende Funktion einen Eindruck davon, wie printf("%s",string); funktionieren könnte, bei der es ja durchaus verwunderlich ist, dass kein Indirektionsoperator vor der Variablen string verlangt wird. Das Geheimnis ist ganz einfach gelöst. Das Ersatzzeichen %s gibt der Funktion printf den Hinweis darauf, dass es sich bei der zugeordneten Variable um einen Zeiger handeln muss. Ist das nicht der Fall, behandelt printf() die Variable trotzdem als Zeiger, was zu unvorhersehbaren Bildschirmdarstellungen führen kann. |
|
|
|
|
|
|
|
// Funktion zur Ausgabe eines Strings zum Bildschirm. Benutzt wird
// das BIOS Unterprogramm putch(), welches einzelne ASCII-Codes
// auf dem Monitor als Zeichen darstellen kann.
#include <conio.h> // für die BIOS-Funktion putch()
void zeigeString (char* string)
{
unsigned n=0;
for(n=0; string[n]!=0x00; n++){ // läuft bis Byte n =0 ist
putch(string[n]); // n-tes Zeichen ausgeben
}
}
// Testprogramm, gibt einen String zum Bildschirm aus
void main (void)
{
char *zeichenfolge = "Alle meine Entchen";
zeigeString(zeichenfolge);
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
char string1[25] = "alle meine Entchen"; char string2[] = "schwimmen auf dem"; char* string = "See"; |
|
|
|
Es ist natürlich auch möglich, die Stringvariablen nur festzulegen, also zu deklarieren. Dabei wird im ersten Beispiel neben dem Zeiger auch ein Buffer bestehend aus 25 Bytes erzeugt, während im zweiten Fall ausschliesslich ein Zeiger erzeugt wird. |
|
|
|
char string1[25]; char* string; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Auf einzelne Zeichen innerhalb eines Strings kann durch die Angabe eines Offsetwertes, der sich auf die Anfangsadresse des Strings bezieht, lesend und schreibend zugegriffen werden. So wird durch eine der beiden nachfolgenden Zuweisungen .. alle meine Entchen .. zu .. alle Deine Entchen .. |
|
string1[5] = 'D'; *(string1+5) = 'D'; |
||
|
|
.. und die Variable c wird mit 0 gefüllt, wenn einer der beiden Lesevorgänge stattfindet .. |
|
int c; c = string1[18]; // string1[18] enthält die c = *(string1+18); // Nullterminierung |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// stringcopy() // in der C-Bibliothek strcpy(). Die Funktion überträgt (kopiert) // die Inhalte eines Stringbuffers auf den der Stringzeiger quelle // weist, in den Buffer eines zweiten Stringzeigers mit dem Namen // ziel. Die Funktion gibt die Adresse zurück, auf die ziel zeigt. char* stringcopy(char* ziel, char* quelle) { unsigned n=0; for(n=0; quelle[n]!=0x00; n++){ // Speicher einzeln kopieren ziel[n]=quelle[n]; } ziel[n]=0x00; // Nullterminierung von ziel return(ziel); // Startddresse von ziel } // main() Testprogramm zur Anwendung der Funktion stringcopy() // Es werden die Adresse auf die der Stringzeiger zeigt, sowie der // Stringbuffer zum Bildschirm ausgegeben #include <stdio.h> // für printf() void main (void) { char string[20]; // ... stringcopy(string, "alle meine Entchen"); printf("%04X - %s schwimmen auf dem See", string, string); } |
||
|
|
|
|
// stringlang() // in der C-Blbliothek strlen(). Die Funktion zählt die Anzahl der // Bytes eines Stringbuffers, ohne das Byte mit der Nullterminie- // rung zu berücksichtigen. Es gibt die Anzahl der gefundenen Bytes // also die Länge des Strings zurück. unsigned stringlang(char* string) { unsigned n=0; while(string[n]!=0x00)n++; // zählen bis Nullterminierung return(n); // Zählwert zurückgeben } // main() Testprogramm zur Anwendung der Funktion stringlang() // Es werden die Adresse auf die der Stringzeiger zeigt, sowie der // Stringbuffer zum Bildschirm ausgegeben #include <stdio.h> // für printf() void main (void) { unsigned lang = 0; char string[]= "alle meine Entchen"; // ... lang = stringlang(string); printf("Der String \"%s\" besteht aus %u Zeichen", string, lang); } |
||
|
|
|
|
// stringanhang() // in der C-Bibliothek strcat(). Die Funktion hängt an einen ersten // String ziel einen zweiten mit dem Namen quelle an. Es ist darauf // zu achten, dass der Buffer des ersten Strings genügend gross // ist. Die Funktion gibt die Adresse zurück, auf die ziel zeigt. char* stringanhang(char* ziel, char* quelle) { unsigned n=0, m=0; for(n=0; ziel[n]!=0x00; n++); // Ende von ziel suchen for(m=0; quelle[m]!=0x00; m++,n++){ ziel[n]=quelle[m]; // Bytes an ziel anhängen } ziel[n]=0x00; // Nullterminierung von ziel return(ziel); // Startddresse von ziel } // main() Testprogramm zur Anwendung der Funktion stringanhang() // Es werden die Adresse auf die der Stringzeiger zeigt, sowie der // Stringbuffer von string1 zum Bildschirm ausgegeben #include <stdio.h> // für printf() void main (void) { char string1[40]= "alle meine Entchen"; char *string = " schwimmen auf dem See"; // ... stringanhang(string1, string); printf("%04X - %s", string1, string1); } |
||
|
|
.de