Arrays. 7.1 Was ist ein Array? Kapitel 7. In diesem Kapitel lernen Sie. Array-Variablen deklarieren

Datei: 07.doc, Seite101 31. Oktober 2006 Kapitel 7 Arrays „ was man in C# unter einem Array versteht „ wie Sie ein Array deklarieren „ wie Sie ...
Author: Catrin Sauer
76 downloads 1 Views 764KB Size
Datei: 07.doc, Seite101 31. Oktober 2006

Kapitel 7

Arrays „

was man in C# unter einem Array versteht

„

wie Sie ein Array deklarieren

„

wie Sie ein Array initialisieren (mit Daten vorbelegen)

„

wie Sie die Elemente eines Arrays ansprechen und bearbeiten

„

was mehrdimensionale Arrays sind

„

nützliche Methoden für den Zugriff auf Arrays kennen

„

was eine ArrayList ist

II – Grundlagen von C#

In diesem Kapitel lernen Sie

7.1 Was ist ein Array? In diesem Kapitel stellen wir Ihnen Arrays vor, die auch als Datenfelder bezeichnet werden. Unter einem Array versteht man die Zusammenfassung mehrerer Variablen des gleichen Typs, die unter einem gemeinsamen Namen angesprochen werden können. Die Variablen werden dabei im Speicher direkt hintereinander, also gewissermaßen »am Stück«, abgelegt. Da die Speicherzugriffe bei dieser Anordnung besonders effizient sind, werden vor allem Operationen, die mehrere Elemente eines Arrays ansprechen, sehr performant. Um die Wirkungsweise eines Arrays zu verstehen, können Sie es mit einer CD-Sammlung vergleichen. Höchstwahrscheinlich bewahren Sie Ihre CDs ja nicht in einer großen Tasche oder in einem Wäschekorb auf, sondern haben sie nebeneinander in ein Regal gestellt. Und Sie werden auch kaum zwischen Ihren CDs irgendwelche anderen Dinge wie Bücher, Landkarten oder Fotos stehen haben. Natürlich würden Sie Ihre CDs dann immer noch finden, aber am schnellsten funktioniert es halt, wenn die CDs fein säuberlich in einer Reihe stehen, denn bei dieser Anordnung lassen sich die CDs am bequemsten und schnellsten »durchblättern«.

Array-Variablen deklarieren In Kapitel 4 haben Sie bereits gelernt, dass Sie eine Variable zuerst deklarieren müssen, bevor Sie sie im Programm verwenden können. Bei dieser Deklaration werden zum einen der Name der Variablen und zum anderen ihr Datentyp festgelegt. Im Falle einer Array-Variable sieht die entsprechende Anweisung zum Beispiel so aus: int[] quadratzahlen;

101 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite102 31. Oktober 2006

Kapitel 7

Arrays

Wenn Sie diese Anweisung mit der Deklaration einer »normalen« Variablen vergleichen, also mit int quadratzahl;

fällt unmittelbar auf, dass sich die beiden Anweisungen nur durch die leeren eckigen Klammern unterscheiden. Und genau diese Klammern sind es, die festlegen, dass es sich bei der Variablen quadratzahlen um ein Array handelt. Die einzelnen Elemente dieses Arrays besitzen in diesem Beispiel den Datentyp int. Wenn Sie bereits Erfahrungen mit anderen Programmiersprachen haben, wird Ihnen aufgefallen sein, dass in der Deklaration keine Angabe über die Größe des Arrays gemacht wird. Hier unterscheidet sich C# von anderen Sprachen, denn bei C# ist die Angabe der Arraygröße bei der Deklaration unzulässig.

Array-Variablen instanzieren Nach der Deklaration einer Variablen ist dem Compiler zunächst nur der Name und der Datentyp der neuen Variable bekannt. Bevor Sie mit einer Array-Variablen arbeiten können, müssen Sie noch eine Instanz der Variablen erstellen: quadratzahlen = new int[10];

Erst diese Anweisung sorgt dafür, dass der Variablen Speicherplatz zur Verfügung gestellt wird. Und jetzt muss natürlich auch die gewünschte Größe des Arrays angegeben werden, um dessen Speicherbedarf zu ermitteln. In diesem Beispiel haben wir dazu eine Zahl verwendet, es ist aber auch möglich, die Größe des Arrays mit Hilfe einer Variablen anzugeben. Dies ist zum Beispiel dann sinnvoll, wenn die benötigte Größe erst zur Laufzeit bekannt ist. Der erzeugten Variablen wird die Adresse des reservierten Speicherbereichs zugewiesen (bei ArrayVariablen handelt es sich also nicht um Wert-, sondern um Verweistypen). Außerdem wird bei diesem Vorgang noch der Speicherplatz der Array-Variablen automatisch initialisiert, und zwar je nach verwendetem Datentyp mit 0, null oder false. Im Falle unseres Arrays quadratzahlen könnte die Speicherbelegung zum Beispiel so aussehen: Adresse

