B.8 Antworten und Lösungen zu Kapitel 9
-
Arrays sind Datenstrukturen, in denen sich mehrere Werte eines bestimmten Typs speichern und bearbeiten lassen. Der Zugriff auf die Daten erfolgt mithilfe des Indizierungsoperators [] über einen Index. Ein Array kann eine oder auch mehrere Dimensionen haben und so sowohl als eine Folge von Werten (z. B. in einem String) als auch z. B. als Tabelle abgelegt werden.
-
Zunächst einmal sind Strings nichts anderes als Arrays vom Datentyp char (bzw. wchar_t). Allerdings sind die char-Arrays die einzige Möglichkeit, um eine Folge von Zeichen, also einen String, auch Zeichenkette genannt, zu speichern. Einen eigenen Datentyp für Strings gibt es in C nicht. Wichtig bei einem char-Array: Damit Sie diesen auch wirklich als echten String verwenden können, müssen Sie ihn mit einem Null-Zeichen oder auch Stringende-Zeichen '\0' abschließen. Demnach muss ein String immer um ein Zeichen länger als die Anzahl der relevanten Zeichen sein, damit das Stringende-Zeichen am Ende auch noch Platz hat.
-
Die größte Gefahr geht davon aus, dass Sie mehr Daten in ein Array oder einen String schreiben, als Speicherplatz dafür vorhanden ist. Haben Sie beispielsweise ein Array mit 10 Elementen angelegt, und schreiben Sie 11 Elemente in das Array, weil Sie den Indexbereich versehentlich überschreiten, haben Sie einen Pufferüberlauf provoziert. Häufig beendet sich das Programm dann mit einem Speicherzugriffsfehler. Ein solcher Fehler kann aber nur schwer gefunden werden und eventuell auch zu falschen Rechenergebnissen führen. In der Netzwerkprogrammierung kann dies ganz böse Folgen haben, weil sich solche Fehler für Angriffe ausnutzen lassen, mit denen z. B. Viren auf dem jeweiligen Rechner eingeschleust werden können. Ein populäres Beispiel aus den letzten Jahren ist ein Pufferüberlauf in der Ladebibliothek für JPEG-Bilder auf verschiedenen Browsern. Hierdurch ließen sich verschiedene Trojaner einschleusen, die Login-Daten und Passwörter der infizierten Rechner ausspionieren konnten.
-
Ein beliebter Anfängerfehler ist es zu vergessen, dass das erste Element eines Arrays bzw. Strings immer mit der Indexnummer 0 beginnt und das letzte Element immer die Indexnummer N-1 (N ist die angegebene Array-Größe) hat. Daher wird hier oft ein Überlauf erzeugt, weil auf die Indexnummer N anstatt auf N-1 zugegriffen wird. Bei Strings wird häufig vergessen, dass noch Platz für das Stringende-Zeichen vorhanden sein muss.
-
In der for-Schleife in Zeile (06) wurden gleich zwei Fehler gemacht. Da i mit MAX initialisiert wurde, wurde dem Array mit dem Index 10 ein Wert übergeben. Somit wäre dies ein Array-Überlauf, weil die Indexnummern nur von 0 bis 9 gehen. Des Weiteren würde durch die Überprüfung, ob i größer als 0 ist, das Array-Element mit dem Index 0 nicht initialisiert. In der for-Schleife in Zeile (06) muss daher MAX-1 an i übergeben werden, und die Schleifenbedingung sollte auf größer-gleich 0 geprüft werden:
06 for(int i = MAX-1; I >= 0; i--) {
-
Dass das char-Array v in Zeile (05) nicht mit \0 abgeschlossen wird, ist nicht der Fehler. Der Fehler wird erst in Zeile (10) des Programms gemacht. Dort wird das char-Array als String behandelt. Das sollten Sie vermeiden, wenn kein Stringende-Zeichen vorhanden ist. Sie haben folgende zwei Möglichkeiten, damit v als korrekter String angesehen werden kann:
char v[6] = { 'A', 'E', 'I', 'O', 'U', '\0' };
char v[6] = { "AEIOU" }; -
Hier eine mögliche Musterlösung der Aufgabe:
00 // kap009/loesung001.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <string.h>
04 int main(void) {
05 int iarr[] = { 2, 4, 6, 4, 2, 4, 5, 6, 7 };
06 double darr[] = { 3.3, 4.4, 2.3, 5.8, 7.7 };
07 char str[] = { "Hallo Welt"};
08 printf("iarr: %zu Bytes\n", sizeof(iarr));
09 printf("iarr: %zu Elemente\n", sizeof(iarr)/sizeof(int));
10 printf("darr: %zu Bytes\n", sizeof(darr));
11 printf("darr: %zu Elemente\n", sizeof(darr)/sizeof(double));
12 printf("str : %zu Bytes\n", sizeof(str));
13 printf("str : %zu Elemente (sizeof)\n", sizeof(str)/
sizeof(char));
14 printf("str : %zu Elemente (strlen)\n", strlen(str)+1);
15 return EXIT_SUCCESS;
16 }Das Programm gibt bei der Ausführung Folgendes aus:
iarr: 36 Bytes
iarr: 9 Elemente
darr: 40 Bytes
darr: 5 Elemente
str : 11 Bytes
str : 11 Elemente (sizeof)
str : 11 Elemente (strlen) -
Hierzu eine Musterlösung:
00 // kap009/loesung002.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #define EQUAL -1
04 #define DIFFSIZE -2
05 int vergleich( int arr1[], int n1, int arr2[], int n2 ) {
06 if(n1 != n2) {
07 return DIFFSIZE; // Arrays unterschiedlich lang
08 }
09 for(int i=0; i < n1; i++) {
10 if( arr1[i] != arr2[i] ) {
11 return i; // Indexnummer mit Unterschied
12 }
13 }
14 return EQUAL; // Beide Arrays sind identisch
15 }
16 int main(void) {
17 int iarr1[] = { 2, 1, 4, 5, 6, 2, 1 };
18 int iarr2[] = { 2, 1, 4, 6, 6, 2, 1 };
19 int ret = vergleich( iarr1,(sizeof(iarr1)/sizeof(int)),
iarr2,(sizeof(iarr2)/sizeof(int)));
20 if( ret == DIFFSIZE ) {
21 printf("Die Arrays sind unterschiedlich lang\n");
22 }
23 else if( ret == EQUAL ) {
24 printf("Beide Arrays sind identisch\n");
25 }
26 else {
27 printf("Unterschied an Pos. %d gefunden\n", ret);
28 }
29 return EXIT_SUCCESS;
30 } -
Hierzu eine Musterlösung:
00 // kap009/loesung003.c
01 #include <stdio.h>
02 #include <stdlib.h>
03 #include <string.h>
04 #define MAX 255
05 void ersetzen( char arr[], int n, char ch1, char ch2 ) {
06 for(int i=0; i < n; i++ ) {
07 if( arr[i] == ch1 ) {
08 arr[i] = ch2;
09 }
10 }
11 }
12 int main(void) {
13 char str[MAX];
14 printf("Bitte Mustertext eingeben: ");
15 if( fgets( str, MAX, stdin ) == NULL ) {
16 printf("Fehler bei der Eingabe\n");
17 return EXIT_SUCCESS;
18 }
19 // 'a' gegen 'x' ersetzen
20 ersetzen( str, strlen(str), 'a', 'x');
21 printf("%s\n", str);
22 return EXIT_SUCCESS;
23 }