2.11 Datenfelder (Arrays) 

Datenfelder fassen gleichartige Daten unter einem gemeinsamen Variablennamen zusammen. In einer Variablendeklaration werden sie mit runden Klammern kenntlich gemacht. Sie haben folgende Syntax (statt Dim kann auch ein anderer Modifikator stehen, siehe Abschnitt 2.5.5, »Sichtbarkeit und Lebensdauer«, optionale Teile stehen in eckigen Klammern, kursive Teile müssen Sie Ihren Bedürfnissen anpassen):
<Modifikator> <Bezeichner>([,]) As <Datentyp> [=<Werte>] |
Um den nötigen zusammenhängenden Speicherplatz zu reservieren, wird die Feldgröße bei der Deklaration des Feldes angegeben. Die einzelnen Elemente werden über ihre Position im Feld angesprochen. Dies macht es einfach, Felder in Schleifen zu verarbeiten.
Hinweis |
Das erste Element eines Arrays hat den Index 0. Bei der Deklaration eines Arrays wird nicht die Anzahl der benötigten Elemente angegeben, sondern der Index des letzten Elements. |
Die Anzahl der Elemente eines jeden Arrays ergibt sich damit wie folgt:
Anzahl der Arrayelemente = letzter Index + 1
Die Anzahl der Positionsangaben zur eindeutigen Identifizierung eines Elements im Feld wird Dimensionalität oder Rang (engl. rank) genannt. So benötigen eindimensionale Felder nur einen Index, um ihre Elemente anzusprechen.
Im Gegensatz zu früheren Versionen von Visual Basic kann man nicht mehr zwischen statischen und dynamischen Arrays unterscheiden, weil die Größe eines Arrays grundsätzlich immer anforderungsgerecht angepasst werden kann.
Hinweis |
Alle Elemente eines Arrays haben den gleichen Datentyp. |
2.11.1 Eindimensionale Arrays 

Da eindimensionale Felder nur einen Index benötigen, muss auch nur ein Index bei der Deklaration angegeben werden. Er wird in runden Klammern dem Namen des Arrays angehängt. Das folgende Beispiel deklariert ein Feld namens teil mit einem maximalen Index von 4, das nur Elemente des Typs Integer enthält:
Dim teil(4) As Integer
Die 4 in der Deklaration gibt den maximalen Index an. Da der kleinste Index (des ersten Elements) 0 ist, besteht das Feld aus 5 Elementen:
teil(0), teil(1), teil(2), teil(3), teil(4)
Die einzelnen Elemente werden über ihren Index angesprochen. Das folgende Codefragment zeigt, wie Elemente in einer Zuweisung mit = belegt und in Write ausgelesen werden:
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Eindimensional()
Dim tag(7) As String
tag(0) = "Montag" : tag(1) = "Dienstag"
tag(2) = "Mittwoch" : tag(3) = "Donnerstag"
tag(4) = "Freitag"
tag(5) = "Samstag" : tag(6) = "Sonntag"
Console.WriteLine("Wochenbeginn ist {0}", tag(0))
Console.WriteLine("Wochenende ab {0}", tag(5))
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe des Programms zeigt, dass auf die richtigen Wochentage zugegriffen wird:
Wochenbeginn ist Montag
Wochenende ab Samstag
2.11.2 Mehrdimensionale Arrays 