Variable

Inhalt

quadratzahlen

2.000.000

2.000.040 2.000.036 2.000.032 2.000.028 2.000.024 2.000.020 2.000.016 2.000.012 2.000.008 2.000.004 2.000.000 1.999.999

Inhalt

? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?

Abbildung 7.1: In der Variablen quadratzahlen befindet sich die Adresse des zugehörigen Speicherplatzes.

102 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite103 31. Oktober 2006

7.2 Elemente eines Arrays ansprechen

Die in der Abbildung angegebenen Adressen sind der Einfachheit halber in dezimaler Schreibweise angegeben. Wie Sie sehen, belegt das Array die Speicherzellen von 2.000.000 bis einschließlich 2.000.039, also insgesamt 40 Byte. Wenn Sie sich noch einmal die Tabelle aus Kapitel 4 vor Augen führen, in der der Speicherbedarf der verschiedenen Integer-Datentypen aufgeführt ist, wird dieser Wert sofort nachvollziehbar: Ein einzelnes int belegt 4 Byte, d. h. ein Array aus zehn int benötigt dementsprechend 40 Byte.

Es ist auch möglich, ein Array mit individuellen Werten zu initialisieren. Dazu geben Sie die gewünschten Werte einfach hinter der Variablen innerhalb von geschweiften Klammern an: quadratzahlen = new int[10] {1, 4, 9, 16, 25, 36, 49, 64, 81, 100};

Die Elemente dieser Liste müssen dabei in Datentyp und Anzahl mit der Deklaration der ArrayVariablen übereinstimmen. Es ist also zum Beispiel nicht möglich, nur einen Teil des Arrays manuell zu initialisieren und für den Rest die automatische Vorbelegung zu übernehmen. Die Deklaration und die Instanziierung einer Array-Variablen lassen sich auch in einer Zeile erledigen: int[] quadratzahlen = new int[10];

Und sogar die manuelle Initialisierung lässt sich noch in der Zeile unterbringen: int[] quadratzahlen = new int[10] {1, 4, 9, 16, 25, 36, 49, 64, 81, 100};

Wenn Sie diese Anweisung einmal genauer betrachten, wird Ihnen wahrscheinlich auffallen, dass sie redundante Informationen enthält. Und zwar wird durch die manuelle Initialisierung die Größenangabe des Arrays überflüssig. Der Compiler kann ja anhand der Liste mit den Initialisierungswerten problemlos erkennen, wie viele Elemente das Array erhalten soll. (Erinnern Sie sich? Die Anzahl der Elemente muss mit der Arraygröße korrespondieren). So ist es nur logisch, dass für die letzte Anweisung folgende Kurzform gültig ist: int[] quadratzahlen = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100};

Achtung: Diese Form der Wertzuweisung ist nur bei der Initialisierung erlaubt! Die Schreibweise mit den geschweiften Klammern, die wir Ihnen gerade vorgestellt haben, können Sie nur bei der Initialisierung einer Array-Variablen verwenden. Sobald die Variable einmal erzeugt ist, ist diese Wertzuweisung nicht mehr möglich.

7.2 Elemente eines Arrays ansprechen Wir haben im letzten Abschnitt bereits kurz erwähnt, dass dem Namen einer Array-Variablen die Adresse des zugehörigen Speicherbereichs zugewiesen wird. Wie können Sie jedoch die zehn Variablen aus unserem Beispiel einzeln ansprechen? Ganz einfach: Die verschiedenen Elemente des Arrays werden durchnummeriert und lassen sich über diese Nummer, die als Index bezeichnet wird, gezielt ansprechen. Probieren Sie es doch gleich mal aus: 103 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

II – Grundlagen von C#

Array-Variablen manuell initialisieren

Datei: 07.doc, Seite104 31. Oktober 2006

Kapitel 7

Arrays

1. Erstellen Sie ein neues Projekt vom Typ Konsolenanwendung und geben Sie ihm den Namen In-

dex. 2. Ergänzen Sie das Codegerüst um die beiden Zeilen: int[] quadratzahlen = { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 }; Console.WriteLine(quadratzahlen[5]);

3. Starten Sie das Programm mit Strg+F5 und interpretieren Sie das angezeigte Ergebnis.

