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

Inhaltsverzeichnis
Vorwort
Vorwort des Gutachters
1 Einstieg in C
2 Das erste Programm
3 Grundlagen
4 Formatierte Ein-/Ausgabe mit »scanf()« und »printf()«
5 Basisdatentypen
6 Operatoren
7 Typumwandlung
8 Kontrollstrukturen
9 Funktionen
10 Präprozessor-Direktiven
11 Arrays
12 Zeiger (Pointer)
13 Kommandozeilenargumente
14 Dynamische Speicherverwaltung
15 Strukturen
16 Ein-/Ausgabe-Funktionen
17 Attribute von Dateien und das Arbeiten mit Verzeichnissen (nicht ANSI C)
18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
19 Zeitroutinen
20 Weitere Headerdateien und ihre Funktionen (ANSI C)
21 Dynamische Datenstrukturen
22 Algorithmen
23 CGI mit C
24 MySQL und C
25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
26 Paralleles Rechnen
27 Sicheres Programmieren
28 Wie geht’s jetzt weiter?
A Operatoren
B Die C-Standard-Bibliothek
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch
Buch: C von A bis Z

C von A bis Z
3., aktualisierte und erweiterte Auflage, geb., mit CD und Referenzkarte
1.190 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1411-7
Pfeil 11 Arrays
Pfeil 11.1 Arrays deklarieren
Pfeil 11.2 Initialisierung und Zugriff auf Arrays
Pfeil 11.2.1 Gültigkeitsbereich von Arrays
Pfeil 11.3 Arrays vergleichen
Pfeil 11.4 Anzahl der Elemente eines Arrays ermitteln
Pfeil 11.5 Übergabe von Arrays an Funktionen
Pfeil 11.6 Arrays aus Funktionen zurückgeben
Pfeil 11.7 Programmbeispiel zu den Arrays
Pfeil 11.8 Einlesen von Array-Werten
Pfeil 11.9 Mehrdimensionale Arrays
Pfeil 11.9.1 Mehrdimensionale Arrays initialisieren
Pfeil 11.9.2 Übergabe von zwei- bzw. mehrdimensionalen Arrays an Funktionen
Pfeil 11.10 Arrays in Tabellenkalkulation einlesen (*.CSV–Dateien)
Pfeil 11.11 Strings/Zeichenketten (»char«-Array)
Pfeil 11.11.1 Vom String zur Binärzahl
Pfeil 11.12 Einlesen von Strings
Pfeil 11.13 Die Standard-Bibliothek <string.h>
Pfeil 11.13.1 »strcat()« – Strings aneinanderhängen
Pfeil 11.13.2 »strchr()« – ein Zeichen im String suchen
Pfeil 11.13.3 »strcmp()« – Strings vergleichen
Pfeil 11.13.4 »strcpy()« – einen String kopieren
Pfeil 11.13.5 »strcspn()« – einen Teilstring ermitteln
Pfeil 11.13.6 »strlen()« – Länge eines Strings ermitteln
Pfeil 11.13.7 »strncat()« – String mit n Zeichen aneinanderhängen
Pfeil 11.13.8 »strncmp()« – n Zeichen von zwei Strings miteinander vergleichen
Pfeil 11.13.9 »strncpy()« – String mit n Zeichen kopieren
Pfeil 11.13.10 »strpbrk()« – nach dem Auftreten bestimmter Zeichen suchen
Pfeil 11.13.11 »strrchr()« – das letzte Auftreten eines bestimmten Zeichens im String suchen
Pfeil 11.13.12 »strspn()« – das erste Auftreten eines Zeichens, das nicht vorkommt
Pfeil 11.13.13 »strstr()« – einen String nach dem Auftreten eines Teilstrings durchsuchen
Pfeil 11.13.14 »strtok()« – einen String anhand bestimmter Zeichen zerlegen


Rheinwerk Computing - Zum Seitenanfang

11.2 Initialisierung und Zugriff auf Arrays Zur nächsten ÜberschriftZur vorigen Überschrift

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 11.2 Ein Array mit Werten initialisieren

Sie sehen hier 5 Zahlen: 0, 1, 2, 3 und 4. Befände sich im Programm die 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 geschieht. Wird hier der Indexbereich überschritten, kann es passieren, dass mit falschen Werten weitergearbeitet wird. Hier ein Beispiel für einen Fehler, der leider oft gemacht wird:

/* 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 elfmal 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 bei der Verwendung von Arrays im Zusammenhang mit Schleifen Vorsicht geboten, und Sie müssen genau darauf 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 Variable vom Datentyp int ist und somit auch einer Ordinalzahl entspricht. Die 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 bei längeren Programmen erheblich verbessern und tragen dazu bei, Fehler zu vermeiden. 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. Anstatt 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 20.8  */
#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 Wert 16843009 bedeuten (alle Bits auf 1).

Hier noch ein weiteres Beispiel zur Initialisierung von Arrays:

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

Internes

memset() kann unter Umständen schneller sein als eine for-Schleife, da memset() viel näher an der Hardware operiert und eventuell deren Funktionalität ausbeuten kann (z. B. ist es viel sinnvoller, einen char[512] mit 128 0-longs zu belegen, anstatt 512-mal eine 0 zu speichern). memset() funktioniert außerdem auch bei multidimensionalen Arrays ohne Pointer, 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 Arrays. Sollte das Programm bei Ihnen gleich nach dem Start abstürzen und verwenden Sie ein recht großes Array, dann könnte ein global definiertes Array Abhilfe schaffen.



Rheinwerk Computing - Zum Seitenanfang

11.2.1 Gültigkeitsbereich von Arrays topZur vorigen Überschrift

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;
}

Abbildung 11.3. zeigt die Ausgabe des Programms am Bildschirm.

Abbildung 11.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 11.4 Gültigkeitsbereich von Variablen



Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: C/C++






 C/C++


Zum Katalog: Einstieg in C






 Einstieg in C


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
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.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de