Die Deklaration und Verwendung eines mehrdimensionalen Feldes erfolgt analog. Indizes verschiedener Dimensionen werden durch Kommata voneinander getrennt. Das folgende Codefragment simuliert eine kleine Firma mit 10 Räumen, in denen jeweils 3 Rechner stehen. Jedem der Rechner wird eine IP-Adresse zugewiesen. Die erste Dimension spezifiziert also den Raum, die zweite den Rechner in dem Raum.
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Mehrdimensional()
Dim IP(9, 2) As String
Dim base As String = "192.168.1."
Dim addr As Integer = 100
For raum As Integer = 0 To 9
For dose As Integer = 0 To 2
IP(raum, dose) = base & addr
addr += 1
Next
Next
Console.WriteLine("Nr 1 in Raum 1 hat IP {0}", IP(0,0))
Console.WriteLine("Nr 2 in Raum 7 hat IP {0}", IP(6,1))
Console.ReadLine()
End Sub
End Module
End Namespace
Die Prozedur erzeugt folgende Ausgabe:
Nr 1 in Raum 1 hat IP 192.168.1.100
Nr 2 in Raum 7 hat IP 192.168.1.119
Hinweis |
Eine For-Each-Schleife durchläuft alle Dimensionen. |
2.11.3 Initialisierung 

Eine Initialisierung erfolgt durch eine explizite Liste mit Werten. Dann ist die Feldgröße allein durch diese Liste bestimmt und darf nicht zusätzlich angegeben werden. Das folgende Codefragment zeigt ein Beispiel. Die doppelten geschweiften Klammern vermeiden eine Interpretation als Platzhalter und erzeugen in der Ausgabe einfache geschweifte Klammern.
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Initialisierung()
Dim teil() As Integer = {44, 99}
Console.WriteLine("Feld {{{0},{1}}}", teil(0), teil(1))
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt die korrekte Belegung des Feldes:
Feld {44,99}
Jedes nicht explizit initialisierte Element eines Arrays wird mit dem Standardwert des Datentyps belegt (siehe Abschnitt 2.5.6, »Initialisierung von Variablen«). Im Fall von Integer ist dies 0. Das folgende Codefragment belegt nur einen Teil der Arrayelemente:
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Vorbelegung()
Dim name() As String = {"Januar", "Februar", "März", _
"April", "Mai", "Juni", "Juli", "August", _
"September", "Oktober", "November", "Dezember"}
Dim verdienst(11) As Integer
verdienst(1) = 5700
verdienst(5) = 4300
verdienst(11) = 7900
For i As Integer = 0 To 11
Console.WriteLine("{0,9}: {1}",name(i),verdienst(i))
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe des Programms zeigt die Nullen der nicht zugewiesenen Elemente. So wie Sie nicht gern nur aus Vergesslichkeit auf Einkommen verzichten möchten, sollten Sie Feldelemente möglichst explizit initialisieren.
Januar: 0
Februar: 5700
März: 0
April: 0
Mai: 0
Juni: 4300
Juli: 0
August: 0
September: 0
Oktober: 0
November: 0
Dezember: 7900
Mehrdimensionale Felder werden analog initialisiert. Jeder Dimension entspricht eine Ebene an geschachtelten geschweiften Klammern. Die Anzahl der Elemente muss innerhalb einer Dimension konstant sein. Es ist zum Beispiel nicht möglich, eine Liste mit 3 Elementen und eine andere Liste auf der gleichen Ebene mit 4 Elementen zu haben. Die folgenden Deklarationen legen die Felder feld2(4,2) und feld3(2,4,3) an.
Dim feld2(,) As Integer = {{2,3}, {7,1}, {9,2}, {6,2}}
Dim feld3(,,) As Integer = { _
{{3,9,4}, {6,0,2}, {2,8,1}, {7,3,1}}, _
{{7,2,1}, {8,5,1}, {4,9,6}, {3,1,9}} _
}
Hinweis |
Objekte als Arrayelemente können mit New nur in Kombination mit einer Liste {...} explizit initialisiert werden. |
2.11.4 Arrayname und Kopien 