Wie Sie sehen, wird die Nummer des gewünschten Elements einfach hinter dem Namen der Variable in eckigen Klammern angegeben. Der Ausdruck quadratzahlen[5] liefert allerdings den Wert 36, der sich nicht an der fünften, sondern erst an der sechsten Stelle des Arrays befindet. Die Erklärung für diesen scheinbaren Fehlgriff: Die Nummerierung beginnt nicht bei 1, sondern bei 0. Diese auf den ersten Blick unsinnige Regelung wird verständlicher, wenn man den Ausdruck quadratzahlen[5] so interpretiert: »Nimm die in quadratzahlen gespeicherte Adresse und gehe 5 Elemente weiter«. Will man also das erste Element des Arrays ansprechen, muss man nach dieser Regel 0 Schritte weitergehen, da die Adresse des ersten Elements mit der in quadratzahlen abgelegten Adresse des Arrays identisch ist. 4. Ändern Sie das Programm, indem Sie [5] durch [10] ersetzen. Starten Sie das Programm diesmal

mit F5 (Debuggen/Debuggen starten). static void Main(string[] args) { int[] quadratzahlen = { 1, 4, 9, 16, 25, 36, 49, 64, 81, 100 }; Console.WriteLine(quadratzahlen[10]); }

Wie Sie sehen, hat das Programm jetzt eine Ausnahme ausgelöst, da Sie versucht haben, auf das elfte Element des Arrays zuzugreifen. Da das Array in diesem Beispiel jedoch nur 10 Elemente enthält, würde der Ausdruck quadratzahlen[10] auf einen Speicherbereich außerhalb des Arrays zugreifen. Genau das ist aber unzulässig und führt zu der erwähnten Ausnahme. Sicherheit durch rigorose Überwachung der Speicherzugriffe Dass ein Zugriff auf fremden Speicher dermaßen konsequent geahndet wird, hat seinen guten Grund. Die Vergangenheit hat nämlich gezeigt, dass viele Programme nicht ausreichend vor solchen »Fehlgriffen« geschützt sind. Diese Bereichsüberschreitungen führen aber häufig zu schweren Programmabstürzen, weil dabei schnell wichtige Speicherbereiche überschrieben werden können. Und auch viele Viren nutzen solche Schwachstellen gezielt aus, um eigenen Virencode in andere Programme einzuschleusen. Das .NET Framework schiebt solchen Versuchen nun einen dicken Riegel vor.

Alle Elemente eines Arrays durchlaufen Bisher haben wir nur auf ein einzelnes Array-Element zugegriffen. Häufig müssen jedoch alle Elemente eines Arrays angesprochen werden. Diese Aufgabe lässt sich sehr elegant mit einer for-Schleife lösen, die wir Ihnen im letzten Kapitel vorgestellt haben. Stellen Sie sich zum Beispiel vor, Sie wollten im Array quadratzahlen jetzt die ersten tausend Quadratzahlen speichern. In diesem Fall wäre natürlich eine Initialisierung, wie wir sie im letzten Abschnitt vorgenommen haben, völlig unpraktikabel. Viel schneller und sicherer geht es so: 104 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite105 31. Oktober 2006

7.2 Elemente eines Arrays ansprechen int[] quadratzahlen = new int[1000]; for (int i = 0; i < 1000; i++) quadratzahlen[i] = i * i;

Das Problem lässt sich in C# jedoch leicht lösen. Sie können nämlich die Größe eines Arrays, d. h. die Anzahl seiner Elemente, während der Laufzeit ermitteln. Dazu rufen Sie die Eigenschaft Length der Array-Variablen auf, die genau diese Information liefert. Die geänderte for-Schleife sieht dann so aus: for (int i = 0; i < quadratzahlen.Length; i++) quadratzahlen[i] = i * i;

Arrays mit foreach durchlaufen In C# existiert eine weitere Anweisung, mit der sich Arrays sogar noch bequemer als mit der for-Schleife durchlaufen lassen. Sie heißt foreach und wird folgendermaßen verwendet: foreach (int i in quadratzahlen) Console.WriteLine(i);

Die foreach-Anweisung durchläuft automatisch alle Elemente des Arrays und weist dabei den Wert des aktuellen Elements der Variablen i zu. Das heißt, die Variable i ist in diesem Fall kein Schleifenzähler! Deshalb muss diese Variable auch den gleichen Datentyp besitzen wie die Array-Elemente. Da sich der Zugriff auf ein Array mit foreach so elegant lösen lässt, liegt der Versuch nahe, die foreachAnweisung auch für die Initialisierung eines Array zu verwenden. Also zum Beispiel: string[] nachnamen = new string[10]; foreach (string s in nachnamen) s = "N.N.";

Wenn Sie diese Anweisung kompilieren, erhalten Sie eine Fehlermeldung des Compilers. Die in der foreach-Anweisung verwendete Variable ist nämlich eine so genannte Iterationsvariable, auf die Sie nur lesend zugreifen dürfen.

105 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

II – Grundlagen von C#

