|
|
|
|
|
|
|
|
| .. Arrays -> Strings (mehrdimensional) | ||
|
|
||
|
|
Ein einzelner String stellt ein eindimensionales Array dar, dessen Variablenname die Adresse des ersten Bytes dieses Arrays bezeichnet. Sollen nun mehrere Strings mit Hilfe eines übergeordneten Arrays verfügbar werden, so lässt sich dies auf zwei Arten verwirklichen. Beide unterscheiden sich voneinander. Die dritte folgend genannte Deklaration stellt nur einen Zeiger dar, der auf einen Zeiger zeigt. Er ist bei den Strings gut zu gebrauchen, stiftet aber manchmal Verwirrung.
Doch zuvor eine.. C-'Binsenweisheit' In den Deklarationen wird die gewünschte Anzahl von Elementen, in natürlicher Zählweise angegeben. Die Element werden dann allerdings mit 0 beginnend gezählt. So bedeutet *string[5], ich will 5 Strings haben, und man erhält die Strings 0,1,2,3,4.
Deklaration |
|
|
|
char string [n][m] // zweidimensionales Array mit n Strings, von
// denen jeder jeweils m Zeichen umfasst.
// insgesamt ergibt sich ein zusammenhängender
// Buffer von n m Bytes, auf dessen erstes
// Byte der Variablenname string zeigt.
|
|
|
|
char *string [n] // eindimensionales Zeigerarray, mit n
// Zeigern, die ihrerseits auf auf Zeiger und
// damit auf Strings zeigen können. Die
// Strings können an beliebigen Orten des
// Hauptspeichers liegen, müssen also nicht
// wie oben einen Speicherblock bilden und
// sie können unterschiedlich lang sein.
|
|
|
|
char **string // Ein Zeiger, dessen Inhalt eine Adresse ist,
// die auf einen char-Zeiger zeigt. Damit
// kann er auf eines der beiden obigen
// Konstrukte zeigen.
|
|
|
|
Deklaration, Initialisation und Definition durch den Compiler Im ersten und zeiten Fall kann der Compiler zum Zeitpunkt der Übersetzung, des Codes den beiden Arrays bereits Strings zuordnen. Im dritten Fall ist dies nicht möglich, denn hier handellt es sich um einen Zeiger, der auf einen Zeiger zeigt. Eine Stringvariable dagegen ist ein Zeiger, der auf einen Inhalt zeigt. |
|
|
|
char string [5][16]= {{"01234"},{"567890"},{"Entchen"}};
// von den 5 angeforderten Strings werden
// bereits 3 definiert. Da sie jeweils kürzer
// sind als 16 Zeichen, wird der Raum für
// jeden genannten String, bis zum 16.Zeichen
// mit 0 aufgefüllt. Der Speicher für die
// zwei nicht definierten Strings wird zwar
// belegt (initialisiert), aber nicht mit 0
// aufgefüllt (definiert).
|
|
|
|
char *string [5] = {{"01234"},{"567890"},{"Entchen"}};
// Hier legt der Compiler die drei genannten
// Strings in aufeinander folgenden Bytes ab,
// wobei jeder String mit einer 0 beendet ist.
// Anders als oben, besitzen die Strings aber
// nur ihre tatsächliche Länge. Die
// Anfangsadressen der Strings überträgt der
// Compiler in die Zeiger *string[0]..1,2. Die
// Inhalte der zwei noch nicht belegten Zeiger
// sind 0. Ihnen können folgend beliebige
// Adressen von Strings zugeordnet werden,
// die irgendwo im Hauptspeicher liegen.
|
|
|
|
char **string = {{"01234"},{"567890"},{"Entchen"}};
// Das geht nicht, da der Inhalt von **string
// die Adresse eines Zeigers, der auf einen
// Zeiger zeigt, erhalten muss und nicht in
// der Lage ist, (hier gleich drei) Zeiger
// aufzunehmen, die auf Speicherzelleninhalte
// zeigen.
|
|
|
|
Definition zur Laufzeit Auch die Zuordnung von Strings zu einem der Arrays während der Laufzeit des Programms, unterscheidet sich bei den zwei obigen Arrays. Während im ersten Fall, ein von der Länge her genau bemessener Raum des Gesamtbuffers (im Beispiel 16 Bytes) mit einem neuen Inhalt gefüllt werden muss, braucht im zweiten Array nur die Zeigeradresse geändert werden. |
|
|
|
char string [5][16]= {{"01234"},{"567890"},{"Entchen"}};
...
strcpy (string[1],"Alle meine");
// hier wird der 16 Bytes lange Speicherraum
// des 2.Strings "567890" durch die 10 Bytes
// "Alle meine" überschrieben. Dies ist nur
// mit der Bibliotheksfunktion strcpy() =
// StringCopy möglich. Der neue String sollte
// nicht mehr als 16 Bytes umfassen.
|
|
|
|
char *string [5] = {{"01234"},{"567890"},{"Entchen"}};
...
string[1]= "Ich und Du, Müllers Kuh,";
// hier wird der Zeiger, der bisher auf
// "567890" zeigte auf den neuen String "Ich
// und Du, Müllers Kuh," gesetzt. Da dieser
// String an einem anderen Ort im
// Hauptspeicher liegt, darf er beliebig lang
// sein. Allerdings ist der Zugriff auf den
// vorhergehenden String nun nicht mehr
// möglich, obwohl er weiterhin im
// Hauptspeicher verbleibt.
strcpy (string[1],"22334");
// Die Möglichkeit, den String "567890" mit
// strcpy() zu überschreiben ist natürlich
// immer noch gegeben, wenn die vorhergehende
// Neuzuordnung noch nicht statt fand. Nur
// sollte anders als oben, der neue String
// nicht länger sein als 6 Zeichen, also der
// Länge von "567890".
|
|
|
|
Zugriff auf Strings bzw. deren Zeichen Beim programmiertechnischen Umgang mit Stringarrays muss man sich klar sein, worauf man Zugriff nehmen will. Soll es der gesamte String sein, der beispielsweise einer Funktion übergeben werden soll, oder will man einzelne Zeichen des Strings weitergeben bzw. verändern. Die beiden folgenden Ausdrücke zeigen einmal den Zugriff auf einen String, dann auf eines seiner Zeichen. Dabei bewirken die jeweilig alternativen Ausdrücke, mit eckigen Klammern oder als Zeiger, tatsächlich gleiches. Allerdings sollte man die Klammern bei den Zeigern ernst nehmen, denn die Operation * (zeige auf) hat assoziativen Vorrang vor der Operation + (addiere). Würde man die Klammern weglassen, so würden die Zeiger nicht mehr auf das gewünschte Objekt zeigen. |
|
string[n] oder *(string+n)
// ein Zeiger auf das erste Byte von String
// Nummer n
// z.B. printf("%s", string[n]); // String
// z.B. printf("%s", *(string+n)); // String
string[n][m] oder *(*(string+n)+m)
// ein Zeiger auf das Zeichen m im String
// Nummer n
// z.B. printf("%c", string[n][m]; // Zeichen
// z.B. printf("%X", string[n][m]; // Code
// z.B. printf("%c", *(*(string+n)+m));
|
||
|
|
Beisp |
|
|
|
|
|
|
|
.de