Der Name eines Feldes benennt dieses nur und stellt nicht die enthaltenen Werte dar. Es ist also ein Referenztyp. Im folgenden Codefragment wird ein solcher Name in eine andere Variable kopiert, und mit dieser wird das Originalfeld geändert. Die neue Variable ist nur ein neuer Name desselben Feldes.
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Arrayname()
Dim orig() As String = {"Jörn", "Navratil"}
Dim name() As String = orig
name(1) = "Schmidt"
Console.WriteLine("orig {{{0},{1}}}", orig(0), orig(1))
Console.WriteLine("name {{{0},{1}}}", name(0), name(1))
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe bestätigt, dass das Original geändert wurde:
orig {Jörn,Schmidt}
name {Jörn,Schmidt}
Was machen Sie nun, wenn Sie eine echte Kopie benötigen? Dafür stellt die Klasse Array eine Kopierfunktion bereit, wie das nächste Codefragment zeigt:
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Kopie()
Dim orig() As String = {"Jörn", "Navratil"}
Dim copy(1) As String
Array.Copy(orig, copy, 2)
copy(1) = "Schmidt"
Console.WriteLine("orig {{{0},{1}}}", orig(0), orig(1))
Console.WriteLine("copy {{{0},{1}}}", copy(0), copy(1))
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt, dass das Original unverändert geblieben ist:
orig {Jörn,Navratil}
copy {Jörn,Schmidt}
Hinweis |
Sind die Feldelemente Referenztypen, zum Beispiel Felder, wird das, worauf sie zeigen, nicht kopiert (sogenannte flache Kopie). Bei Zuweisungen werden erweiternde Referenzkonvertierungen der Elemente implizit benutzt. |
2.11.5 Speicherbelegung und Redimensionierung 

Bei der Deklaration kann auf die Angabe eines oder mehrerer Indizes verzichtet werden. Eine solche Angabe reserviert nur Speicher für den Namen des Feldes. Dieser Name ist eine Referenz auf das Feld, Felder sind also Referenztypen. Bevor das Feld das erste Mal verwendet wird, muss noch Platz geschaffen werden für seine Elemente. Das folgende Codefragment wird also einen Laufzeitfehler erzeugen:
Dim feld() As Integer
feld(0) = 26 'Laufzeitfehler!!
Speicher wird mit ReDim alloziert (die Verwendung von New wird im Rahmen der Objektorientierung besprochen). Damit lässt sich das letzte Fragment korrigieren.
Dim feld() As Integer
ReDim feld(12)
feld(0) = 26 'fehlerfrei
Soll ein Feld vergrößert werden, ohne bisherige Werte zu verlieren, wird ReDim durch das Schlüsselwort Preserve ergänzt. Das folgende Codefragment passt eine Feldgröße mehrfach an:
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Redimensionierung()
Dim f() As Integer
ReDim f(0) '1 neues Element
f(0) = 56
Console.WriteLine("{{{0}}}", f(0))
ReDim Preserve f(1) '1 neues und 1 altes Element
f(1) = 78
Console.WriteLine("{{{0},{1}}}", f(0), f(1))
ReDim f(2) '3 neue Elemente
f(2) = 81
Console.WriteLine("{{{0},{1},{2}}}", f(0), f(1), f(2))
Console.ReadLine()
End Sub
End Module
End Namespace
Die dritte Ausgabe zeigt, dass ohne Preserve bisherige Werte verloren gehen: Die ersten beiden Feldelemente haben eine 0 durch die implizite Feldinitialisierung statt der Werte 56 und 78.
{56}
{56,78}
{0,0,81}
Mehrdimensionale Felder werden analog geändert. Zum Beispiel reserviert die Anweisung
ReDim g(6,2)
Speicher für ein zweidimensionales Feld mit 7 Zeilen und 3 Spalten.
Hinweis |
Ein Compilerfehler wird erzeugt, wenn versucht wird, mt ReDim die Dimensionalität eines Feldes zu ändern. |
Hinweis |
Ein Laufzeitfehler wird erzeugt, wenn bei einem mehrdimensionalen Array mit Preserve nicht nur die letzte Dimension verändert wird. |
Anhänger anderer Programmiersprachen arbeiten gern direkt mit dem Speicher. Obwohl dies in Visual Basic nicht möglich ist, soll Ihnen nicht vorenthalten werden, dass Felder linear im Speicher abgelegt werden. Zuerst kommen alle Elemente, die alle Indizes bis auf den letzten gemeinsam haben. Der letzte Index wird sukzessive durchlaufen, und die Elemente werden im Speicher abgelegt. Dann wird der vorletzte Index um eins erhöht und das Spiel wiederholt, bis der erste Index den höchsten erlaubten Wert hat. Der Feldname selbst verweist auf die Stelle im Speicher, an der das erste Feldelement steht (Startadresse).
Hinweis |
Da ein Feld ein Referenztyp ist, wird bei dessen Weitergabe nur ein Zeiger auf das Feld kopiert und nicht dessen Inhalt. Dies ist sehr effizient. |
2.11.6 Jagged Arrays 

