Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 13 Arrays
  gp 13.1 Arrays deklarieren
  gp 13.2 Initialisierung und Zugriff auf Arrays
    gp 13.2.1 Gültigkeitsbereich von Arrays
  gp 13.3 Arrays vergleichen
  gp 13.4 Anzahl der Elemente eines Arrays ermitteln
  gp 13.5 Übergabe von Arrays an Funktionen
  gp 13.6 Arrays aus Funktionen zurückgeben
  gp 13.7 Programmbeispiel zu den Arrays
  gp 13.8 Einlesen von Array-Werten
  gp 13.9 Mehrdimensionale Arrays
  gp 13.10 Mehrdimensionale Arrays initialisieren
    gp 13.10.1 Tic Tac Toe
    gp 13.10.2 Dreidimensionale Arrays
  gp 13.11 Übergabe von zwei- bzw. mehrdimensionalen Arrays an Funktionen
  gp 13.12 Arrays in Tabellenkalkulation einlesen (*.CSV–Dateien)
  gp 13.13 Strings/Zeichenketten (char Array)
    gp 13.13.1 Vom String zur Binärzahl
  gp 13.14 Einlesen von Strings
  gp 13.15 Standard-Bibliothek <string.h>
    gp 13.15.1 strcat() – Strings aneinander hängen
    gp 13.15.2 strchr() – ein Zeichen im String suchen
    gp 13.15.3 strcmp() – Strings vergleichen
    gp 13.15.4 strcpy() – einen String kopieren
    gp 13.15.5 strcspn() – einen Teilstring ermitteln
    gp 13.15.6 strlen() – Länge eines Strings ermitteln
    gp 13.15.7 strncat() – String mit n Zeichen aneinander hängen
    gp 13.15.8 strncmp() – n Zeichen von zwei Strings miteinander vergleichen
    gp 13.15.9 strncpy() – String mit n Zeichen kopieren
    gp 13.15.10 strpbrk() – Auftreten bestimmter Zeichen suchen
    gp 13.15.11 strrchr() – das letzte Auftreten eines bestimmten Zeichens im String suchen
    gp 13.15.12 strspn() – erstes Auftreten eines Zeichens, das nicht vorkommt
    gp 13.15.13 strstr() – String nach Auftreten eines Teilstrings durchsuchen
    gp 13.15.14 strtok() – String anhand bestimmter Zeichen zerlegen


Galileo Computing - Zum Seitenanfang

13.2 Initialisierung und Zugriff auf Arrays  downtop

In dem folgenden Listing wird gezeigt, wie ein Array mit Werten initialisiert wird und wie darauf zugegriffen werden kann:

/* array1.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   int i[5];     /* Array mit 5 int Elementen */
   /* Wertzuweisungen des Arrays */
   i[0] = 5;
   i[1] = 100;
   i[2] = 66;
   i[3] = 77;
   i[4] = 1500;
   /*Ausgabe der einzelnen Array-Elemente*/
   printf("Array-Element i[0]= %d\n", i[0]);
   printf("Array-Element i[1]= %d\n", i[1]);
   printf("Array-Element i[2]= %d\n", i[2]);
   printf("Array-Element i[3]= %d\n", i[3]);
   printf("Array-Element i[4]= %d\n", i[4]);
   return EXIT_SUCCESS;
}

Bei diesem Beispiel wurde an alle fünf Feldelemente ein Wert mithilfe des Indizierungsoperators [] übergeben. Und wie der Name des Operators schon sagt, dient dieser dem indizierten Zugriff auf Datentypen, die typischerweise hintereinander im Speicher abgelegt sind.

Warum lautet der Index des letzten Elements [4] und nicht [5]? Für den Computer ist die Zahl 0 auch ein Wert, und somit fängt dieser stets bei 0 an zu zählen:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.2   Ein Array mit Werten initialisieren

Sie sehen hier 5 Zahlen: 0, 1, 2, 3 und 4. Befände sich im Programm folgende Zeile

i[5] = 111;
printf("i[5] = %d\n",i[5]);

würde versucht, auf einen nicht reservierten Speicher zuzugreifen. Es wurde aber nur Speicher für fünf Adressen vom Datentyp int reserviert. Gefährlicher kann das werden, wenn dies in einer for-Schleife vorgenommen wird. Wird hier der Indexbereich überschritten, kann es passieren, dass mit falschen Werten weitergearbeitet wird. Hier ein Beispiel eines leider oft gemachten Fehlers:

/* array2.c */
#include <stdio.h>
#include <stdlib.h>
int main(void) {
   int test[10];
   int i;
   for(i = 0; i <= 10; i++)  /*  !!Bereichsüberschreitung!! */
      test[i] = i;
   for(i = 0; i <= 10; i++)
      printf("%d, ", test[i]);
   printf("\n");
   return EXIT_SUCCESS;
}

