Arrays
Praktikum als Weihnachtsmann
Wer Arrays beherrscht, kann virtueller Weihnachtsmann werden. Du bist verwirrt? Brauchst du nicht, die Sache ist ganz logisch: Denn was braucht jemand, der als Weihnachtsmann anheuern möchte? Einen roten Mantel an erster Stelle, einen Bart, klar, und einen Schlitten. Aber ohne einen großen Beutel wäre der Weihnachtsmann verloren! Wo sollen denn sonst all die Geschenke aufbewahrt werden?
Und genauso ist man auch in der Welt des Programmierens ohne einen Beutel so ziemlich aufgeschmissen. Ebenso wie der Weihnachtsmann mit Unmengen an Geschenken hantieren muss, kann es vorkommen, dass auch du als Programmierer massenhaft Variablen benötigst. Stelle dir nur ein Programm zur Wetterbeobachtung vor, bei dem du die Temperaturen des letzten Monats einspeichern möchtest. Mit deinem bisherigen Wissen müsstest du ganze dreißig Variablen für jede gemessene Tagestemperatur deklarieren. Unpraktisch und mühselig! Besser wäre es doch, einen großen Beutel zu definieren, in dem man alle seine Variablen hinein schmeißen kann. Wenn man dann eine bestimmte Variable benötigt, greift man einfach in den Beutel und arbeitet anschließend mit der gewünschten Variablen weiter.
Beutel gibt es in der Programmiersprache C++ tatsächlich, nur heißen sie hier „Arrays“, zu deutsch: „Felder“. Ein Array ist eine Zusammenfassung mehrerer Objekte eines bestimmten Datentyps. Will heißen: Einen Kessel Buntes kannst du mit Arrays nicht programmieren. Arrays beinhalten stets Variablen desselben Datentyps, wie Integer oder Float.
Schauen wir uns nun an, wie du ein Array konkret deklarieren kannst. Da stehen dir drei Möglichkeiten offen:
int feld[10];
int feld[]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int feld[10]={1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
Alle drei Varianten haben gemeinsam, dass du zuerst den Datentyp nennst, den die Elemente des Arrays besitzen sollen, in diesem Fall „int“. Auffällig sind dann die eckigen Klammern. Mit ihnen kannst du angeben, wie viele Elemente dein Array besitzen soll. Die Betonung liegt auf „kannst“, denn tatsächlich musst du das nur dann machen, wenn du dem Array nicht sofort Elemente zuweist. Sprich, wie in der ersten Programmzeile geschehen. In diesem Fall musst du immer eine Arraygröße angeben. Weißt du allerdings schon, welche Elemente das Array besitzt, kannst du sie in geschweiften Klammern (vergleiche die zweite Programmzeile) und mit Kommas getrennt angeben. Der Compiler berechnet die Arraygröße dann automatisch – er kann schließlich zählen, die gute Rechenmaschine. Eine Kombination beider Varianten ist auch möglich, wie in Zeile drei geschehen und bietet sich besonders dann an, wenn du das Array nicht gleich vollständig mit Werten besetzen kannst. Du definierst beispielsweise ein Array der Größe 10, kennst aber nur die ersten drei Elemente. Hättest du die Arraygröße in den eckigen Klammern weggelassen und nur die dir bekannten drei Werte hingeschrieben, würde der Compiler nämlich annehmen, dein Array besitzt die Größe 3.
Die Elemente eines Arrays sind im Speicher hintereinander belegt. Kannst du dem Array nicht sofort Elemente zuweisen, reserviert der Compiler Speicherplatz für die Gesamtanzahl der Elemente, die du ja in diesem Fall angeben musstest. Diese Grafik stellt diesen Sachverhalt nochmal anschaulich dar:
Die Integer-Werte 0, 30 und 12 sind hier in ihrer Binärform zusammenhängend gespeichert
Oft kannst du das Array, deinen Beutel, nicht gleich bei der Deklaration mit Werten füllen. Welche Varianten stehen dir aber dann zur Verfügung, um Objekte in das Array zu stecken?
Die primitivste Möglichkeit ist, dem Compiler zu sagen: Jene Stelle bitte mit diesem Wert besetzen. Jene Stelle mit diesem. Schauen wir uns das mal näher an:
int qudratzahlen[5];
quadratzahlen[0]=1;
quadratzahlen[1]=4;
quadratzahlen[2]=9;
quadratzahlen[3]=16;
quadratzahlen[4]=25;
Bei dieser Variante rücken die eckigen Klammern nochmal in den Vordergrund. Bei der Zuweisung von Arrayelementen fungieren sie als so genannter Indexoperator. In den eckigen Klammern steht jeweils die Position im Array, die du mit einem Wert besetzen möchtest. Aber Vorsicht! Wie du in dem Programmbeispiel siehst, beginnt der Compiler das Zählen bei 0! Wenn du also die erste Position besetzen willst, muss in den eckigen Klammern eine 0 stehen, bei der fünften Position eine 4. Oder allgemein gesprochen: Bei einem Array der Größe n erfolgt die Wertzuweisung mit einem Index von 0 bis n-1. Das solltest du dir unbedingt merken, um später grobe Fehler zu vermeiden.
Wenn dennoch die unerlaubte Zuweisung „quadratzahl[5]=36“ erfolgt, würde fremder Speicherplatz in Anspruch genommen werden. Das Array hat jedoch nur Speicherplatz für fünf Integer reserviert. Auf der danach folgenden Speicheradresse könnte bereits eine andere Variable gespeichert sein – deshalb würde bei der Ausführung des programms die Fehlermedung "index-out-of-memory" ausgegeben werden.
Das Zuweisen der Array-Elemente kannst du jedoch auch dem Anwender überlassen:
cin >> quadratzahl[0];
cin >> quadratzahl[1];
Der Benutzer des Programms wird dann aufgefordert, Werte einzugeben, die in dem Array an den angegebenen Positionen gespeichert werden.
Eine viel elegantere Lösung ist es jedoch, Arrays mit Schleifen zu kombinieren. Damit lässt sich nämlich auf der einen Seite die Eingabe von Arraywerten leicht programmieren:
int feld[10];
for(int i=0;i<10;i++) {
cout << "Bitte einen Wert eingeben: "
cin >> feld[i];
}
Auf der anderen Seite gelingt dir somit aber auch, die Ausgabe von Arraywerten zu realisieren:
for(int i=0;i<10;i++) {
cout << "Element“ << i+1 << ":“ << feld[i] << endl;
}
Damit dir bei der Indexierung keine Fehler unterlaufen, ist es sinnvoll, den Schleifenoperator i stets von 0 bis n-1 laufen zu lassen, wobei n für die Arraygröße steht.
Vielleicht hast du dir schon die Frage gestellt, ob man ein Array nicht auch an eine Funktion übergeben kann. Und tatsächlich: Wenn ein Array als Parameter in einer Funktion gefordert ist, hat der Compiler zunächst nichts zu meckern. Innerhalb der Funktion kannst du mit dem Indexoperator wie gewohnt auf Arrayelemente zugreifen und diese manipulieren. Das Tolle ist: Der Aufruf erfolgt mittels „call-by-reference“, das heißt, alle Änderungen an den Arrayelementen bleiben erhalten. Bei der Übergabe von Arrays an eine Funktion zeigt sich übrigens auch die wahre Natur von Arrays: Denn tatsächlich sind Arrays keine Beutel, sondern reine Computer-Mathematik. Wird ein Array an eine Funktion übergeben, erhält die Funktion in Wirklichkeit die Adresse des ersten Elements, also die etwas kryptisch anmutenden Binär-Zeichenfolgen wie "0010101001011010(2)“. Das ist eine Zahl im Binärsystem, diese kann man in eine etwas lesbarere Schreibweise ins Hexadezimalsystem umrechnen, dann erhält man 2A5A(16). Wenn man nun also die Startadresse und die Größe des Datentyps (wie Integer oder Float) kennt, kann man die Adressen der folgenden Elemente im Nu berechnen, wie hier beispielhaft geschehen:
Beispiel: messwerte[3]
Anfangsadresse: 0010101001011010(2)
Datentyp: int
Anzahl Bytes: 4 Byte für die Speicherung eines int-Wertes,
der Wert 4(10) aus dem Dezimalsystem ist im Binärsystem 100(2)
Indexposition: 0, im Binärsystem 0(2)
Berechnung der Adresse: Startadresse + Indexposition * Anzahl Bytes pro Element =
0010101001011010(2) + 0(2) * 100(2) = 0010101001011010(2)
(das Element mit der Indexpositon 0 finden wird also genau an der Startadresse des Arrays)
Indexposition: 2, im Binärsystem 10(2)
Berechnung der Adresse: Startadresse + Indexposition * Anzahl Bytes pro Element =
0010101001011010(2) + 10(2)* 100(2) = 0010 1010 0110 0010(2)
(das Element mit der Indexpositon 2 finden wird bei int-Arrays 8 Byte nach der Startadresse des Arrays)
Auf diese Weise arbeiten auch Funktionen mit übergebenen Arrays.
Das aber nur am Rande. Für deine künftige Tätigkeit als virtueller Weihnachtsmann reicht es zunächst, wenn du Arrays Werte zuweisen und diese ausgeben kannst. Beherrscht du diese Fertigkeiten, steht einer schönen C++-Bescherung nichts im Wege.
Und auch viele andere Beispielprogramme wie die Speicherung und Auswertung von Messdaten lassen sich mit Hilfe von den gerade kennengelernten Arrays programmieren.
Aufgaben: Arrays
A1: Quiz dich schlau!
Nachfolgend sind einige Fragen aufgeführt, die du nach diesem Abschnitt beantworten können solltest:
(1) Was ist ein Array in der Programmierung?
(2) Wie wird ein eindimensionales Array definiert? Erstelle bitte ein Beispielfeld zum Speichern von 20 Integerwerten.
(3) Weise bitte diesem Feld die Werte 10, 20, 30 .. 200 zu, verwende dazu eine Schleife.
(4) Welche Indexpositionen hast du dabei verwendet?
A2: Schnelle Rallye
Der Hockenheimring ist bekannt für seine schnellen Motoren und glühenden Reifen. Infolge der Automatisierung ist ein neues Zeiterfassungssystem entwickelt worden, für das noch ein Auswertungsprogramm geschrieben werden muss. Es soll die Runden mit 17 Kurven und 4.574 m die Rundenzeiten erfassen und speichern und anschließend die Minimal- und Maximalgeschwindigkeit sowie die Durchschnittsgeschwindigkeit berechnen. Gemessen werden sollen die Zeiten von 5 Runden. Die Ausgabe soll wie folgt aussehen:
Runde 1:
Geschwindigkeit in s: 71.4
Runde 2:
Geschwindigkeit in s: 68.4
..
Runde 5:
Geschwindigkeit in s: 76.2
Auswertung:
Minimalzeit (Rundenrekord): 68.4 s
Maximalzeit: 76.2 s
Durchschnittszeit: 72.1 s
Realisiere diese Ausgabe mithilfe von Arrays.
A3: Sieb des Eratostenes
Das Sieb des Eratostenes (240 v.Chr.) ist eine einfache Idee zur Ermittlung von Primzahlen:
Eine Liste aller Zahlen (bis n) wird angelegt. Alle Zahlen, die das Produkt der Multiplikation zweier Zahlen zwischen 1 und n sind, werden aus der Liste gestrichen.
Beispiel:
Ausgangszustand: [0 1 2 3 4 5 6 7 8 9 10 11 12 13]
Nach dem Löschen der Zahlen, die das Produkt zweier Zahlen sind,
verbleiben die Primzahlen: [0 0 2 3 0 5 0 7 0 0 0 11 0 13]
Schreibe bitte ein C++-Programm zur Ausgabe aller Primzahlen, die kleiner als 10000 sind. Verwende dafür bitte ein n-elementiges Array, durch dein Programm sollen alle "Nichtprimzahlen" in dem Array auf 0 gesetzt werden, die übrig bleibenden Primzahlen sollen anschließend ausgegeben werden.
Musterlösungen
L1: Quiz dich schlau!
(1) Ein Array ist die Zusammenfassung einer Anzahl von gleichartigen Objekten eines Datentyps, wie z. B. int‐ oder double‐Werten.
(2) Datentyp Arrayname[Größe] Bsp: int oneD[20]
(3) for (int i = 0; i < 20; i++) {
oneD[i] = 10*(i+1);
}
(4) Indexwerte von 0 bis n-1, in dem Beispiel müssen also 0..19 verwendet werden.
L2: Schnelle Rallye
#include <iostream>
using namespace std;
int main() {
const int anzRunden = 5; // Array-Größe muss damit nur an einer Stelle geändert werden
double zeiten[anzRunden];
int i;
double min, max, durchschnitt;
for (i = 1; i <= anzRunden; i++) {
cout << "Runde " << i << endl;
cout << "Geschwindigkeit in s: ";
cin >> zeiten[i - 1]; // Speicherung des 1. Element mit Index 0, usw.
}
min = zeiten[0]; // Initialisierung von min, max, summe
max = zeiten[0];
double summe = zeiten[0];
for (i = 1; i < anzRunden; i++) {
if (zeiten[i] < min) {
min = zeiten[i];
}
if (zeiten[i] > max) {
max = zeiten[i];
}
summe= summe + zeiten[i];
}
cout << endl << "Auswertung: " << endl;
cout << "Minimalzeit(Rundenrekord): " << min << " s" << endl;
cout << "Maximalzeit: " << max << " s" << endl;
cout << "Durchschnittszeit: " << summe/anzRunden << " s" << endl;
return(0);
}
L3: Sieb des Eratostenes
#include <iostream>
using namespace std;
int main() {
const int n = 10000; // Konstante für die Feldgröße
int primzahlen[n]; // Array zur Speicherung der Zahlen
for (int i = 0; i < n; i++) { // Initialisierung des primzahlen-Feldes
primzahlen[i] = i;
}
// Löschen aller Produkte aus 2 Zahlen aus dem Feld
for (int a = 2; a < n; a++){
for (int b = 2; b < n; b++){
if (a*b < n){ // Test, ob das berechnete Produkt innerhalb des Feldes liegt
primzahlen[a*b] = 0; // Löschen des Ergebnisses (Produktes) im Primzahlen-Feld
}
}
}
// Ausgabe aller verbleibenden Primzahlen (alle Zaheln, die nicht das Produkt aus zwei anderen Zahlen waren
for (int i = 2; i < n; i++) {
if (primzahlen[i] != 0) {
cout << primzahlen[i] << " ";
}
}
return 0;
}
/* Hinweis: In diesem Programm gibt es noch viele Optimierungsmöglichkeiten. Wenn du eine gefunden hast, schreib uns gern eine Mail. */
Fragen, Anregungen?
Ist etwas unverständlich oder du hast Fragen zu einem Thema, Aufgabe oder einfach zur C++-Welt?
Dann schreibe uns einfach eine Mail!