Soll ein Feld in einer Dimension verschieden lange Unterfelder enthalten, muss man es als Feld von Feldern und nicht als mehrdimensionales Feld deklarieren. Dazu wird mindestens ein extra Klammerpaar bei der Deklaration verwendet. Jedes Klammerpaar repräsentiert ein Feld beliebiger Dimensionalität, wobei das äußerste Feld ganz links steht. Das folgende Codefragment definiert eine simple Jahresübersicht. Das Feld jahr ist als Feld mit 12 Monaten deklariert, die jeweils ein Feld von unterschiedlich vielen Tagen sind.
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Jagged()
Dim name() As String = {"Montag", "Dienstag", _
"Mittwoch", "Donnerstag", "Freitag", _
"Samstag", "Sonntag"}
Dim jahr(11)(), monat() As String
Dim tage, no As Integer
For monatsnummer As Integer = 0 To 11
Select Case monatsnummer + 1
Case 2 : tage = 27
Case 4, 6, 9, 11 : tage = 29
Case Else : tage = 30
End Select
ReDim monat(tage)
jahr(monatsnummer) = monat
For tag As Integer = 0 To tage
jahr(monatsnummer)(tag) = name(no Mod 7)
no += 1
Next
Next
Console.WriteLine("7. Mai ist ein {0}", jahr(4)(6))
Console.WriteLine("3. Oktober ist ein {0}",jahr(9)(2))
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt die korrekten Tage für 2007:
7. Mai ist ein Montag
3. Oktober ist ein Mittwoch
2.11.7 Feldgröße & Co. 