Das Programm macht nichts anderes, als das Array test[10] mit 11(!) Werten zu initialisieren, und anschließend werden diese Werte auf dem Bildschirm ausgegeben. (Haben Sie den Fehler schon gefunden?) Der Fehler liegt in der for-Schleife:

for(i = 0; i <= 10; i++)

Die for-Schleife wird insgesamt elf Mal durchlaufen: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10. Es kann (oder besser es wird) bei diesem Programm passieren, dass test[10] tatsächlich den Wert 10 enthält.

Sobald aber irgendwo im Programm diese Speicheradresse für eine andere Variable benötigt wird, wird der aktuelle Wert von test[10] überschrieben. Es kann also nicht garantiert werden, dass der Wert von test[10] erhalten bleibt, was zwangsläufig zu ungewollten Effekten und schwer aufzuspürenden Fehlern im Programm führt.

Wenn Sie das Programm gegenwärtig ausführen wollen, ohne dass solch ein Fehler auftritt, müssen Sie nur den Zuweisungsoperator aus den beiden for-Schleifen entfernen:

for(i = 0; i < 10; i++)  /* ohne '='-Zeichen richtig */

In dem Programm haben Sie gesehen, wie auf ein Array zugegriffen werden kann, um es mit Werten zu initialisieren:

for(i = 0; i < 10; i++)
   test[i] = i;

Damit wird die Schleife abgebrochen, sobald i den Wert 10 erreicht. Generell ist also Vorsicht geboten bei der Verwendung von Arrays im Zusammenhang mit Schleifen, und genau darauf zu achten, dass der Wertebereich des Feldes nicht unter- bzw. überschritten wird. Solche Unter- oder Überschreitungen werden vom Compiler nicht überprüft oder moniert.


Hinweis   Auf manchen Systemen gibt es eine Compiler-Option (range-checking), womit ein solcher Über- bzw. Unterlauf eines Arrays zur Laufzeit des Programms geprüft wird. Das fertige Programm sollte allerdings nicht mehr mit dieser Option übersetzt werden, da dies zu einem schlechten Laufzeitverhalten führt.


Statt einer konstanten Ganzzahl wurde hier die Variable i verwendet. Das funktioniert deshalb, weil diese vom Datentyp int ist und somit auch einer Ordinalzahl entspricht. Diese Variable wird von der for-Schleife bei jedem Durchlauf um den Wert eins erhöht (inkrementiert). Daraus ergibt sich, dass als Index nur Ganzzahlwerte erlaubt sind. Oftmals wird zur Bezeichnung des Index auch eine define-Konstante verwendet, wie das folgende Beispiel demonstriert:

/* array3.c */
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
int main(void) {
   int zahlen[SIZE] = { 0 };
   printf("Anz. Elemente : %d\n", sizeof(zahlen) / sizeof(int));
   return EXIT_SUCCESS;
}

Solche Konstanten können die Lesbarkeit und Vermeidung von Fehlern bei längeren Programmen erheblich verbessern. Ein weiterer Vorteil entsteht, wenn Sie die Anzahl der Elemente des Arrays erhöhen wollen. Sie müssen nur den Wert der define-Konstante ändern und nicht mühsam im Programm danach suchen.

Arrays lassen sich auch anders, nämlich direkt bei der Deklaration initialisieren. Die Werte müssen dabei zwischen geschweiften Klammern stehen:

int numbers[] = { 1, 2, 4, 5, 9 };

Wenn Sie das Array so initialisieren, können Sie die Größe des Arrays auch weglassen. C kümmert sich darum, dass genügend Speicher zur Verfügung steht. Die einzelnen Initializer werden immer mit einem Komma getrennt und stehen in geschweiften Klammern. Dadurch ist das Feld wie folgt mit Werten belegt:

numbers[0] = 1;
numbers[1] = 2;
numbers[2] = 4;
numbers[3] = 5;
numbers[4] = 9;

Natürlich können Sie trotzdem die Größe des Arrays angeben. Bei einem größeren Array hat diese Initialisierung den Vorteil, dass Sie alle anderen Werte gleich mit 0 vorbelegen können. Statt eine for-Schleife zu schreiben, wie etwa

int bigarray[1000];
for(i = 0; i < 1000; i++)
   bigarray[i] = 0;

lässt sich das auch einfacher formulieren:

int bigarray[1000] = { 0 };

Hier wurde nur das Array mit dem Index [0], also bigarray[0], mit dem Wert 0 initialisiert. Die restlichen 999, die nicht ausdrücklich initialisiert wurden, werden jedoch automatisch ebenfalls mit dem Wert 0 besetzt.