Beachten Sie, dass der Schleifenzähler i die Werte von 0 bis 999 durchläuft (und nicht von 1 bis 1000). So elegant diese Lösung auf den ersten Blick auch aussieht – sie hat noch einen kleinen Schönheitsfehler: Dadurch, dass in der Abbruchbedingung die Größe des Arrays als konstanter Wert verwendet wird, laufen Sie Gefahr, das Array nur teilweise zu initialisieren oder sogar eine IndexOutOfRange-Ausnahme auszulösen, wenn Sie die Größe des Arrays ändern und dabei vergessen, die for-Schleife entsprechend anzupassen.

Datei: 07.doc, Seite106 31. Oktober 2006

Kapitel 7

Arrays

Abbildung 7.2: Die foreach-Anweisung erlaubt nur lesende Zugriffe.

Größe eines Arrays ändern Wir hatten zu Beginn des Kapitels gesagt, dass die Größe eines Arrays bei seiner Instanziierung festgelegt werden muss. Das ist vom Prinzip her auch richtig, doch es gibt in der Praxis durchaus Situationen, in denen es vorteilhaft wäre, wenn man die Größe eines Arrays während des Programmablaufs verändern könnte. Die eigentliche Schwierigkeit ist natürlich das Vergrößern des Arrays, denn der Speicherbereich eines Arrays muss bekanntlich zusammenhängend sein. Da aber der Speicherplatz direkt hinter einem Array mit nahezu hundertprozentiger Wahrscheinlichkeit bereits belegt ist, gibt es nur eine Möglichkeit, um ein Array zu vergrößern: Es muss ein neues Array der gewünschten Größe erstellt und anschließend der Inhalt des alten Arrays hineinkopiert werden. Außerdem müssen alle Variablen angepasst werden, die auf das alte Array verweisen. Zum Schluss kann dann das alte Array gelöscht werden. Seit der Version 2.0 des .NET Framework existiert in der Klasse Array eine Methode, die genau diese Aufgaben für Sie erledigt. Die Methode erwartet dazu einen Verweis auf das zu ändernde Array und die neue Anzahl der Elemente. Mit der folgenden Anweisung können Sie zum Beispiel die Größe des Arrays quadratzahlen verdoppeln: Array.Resize(ref quadratzahlen, quadratzahlen.Length * 2);

Unabhängig davon, ob Sie ein Array vergrößern oder verkleinern, erstellt die Resize-Methode in jedem Fall ein neues Array bereit. (Wenn das Array bereits die gewünschte Größe besitzt, bleibt die Methode wirkungslos). Wird das Array verkleinert, fallen beim anschließenden Kopieren die überschüssigen Elemente weg. Beim Vergrößern bleiben demnach die zusätzlichen Elemente des neuen Arrays leer bzw. behalten die Werte, mit denen das Array beim Erstellen initialisiert wurde (je nach Datentyp der Elemente mit 0, null oder false). 106 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite107 31. Oktober 2006

7.3 Mehrdimensionale Arrays

7.3 Mehrdimensionale Arrays Bisher haben wir Sie nur mit eindimensionalen Arrays bekannt gemacht. In C# ist es jedoch auch möglich, mehrdimensionale Arrays zu erstellen. Das einfachste mehrdimensionale Array ist naturgemäß das zweidimensionale, an dem wir Ihnen den Umgang mit mehrdimensionalen Arrays erklären werden.

Die Deklaration eines mehrdimensionalen Array erfolgt analog zu den eindimensionalen Arrays: int[,] spielfeld1;

Die neue Dimension wird also durch ein zusätzliches Komma zwischen den eckigen Klammern angegeben. Dementsprechend sieht die Instanziierung einer der Array-Variablen für unser Beispiel so aus: int[,] spielfeld1 = new int[10,10];

Auch wenn Sie das Array manuell initialisieren wollen, gehen Sie analog zum eindimensionalen Fall vor. Allerdings ist diese Form der Initialisierung bei mehreren Dimensionen deutlich unhandlicher: int[,] arr2d = new int[2, 4] { { 1, 2, 3, 4}, {5, 6, 7, 8} };

Die erste Zahl in den eckigen Klammern gibt also die Dimension in den äußeren geschweiften Klammern an, die zweite Zahl die Dimension der zweiten geschweiften Klammerebene und so weiter. Das nächste Beispiel zeigt die Initialisierung für ein dreidimensionales Array und Sie sehen, die Angelegenheit wird langsam unübersichtlich: int[, ,] arr3d = new int[2, 3, 4] { { { 1, 2, 3, 4}, { 5, 6, 7, 8}, { 9, 10, 11, 12} }, { {13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24} } };

Um auf ein bestimmtes Element eines mehrdimensionalen Arrays zuzugreifen, müssen Sie für jede Dimension den gewünschten Index angeben. Wenn Sie zum Beispiel im Array spielfeld1 dem Element, das sich in der dritte Zeile (1. Dimension) und dort in der zweiten Spalte (2. Dimension) befindet, eine 1 zuweisen wollen, lautet die entsprechende Anweisung: Spielfeld1[2,1] = 1;