Durch die Möglichkeit der Redimensionierung weiß man nicht immer im Voraus, wie groß ein Feld ist. Daher haben Felder die Möglichkeit, sie mit GetUpperBound nach der Größe zu fragen. Das nächste Codefragment zeigt einen solchen Fall. Die Felddimensionen werden zufällig bestimmt. Die erste Ausgabe nutzt eine sprachunabhängige Methode der Klasse Array, während die zweite nur in Visual Basic zur Verfügung steht. Die Zählung der Dimension beginnt im ersten Fall bei 0 und im zweiten bei 1.
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Feldgroesse()
Randomize() 'Initialisierung Zufallszahlengenerator
Dim arbeitsstunden(,) As Integer
ReDim arbeitsstunden(2 + CType(Rnd() * 10, Integer), _
2 + CType(Rnd() * 8, Integer))
Console.WriteLine("{0} Tage a {1} Stunden", _
arbeitsstunden.GetUpperBound(0), _
arbeitsstunden.GetUpperBound(1))
Console.WriteLine("{0} Tage a {1} Stunden", _
UBound(arbeitsstunden,1), UBound(arbeitsstunden,2))
Console.ReadLine()
End Sub
End Module
End Namespace
Alle Felder haben Zugriff auf die Methoden von System.Array, die neben der hier gezeigten Feldgröße weitere Informationen zum Feld liefern. In eckigen Klammern steht jeweils, woher die gelisteten Symbole stammen.
[Int32()]
Get, Set, Address
[Array]
AsReadOnly, Resize, BinarySearch, ConvertAll, Exists, Find, FindAll, FindIndex,
FindLast, FindLastIndex, ForEach, IndexOf, LastIndexOf, Sort, TrueForAll, Clear,
GetLength, GetUpperBound, GetLowerBound, Initialize, CreateInstance, Copy,
ConstrainedCopy, GetValue, SetValue, GetLongLength, Clone, CopyTo, GetEnumerator, Reverse
[Object]
GetType, GetHashCode, ToString, Equals, ReferenceEquals
[Queryable]
AsQueryable
[Enumerable]
First, FirstOrDefault, Last, LastOrDefault, Single, SingleOrDefault, ElementAt,
ElementAtOrDefault, Any, All, Count, LongCount, Contains, Aggregate, Sum, Min,
Max, Average, Where, Select, SelectMany, Take, TakeWhile, Skip, SkipWhile, Join,
GroupJoin, OrderBy, OrderByDescending, GroupBy, Concat, Distinct, Union,
Intersect, Except, SequenceEqual, AsEnumerable, ToArray, ToList, ToDictionary,
ToLookup, DefaultIfEmpty, OfType, Cast
[Extensions]
Ancestors, Nodes, DescendantNodes, Descendants, Elements, InDocumentOrder,
Remove, Attributes, AncestorsAndSelf, DescendantNodesAndSelf, DescendantsAndSelf
[DataTableExtensions]
CopyToDataTable
[Properties]
[Array]
Length, LongLength, Rank, SyncRoot, IsReadOnly, IsFixedSize, IsSynchronized
Als Beispiel wird im nächsten Codefragment der Mittelwert aus 100 Zufallszahlen berechnet, der nahe 0.5 liegt:
' ...\Sprachsyntax\Felder\Felder.vb |
Option Strict On
Namespace Sprachsyntax
Module Felder
...
Sub Mittelwert()
Randomize() 'Initialisierung Zufallszahlengenerator
Dim zahlen(100) As Integer
For no As Integer = 0 To zahlen.Length – 1
zahlen(no) = CType(Rnd() * 100, Integer)
Next
Console.WriteLine("Mittelwert: {0}", zahlen.Average())
Console.ReadLine()
End Sub
End Module
End Namespace
2.11.8 Zusammenfassung 

- Datenfelder (Arrays) fassen eine Menge typgleicher Werte unter einem Namen zusammen. Die Werte werden durch einen oder mehrere Indizes identifiziert. Die Common Language Runtime betrachtet ein Array als Referenztyp, es ist somit ein Objekt.
- Der Index des ersten Elements eines Arrays ist immer 0, der des letzten Elements entspricht der Angabe in der Deklaration.
- Der einfache Arrayname ohne die Angabe eines Index repräsentiert einen Zeiger auf die Startadresse des Speicherbereichs, den das Feld für sich beansprucht.
- Die Anweisung ReDim ändert die Kapazität eines Arrays. Dabei gehen alte Feldinhalte verloren. Zur Beibehaltung alter Feldinhalte muss die Redimensionierung mit ReDim Preserve erfolgen.
- Mehrdimensionale Arrays können unter Bewahrung ihres Inhalts nur in der letzten Dimension redimensioniert werden.
- Eine Redimensionierung zwecks Erhöhung der Anzahl der Dimensionen ist nicht möglich.
- Arrays können wie Variablen bei der Deklaration initialisiert werden. Dazu werden die Startwerte in geschweiften Klammern geschrieben. Die Dimensionsgröße darf dabei nicht angegeben werden, sie erfolgt implizit.
- Zur Bestimmung der Obergrenze eines Feldes liefert die Methode GetUpperBound als Ergebnis des Aufrufs den Index des letzten Feldelements.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.