Dies kann aber noch ganz anders gelöst werden, und zwar unter Verwendung der folgenden Funktion:

/* Beschreibung der Funktion, siehe Abschnitt 13.14 string.h */
#include <string.h>
void *memset(void *adres, int zeichen, size_t n);

Mit der Funktion memset() wird der Wert von zeichen in jedes der ersten n Zeichen des Speicherbereichs mit der Adresse adres geschrieben. Das sieht dann wie folgt aus:

int bigarray[1000];
memset(bigarray, 0, sizeof(bigarray));

Wenn Sie das jetzt nicht nachvollziehen können: Ein paar Seiten später werden Sie es besser verstehen. Tatsächlich handelt es sich hier auch um einen Spezialfall der Verwendung von memset(), da sich dieses Verfahren nur mit dem Wert 0 auf ein int-Array anwenden lässt. Das liegt daran, dass memset() bitweise arbeitet. Bei einem int-Array auf einem 32-Bit-System würde dies bei 4 Bytes den Hier noch ein weiteres Beispiel zur Initialisierung von Arrays:

double inhalt[100] = { 2.4, 2.8, 9.45, 10.99 };

Wert 16843009 bedeuten (alle Bits auf 1).


Internes   memset() kann u.U. schneller sein als eine for-Schleife, da Ersteres viel näher an der Hardware operiert und evtl. deren Funktionalität ausbeuten kann (z.B. ist es viel sinnvoller, einen char[512] mit 128 0-longs zu belegen, statt 512x eine 0). memset() funktioniert außerdem auch bei nicht-pointer-multi-dimensionalen Arrays, z.B.:

char m_ar[10][10]; memset(m_ar, 0, 100);

Hiermit wurden folgende Werte initialisiert:

inhalt[0] = 2.4
inhalt[1] = 2.8
inhalt[2] = 9.45
inhalt[3] = 10.99
inhalt[4] = 0.0
inhalt[5] = 0.0
...
inhalt[997] = 0.0
inhalt[998] = 0.0
inhalt[999] = 0.0

Ab inhalt[4] bis inhalt[999] werden alle Werte automatisch mit 0.0 initialisiert. Leider ist es nicht möglich, den Inhalt eines Arrays mit einem anderen konstanten Wert außer 0 zu initialisieren.


Hinweis   Manche Systeme vertragen keine lokalen, übergroß dimensionierten Arrrays. Sollte das Programm bei Ihnen gleich nach dem Start abstürzen, und Sie verwenden ein recht großes Array, dann könnte ein global definiertes Array Abhilfe schaffen.



Galileo Computing - Zum Seitenanfang

13.2.1 Gültigkeitsbereich von Arrays  toptop

Der Gültigkeitsbereich von Arrays richtet sich danach, ob es sich dabei um ein statisches, globales oder ein normales (lokales) Array handelt. Betrachten Sie zur Verdeutlichung ein kleines Beispielprogramm:

/* array4.c */
#include <stdio.h>
#include <stdlib.h>
int wert_global[5];
int main(void) {
   static int wert_static[5];
   int wert_auto[5];
   int i;
   for(i = 0; i < 5; i++)
      printf("%d:\t%10d\t%10d\t%10d\n",
         i, wert_global[i], wert_static[i], wert_auto[i] );
   return EXIT_SUCCESS;
}

Die Ausgabe des Programms am Bildschirm sieht wie folgt aus:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.3   Gültigkeitsbereich von Variablen

Das Programm gibt für das globale und für das mit dem Schlüsselwort static deklarierte Array jeweils den Wert 0 aus. Das automatische Array wert_auto hingegen gibt einen undefinierten Wert zurück. Daraus lässt sich schließen, dass globale und mit static deklarierte Arrays automatisch mit 0 initialisiert werden.

Das Verhalten des Programms ändert sich, wenn die Automatic-Variable (wert_auto) mit mindestens einem Wert initialisiert wird:

/* array5.c */
#include <stdio.h>
#include <stdlib.h>
int wert_global[5];
int main(void) {
   static int wert_static[5];
   int wert_auto[5] = { 0 };  /* Array mit 0 initialisiert */
   int i;
   for(i = 0; i < 5; i++)
      printf("%d:\t%10d\t%10d\t%10d\n",
         i, wert_global[i], wert_static[i], wert_auto[i] );
  return EXIT_SUCCESS;
}

Es wurde hier nur die Zeile

int wert_auto[5] = { 0 };

verändert und wert_auto[0] mit dem Wert 0 initialisiert. Die Ausgabe des Programms zeigt jetzt (erwartungsgemäß) die initialisierten Werte.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.4   Gültigkeitsbereich von Variablen

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de