Mehrdimensionale Arrays durchlaufen Um alle Elemente eines mehrdimensionalen Arrays zu durchlaufen, verwendet man üblicherweise verschachtelte for-Schleifen. Für jede Dimension benötigt man eine separate Schleife mit einer eigenen Schleifenvariablen. Um z. B. das Spielfeld aus dem letzten Beispiel auszugeben, können Sie folgenden Code verwenden, dessen Ausgabe Sie im nächsten Bild sehen (das vollständige Programm finden Sie im Beispielordner Kap07\SchiffeVersenken): for (int zeile = 0; zeile < 10; zeile++) { for (int spalte = 0; spalte < 10; spalte++) { Console.Write(spielfeld1[zeile, spalte]); } Console.WriteLine(); }

107 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

II – Grundlagen von C#

Stellen Sie sich vor, Sie wollten ein Programm erstellen, mit dem man Schiffe versenken spielen kann. Das Spielfeld soll aus 10 Spalten und 10 Zeilen bestehen, hat also insgesamt 100 Felder. Wenn Sie nun diese Felder in einem eindimensionalen Array verwalten würden, müssten Sie bei jedem Zugriff auf das Array die Zeilen- und Spaltenangaben umrechnen. Mit einem zweidimensionalen Array können Sie sich diesen Umstand ersparen, denn es ist genauso aufgebaut wie Ihr Spielfeld.

Datei: 07.doc, Seite108 31. Oktober 2006

Kapitel 7

Arrays

Abbildung 7.3: Der Inhalt des zweidimensionalen Arrays wurde mit zwei verschachtelten for-Schleifen ausgegeben.

Array-Elemente mit foreach durchlaufen Die foreach-Anweisung lässt sich nur für eindimensionale Arrays verwenden. Bei mehrdimensionalen Arrays kommen Sie also um eine »echte« Schleifenkonstruktion nicht herum.

7.4 Nützliche Methoden für Arrays Sie haben in den letzten Abschnitten bereits zwei Methoden kennengelernt, die Sie im Zusammenhang mit Arrays verwenden können. Natürlich gibt es in C# noch viele andere Methoden, von denen wir Ihnen nun einige besonders wichtige und nützliche vorstellen möchten.

Die GetLength-Methode Die Length-Eigenschaft haben wir zwar bereits in einem Beispiel eingesetzt und erläutert, aber im Zusammenhang mit mehrdimensionalen Arrays müssen wir noch einige Informationen nachtragen. Angenommen, Sie haben mit folgender Anweisung ein zweidimensionales Array erzeugt: int[,] matrix = new int[3,4];

Zum Initialisieren dieses Arrays wollen Sie zwei verschachtelte for-Schleifen benutzen. So weit, so gut. Da Sie sich an unseren Hinweis auf die Length-Eigenschaft (siehe Seite 105) erinnern, möchten Sie die Abbruchbedingung der for-Schleifen flexibel halten und in ihr keine konstanten Werte verwenden. Kann Ihnen die Length-Eigenschaft hier weiterhelfen? Nein, denn diese Eigenschaft liefert immer die Gesamtanzahl aller Elemente eines Arrays, im aktuellen Beispiel also 12. Sie benötigen hingegen eine Möglichkeit, um die Anzahl der Elemente einer bestimmten Dimension des Arrays zu ermitteln. Die Lösung ist in diesem Fall die Methode GetLength(), deren Einsatz Sie im nächsten Beispiel studieren können: 108 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite109 31. Oktober 2006

7.4 Nützliche Methoden für Arrays for (int i = 0; i < matrix.GetLength(0); i++) for (int j = 0; j < matrix.GetLength(1); j++) matrix[i, j] = i + j;

Wie Sie sehen, erwartet die Methode GetLength() als einzigen Parameter die Angabe der gewünschten Dimension, wobei die erste Dimension den Wert 0 hat.

Mit der Methode CopyTo() lassen sich Daten zwischen eindimensionalen Arrays kopieren. Die Methode erwartet als Parameter das Zielarray sowie den Index des Zielarrays, an dem mit dem Einfügen der Daten begonnen werden soll. Im folgenden Codeschnipsel wird der Inhalt von array1 nach array2 kopiert, wobei der Einfügevorgang in array2 beim zehnten Element beginnt: int[] array1 = new int[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int[] array2 = new int[25]; array1.CopyTo(array2, 10);

Wenn Sie anschließend den Inhalt von array2 auf dem Bildschirm ausgeben (z. B. mit einer foreachAnweisung) erhalten Sie folgende Ausgabe: 00000000001234567891000000

C# kennt auch noch eine leistungsfähigere Methode zum Kopieren von Array-Elementen. Es handelt sich um die Methode Copy(), die auch mit mehrdimensionalen Arrays verwendet werden kann. Außerdem können Sie bei dieser Methode den Bereich im Quell-Array festlegen, der von der Methode kopiert werden soll. Weitere Informationen zu dieser Methode finden Sie in der Online-Hilfe.

Arrays duplizieren Da es sich bei Array-Variablen um Verweistypen handelt, lassen sie sich mit einer einfachen Zuweisung nicht kopieren. Der folgende Code erstellt also kein Duplikat von array1, sondern er erreicht lediglich, dass die Variable array2 anschließend auf die gleiche Arrayinstanz, also den gleichen Speicherbereich, wie array1 zeigt: int[] array1 = new int[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int[] array2; array2= array1;

Um tatsächlich eine Kopie eines Arrays anzulegen, müssen Sie sich wieder der Hilfe einer Methode bedienen. Sie trägt in diesem Fall den Namen Clone und wird folgendermaßen verwendet: int[] array1 = new int[10] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int[] array2; array2 = (int[]) array1.Clone();

Die Typumwandlung durch (int[]) ist erforderlich, da die Methode ein Objekt zurückgibt und der Compiler keine implizite Typumwandlung vornimmt. Bei der erzeugten Kopie handelt es sich um eine sogenannte flache Kopie. Damit ist gemeint, dass lediglich die Daten des Arrays selbst, nicht jedoch die Daten der Objekte, auf die im Array eventuell verwiesen wird, kopiert werden.

109 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

II – Grundlagen von C#

Daten zwischen Arrays kopieren

Datei: 07.doc, Seite110 31. Oktober 2006

Kapitel 7

Arrays

7.5 Die Klasse ArrayList Wenn Sie mehrere Elemente verwalten möchten, deren Anzahl und Anordnung sich während der Laufzeit des Programms regelmäßig ändern, bietet ein normales Array zu wenig Flexibilität. Wie Sie in den letzten Abschnitten gesehen haben, ist es zwar möglich, Arrays nachträglich zu vergrößern und ihren Inhalt umzukopieren, aber der Aufwand, um zum Beispiel ein neues Element an einer bestimmten Position des Arrays einzufügen, wäre einfach zu groß und hätte mit gradliniger Programmierung nicht mehr viel zu tun. Für solche Fälle ist in C# die Klasse ArrayList aus dem Namensraum System.Collections prädestiniert. Dabei handelt es sich um einen Datentyp, der zwar viel Ähnlichkeit mit den zuvor besprochenen Arrays hat, dem jedoch ein vollständig anderes Speicherkonzept zugrunde liegt. Variablen vom Datentyp ArrayList werden nämlich nicht in einem zusammenhängenden Bereich im Speicher abgelegt, sondern als Liste verwaltet. Außerdem handelt es sich um Verweistypen, d. h. in solch einer Liste können die Elemente einen beliebigen Datentyp annehmen. Dem damit einhergehenden Performanceverlust steht ein enormer Zugewinn an Flexibilität gegenüber. Um eine neue Instanz der ArrayList-Klasse zu erstellen, können Sie im einfachsten Fall folgende Anweisung verwenden. (Dazu müssen Sie natürlich vorher mit using den Namensraum System.Collections bekannt machen.): ArrayList arrayListe = new ArrayList();

Hierdurch wird eine leere ArrayListe der Kapazität 0 erzeugt. Die Kapazität einer ArrayListe gibt an, wie viele Elemente in der Liste gespeichert werden können, bevor neuer Speicherplatz für die Instanz angefordert werden muss. Können Sie bereits bei der Definition der Variable absehen, wie viele Elemente Sie in der ArrayListe unterbringen müssen, sollten Sie deren Kapazität direkt vorgeben: ArrayList arrayListe = new ArrayList(10);

Wenn Sie einer vollen Liste ein weiteres Element hinzufügen, wird deren Kapazität automatisch verdoppelt. Das heißt, wenn Sie in eine Liste, die 1000 Elemente aufnehmen kann, das 1001te Element einfügen, wächst die Liste im Speicher auf 2000 Elemente an. Der Vollständigkeit halber sei aber schon jetzt erwähnt, dass es auch eine Möglichkeit gibt, den ungenutzten Platz einer ArrayList-Variablen wieder freizugeben. Die entsprechende Methode stellen wir Ihnen im weiteren Verlauf des Kapitels vor. Vorläufig brauchen Sie sich nur zu merken, dass man bei Objekten der ArrayList-Klasse zwischen der Anzahl der Elemente und der Kapazität der Liste unterscheidet. Der Zugriff auf die einzelnen Elemente einer ArrayListe erfolgt wie bei einem Array über einen Index. Und natürlich können Sie auch die foreach-Anweisung verwenden, um eine ArrayListe zu durchlaufen. Vorsicht: Verwechseln Sie nicht die Kapazität mit der tatsächlichen Anzahl der Elemente Auch wenn Sie bei der Instanziierung einer ArrayList-Variablen die Kapazität der Liste angeben, enthält die Liste zunächst keine Elemente! Der folgende Code löst daher die Ausnahme System.ArgumentOutOfRange aus: ArrayList arrayListe = new ArrayList(10); Console.WriteLine(arrayListe[1]);

110 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite111 31. Oktober 2006

7.5 Die Klasse ArrayList

Neue Elemente in eine ArrayListe aufnehmen Die einfachste Möglichkeit, um einer ArrayListe ein neues Element hinzuzufügen, ist die Add-Methode. Das neue Element wird dabei einfach an die bestehende Liste angefügt: ArrayList arrayListe = new ArrayList(); arrayListe.Add(10); arrayListe.Add("zehn");

Wenn Sie die Position des neuen Elements vorgeben möchten, müssen Sie die Methode Insert benutzen. Die Anweisung arrayListe.Insert(1, 11);

fügt der Liste das neue Element am Index 1 zu, also an der zweiten Position der Liste. Wenn Sie den Inhalt des Arrays anschließend mit einer Schleife ausgeben, würde das Ergebnis folglich so aussehen: 10, 11, "zehn"

Rückgabewert der Add-Methode Wenn Sie mit der Add-Methode ein neues Element in eine ArrayListe aufnehmen, liefert der Rückgabewert von Add den Index des neuen Elements. Diese Information ist allerdings nur von begrenztem Nutzen, da sich der Index eines Elements durch das Hinzufügen oder Entfernen von anderen Elementen jederzeit ändern kann.

Elemente aus einer ArrayListe entfernen Zum Entfernen von Elementen aus einem ArrayList-Objekt stellt die Klasse ArrayList analog zum Hinzufügen von Elementen zwei Methoden zur Verfügung: Remove und RemoveAt. Mit der ersten Methode können Sie das gewünschte Element über seinen Inhalt ansprechen. Um zum Beispiel das im letzten Beispiel nachträglich eingefügte Element wieder zu löschen, könnten Sie folgenden Methodenaufruf verwenden: arrayListe.Remove(11);

Diese Anweisung hat allerdings einen kleinen Haken: Wenn sich in der Liste mehrere Objekte mit diesem Wert befinden, wird nur das erste dieser Elemente gelöscht! Gegebenenfalls müssen Sie dann noch mit der Methode Contains prüfen, ob der betreffende Wert noch öfter in der Liste vorkommt. Wenn Sie die exakte Position des zu löschenden Elements in der Liste kennen, können Sie die Methode RemoveAt benutzen, der Sie den Index des betreffenden Elements übergeben: arrayListe.RemoveAt(1);

Durch das Entfernen von Elementen aus einer Liste reduziert sich zwar die Gesamtanzahl der Listenelemente, die aktuelle Kapazität der Liste verändert sich dadurch jedoch nicht. Falls für eine Liste die Diskrepanz aus tatsächlicher (=Kapazität) und benötigter Größe (=Anzahl der Elemente) zu groß wird, können Sie die Kapazität der Liste mit der Methode TrimToSize anpassen. Die Liste belegt dann nur noch genau den Speicherplatz, der für die in ihr enthaltenen Elemente benötigt wird.

111 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

II – Grundlagen von C#

Beachten Sie, dass das erste Element einen Integer-Wert erhält und das zweite Element eine Zeichenkette aufnimmt. Wir hatten ja eingangs schon erwähnt, dass ArrayListen im Gegensatz zu Arrays nicht der Beschränkung auf einen Datentyp unterliegen.

Datei: 07.doc, Seite112 31. Oktober 2006

Kapitel 7

Arrays

Das Beispielprogramm ListeFüllen Damit Sie ein Gefühl für die Größenänderungen eines ArrayList-Objekts entwickeln können, haben wir ein kleines Beispielprogramm entwickelt. Mit diesem Programm können Sie eine Liste Element für Element füllen und dabei die Veränderungen ihrer Kapazität beobachten: 1. Geben Sie den folgenden Programmcode in ein leeres Projekt ein oder öffnen Sie das Beispielpro-

jekt Kap07\Listefüllen aus dem Ordner, in den die Beispiele für dieses Buch installiert wurden. ArrayList arrayListe = new ArrayList(1); string eingabe;

// using System.Collections; nicht vergessen!

Console.WriteLine("Kapazität des Arrays: {0} Elemente", arrayListe.Capacity); Console.WriteLine("Anzahl der Elemente : {0}", arrayListe.Count); Console.WriteLine(); do { Console.Write("Geben Sie eine Zahl ein (beenden mit Eingabe): "); eingabe = Console.ReadLine();

// Eingabe einlesen

if (eingabe.Equals("")) break; // Eine leere Eingabe beendet die Schleife else { try arrayListe.Add(int.Parse(eingabe)); // Element in die Liste eintragen catch (FormatException) Console.WriteLine("Ungültige Eingabe wird ignoriert!\n"); Console.Write("Inhalt des Arrays foreach (int i in arrayListe) Console.Write(i + " "); Console.WriteLine();

: ");

// Aktuellen Inhalt der ArrayList anzeigen

Console.WriteLine("Kapazität des Arrays: {0} Elemente", arrayListe.Capacity); Console.WriteLine("Anzahl der Elemente : {0}", arrayListe.Count); Console.WriteLine(); } } while (true); // Größe des Arrays an seinen tatsächlichen Inhalt anpassen arrayListe.TrimToSize(); Console.WriteLine("TrimToSize durchgeführt. Neue Kapazität des Arrays: {0} Elemente\n", arrayListe.Capacity);

2. Starten Sie das Programm mit Strg+F5. 3. Füllen Sie die Liste, indem Sie der Reihe nach die gewünschten Zahlen eingeben und jeweils mit der

Eingabetaste bestätigen. Das Programm zeigt nach jeder Eingabe die neue Anzahl der Elemente und die aktuelle Kapazität der Liste an. 4. Wenn Sie die Eingabetaste betätigen, ohne zuvor eine Zahl eingegeben zu haben, wird das Pro-

gramm beendet. Zuvor wird noch die Methode dem Bildschirm ausgegeben.

TrimToSize

aufgerufen und die neue Kapazität auf

112 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite113 31. Oktober 2006

II – Grundlagen von C#

7.6 Übungen zu diesem Kapitel

Abbildung 7.4: Die Kapazität des Arrays wird dynamisch angepasst.

7.6 Übungen zu diesem Kapitel In diesem Abschnitt finden Sie einige Übungen zu diesem Kapitel. Die richtigen Antworten und Lösungen finden Sie wie immer auf der Website www.vsxpress.de.

Übung 7.1 Erweitern Sie das Programm Index von Seite 104 um einen try-catch-Block, der die IndexOutOfRangeAusnahme behandelt. Hinweis: Diese Konstruktion haben wir in Kapitel 5 vorgestellt.

Übung 7.2 Mit welcher Methode können Sie bei einem mehrdimensionalen Array die Anzahl der Elemente einer bestimmten Dimension ermitteln?

Übung 7.3 Erstellen Sie eine Instanz der ArrayList-Klasse. Fügen Sie der Liste ein Element mit dem Integerwert 10 und ein weiteres mit der Zeichenkette "zehn" hinzu. Geben Sie den Inhalt dann mit einer foreachAnweisung auf der Konsole aus.

113 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Datei: 07.doc, Seite114 31. Oktober 2006

Kapitel 7

Arrays

7.7 Zusammenfassung In diesem Kapitel haben Sie erfahren, was man in C# unter einem Array versteht und wichtige Techniken im Umgang mit Arrays kennengelernt: „

Unter einem Array versteht man die Zusammenfassung mehrerer Variablen des gleichen Typs, die unter einem gemeinsamen Namen angesprochen werden können.

„

Arrays werden in einem zusammenhängenden Speicherbereich abgelegt. Dadurch werden die Speicherzugriffe sehr effizient.

„

Arrays in C# sind nullbasiert, das heißt, das erste Element wird über den Index 0 angesprochen.

„

Der Zugriff mit einem ungültigen Index löst eine IndexOutOfRange-Ausnahme aus.

„

Um alle Elemente eines Arrays zu durchlaufen, eignet sich am besten die foreach-Anweisung. Sie können dabei allerdings nur lesend auf das Array zugreifen. Für schreibende Zugriffe verwenden Sie am besten eine for-Schleife.

„

Mit der Methode Array.Resize kann die Größe eines Arrays nachträglich geändert werden. Die aktuellen Daten des Arrays bleiben dabei erhalten. Falls das Array verkleinert wird, fallen die überschüssigen Elemente weg.

„

Mehrdimensionale Arrays werden durch zusätzliche Kommata in den eckigen Klammern erzeugt. Die Initialisierung und der Zugriff erfolgt analog zu eindimensionalen Arrays.

„

Die Klasse Array enthält viele nützliche Methoden zum Bearbeiten von Arrays, von denen wir Ihnen

die Methoden GetLength(), CopyTo() und Clone() vorgestellt haben. „

Im letzten Abschnitt haben Sie ArrayListen kennengelernt. ArrayListen werden nicht zusammenhängend im Speicher abgelegt, sondern als Listen verwaltet, und sind dadurch besonders flexibel.

114 Klaus Fahnenstich, Rainer G. Haselier: Richtig einsteigen: Programmieren lernen mit Visual C# 2005. Microsoft Press 2006 (ISBN 978-3-86645-201-5)

Suggest Documents