Array Einführung

 

Beim Programmieren ist eine gewisse Effektivität erstrebenswert. Wenn möglich sollte der Code eine gewisse Kompaktheit haben, sonst artet er in viele Codezeilen aus. Stell dir vor, du hast die Aufgabe, sieben Töne nacheinander abzuspielen.

Mit unserem jetzigen Vorrat an Programmierkenntnissen könnte der Sketch wie folgt aussehen:

int piezoPin = 8;

int tone0 = 525;
int tone1 = 664;
int tone2 = 598; 
int tone3 = 701;
int tone4 = 661;
int tone5 = 481;
int tone6 = 695;


void setup() 
{
  Serial.begin(9600);

  tone(piezoPin, tone0, 1000);
  delay(500);
  tone(piezoPin, tone1, 1000);
  delay(500);
  tone(piezoPin, tone2, 1000);
  delay(500);
  tone(piezoPin, tone3, 1000);
  delay(500);
  tone(piezoPin, tone4, 1000);
  delay(500);
  tone(piezoPin, tone5, 1000);
  delay(500);
  tone(piezoPin, tone6, 1000);
  delay(500);
}

void loop() 
{
 //leer
}

Diese Lösung ist speicherintensiv und wirkt auch sehr klobig. Viel eleganter können wir dieses Problem mit einem Array lösen. Das Array wird uns an anderen Stellen noch sehr wertvolle Dienste leisten.

Was ist ein Array?

Stell dir ein Array als eine Liste von Variablen gleichen Typs vor, die alle die gleichen Namen haben. Es ist möglich in ein Array sehr viele Variablen abzulegen und relativ einfach darauf zuzugreifen. Jede im Array platzierte Variable wird als Element bezeichnet. Die Anzahl der Elemente wird als Array-Größe bezeichnet.

###Syntaxbild

Folgende Codezeile erzeugt ein Array aus sieben Integer-Elementen und initialisiert jedes der Elemente:

Diese Lösung ist speicherintensiv und wirkt auch sehr klobig. Viel eleganter können wir dieses Problem mit einem Array lösen. Das Array wird uns an anderen Stellen noch sehr wertvolle Dienste leisten. Was ist ein Array? Stell dir ein Array als eine Liste von Variablen gleichen Typs vor, die alle die gleichen Namen haben. Es ist möglich in ein Array sehr viele Variablen abzulegen und relativ einfach darauf zuzugreifen. Jede im Array platzierte Variable wird als Element bezeichnet. Die Anzahl der Elemente wird als Array-Größe bezeichnet.

 ###Syntaxbild

Folgende Codezeile erzeugt ein Array aus sieben Integer-Elementen und initialisiert jedes der Elemente:

Ein Array beginnt mit dem Variablentyp (int), gefolgt vom Arraynamen (sequenz) und zwei rechteckigen Klammern. Dieser wird gleichgesetzt mit dem Inhalt: innerhalb zwei geschweifter Klammern sind die Array-Elemente {525, 664, 598, 701, 661, 781, 695} platziert, die durch Kommas voneinander getrennt werden. Sie alle heißen note, werden aber durch ihre Position im Array unterschieden. Arrays sind Null indiziert, d.h. sie beginnen nicht bei 1, sondern bei 0. Der erste Wert 525 hat zum Beispiel den Index 0. Der zweite Wert 664 den Index 1.  

####bild mit index

Wie wir aus einem Array eine bestimmte Variable herausziehen, sehen wir im folgenden Sketch. Der Serial.prinln()-Befehl zieht aus dem Array das angeforderte Element sequenz[4] = 661 und sendet es an den seriellen Monitor.

int piezoPin = 8;
int sequenz[] = {525, 664, 598, 701, 661, 781, 695};

void setup() 
{
  Serial.begin(9600);
}

void loop() 
{
  Serial.println(sequenz[4]);
}

Ein Array erkennen wir immer an den rechteckigen Klammern.

intsequenz[]={525,664,598,701,661,781,695};

Um ein bestimmtes Element aus dem Array zu wählen, wird die Index-Nummer innerhalb der eckigen Klammern platziert:

sequenz[0] = 525
sequenz[1] = 664
sequenz[2] = 598 
sequenz[3] = 701 
sequenz[4] = 661 
sequenz[5] = 781 
sequenz[6] = 695 

Der serielle Monitor zieht sich das fünfte Element (index 4) aus dem Array und gibt die zahl 661 aus.

Serial.println(sequenz[4]);

Die Eleganz von Code

Das Array ist ein sehr starkes Programmierkonstrukt. Aber sein ganzes Potenzial entfaltet es erst in Kombination mit einer for-Schleife. Die Schleife erleichtert das Aufrufen der einzelnen Array-Elemente. Schreiben wir den ersten Sketch so um, dass wir ein Minimum an Zeilen und eine echte kompakte Form erreichen.

int piezoPin = 8;
int sequenz[] = {525, 664, 598, 701, 661, 781, 695};


void setup() 
{
  for(int index=0; index<=8; index++)
  {
    tone(piezoPin, sequenz[index], 1000);
    delay(500);
  }
}

void loop() 
{
  //leer
}

Verglichen mit dem ersten Sketch demonstriert das array mit der for()-Schleife, dass auch ein Begriff wie elegant oder stilvoll auch in der Programmierung verwendet werden kann. Es erfüllt genau den gleichen Zweck, ist aber viel übersichtlicher.

Lass uns den Sketch genauer betrachten. Herzstück des Sketches ist die for-Schleife. Die for-Schleife zählt von 0 bis 7 - genauso oft wie es Array-Elemente gibt. Die Tondauer ist mit dem Wert 1000 hartgecoded und ändert sich nicht. Das Array und die for()-Schleife bestimmen den Wert der Frequenz. Die for()-Schleife hilft dabei, die Werte für die Frequenz aus dem Array zu holen: Bei jedem Schleifendurchgang wird das Ergebnis von index aus dem Schleifenkopf in die eckigen Klammern von sequenz[index] eingesetzt. Dadurch werden alle Elemente aus dem Array int sequenz[] nacheinander geholt und mit einem Abstand von 500ms (delay) abgespielt.

for(int index=0; index<8; index++)
  {
    tone(piezoPin, sequenz[index], 1000);
    delay(500);
  }

Hier die einzelnen for()-Schleifen Durchgänge und ihre Werte:

1. Schleifendurchgang > sequenz[0] (Element 1 im Array) > Ergebnis: 525 für Frequenz
2. Schleifendurchgang > sequenz[1] (Element 2 im Array) > Ergebnis: 664 für Frequenz
3. Schleifendurchgang > sequenz[2] (Element 3 im Array) > Ergebnis: 598 für Frequenz
4. Schleifendurchgang > sequenz[3] (Element 4 im Array) > Ergebnis: 701 für Frequenz
5. Schleifendurchgang > sequenz[4] (Element 5 im Array) > Ergebnis: 661 für Frequenz
6. Schleifendurchgang > sequenz[5] (Element 6 im Array) > Ergebnis: 781 für Frequenz
7. Schleifendurchgang > sequenz[6] (Element 7 im Array) > Ergebnis: 695 für Frequenz

Werte außerhalb der Array-Größe

Die for-Schleife durchläuft index 0 bis 7. An dieser Stelle treten Fehler auf, wenn die Schleifendurchgänge außerhalb der Array-Größe liegen. Wenn z.B. die Schleife bis 9 anstatt 7 zählt, obwohl nur 7 Elemente vorhanden sind. Der Compiler wird in solchen Fällen keinen Fehler melden, wird aber das Ergebnis beeinflussen, wie du im folgenden Beispiel hören und sehen kannst:

int piezoPin = 8;
int sequenz[] = {525, 664, 598, 701, 661, 781, 695};

void setup() 
{
  Serial.begin(9600);
  
  for(int i=0; i<10; i++)
  {
    tone(piezoPin, sequenz[i], 1000);
    delay(500);
    Serial.println(sequenz[i]);
  }
}

void loop() 
{
  //leer
}

Die Schleife zählt diesmal von 0 bis 9 – also über die Array-Größe von 7 Elementen hinaus. Es werden am Schluss drei zusätzliche Töne abgespielt.

for(int i=0; i<10; i++)
{
...
}

Der Serial.println() zeigt, dass weitere drei Werte hinzugefügt wurden, die nicht im Array vorhanden sind. Wenn dieser Fehler unbekannt bleibt, führt dies definitiv zu Fehlberechnungen.

Serial.println(sequenz[i]);

Entweder man passt genau auf und fügt die richtige Array-Größe in die for-Schleife, oder bedient sich einem Trick und macht sich keine Gedanken mehr darüber, wie groß das Array ist.  Mithilfe der sizeof()-Funktion können wir die Anzahl von Array-Elementen ausrechnen. Ein direktes Auslesen der Elementen-Anzahl funktioniert leider nicht. Wir müssen eine kleine Berechnung anstellen.

Die sizeof()-Funktion liest die Speichergröße aus, die die Elemente belegen – nicht die Anzahl. Der Rückgabewert von sizeof() erfolgt in Byte. Folgender Code liest die Größe des Arrays im seriellen Monitor als Byte aus. Der serielle Monitor gibt die Zahl 16 aus.

int sequenz[] = {523, 659, 587, 698, 659, 784, 698, 880}; 
int elements = sizeof(sequenz); // sizeof(sequenz[0]);

void setup()
{  
  Serial.begin(9600);
  Serial.println(elements);
}

void loop(){/* leer */} 

Unser Array enthält 8 Elemente.

int sequenz[] = {523, 659, 587, 698, 659, 784, 698, 880};

Mit dem sizeof()-Befehl ziehen wir die Speichergröße in Byte heraus. Das Ergebnis ist also 2 x 8 = 16 Bytes. Dem nach belegt das Array 16Bytes im Speicher. Das ist korrekt, wenn wir bedenken, dass ein Integer 2 Bytes an Speicher belegt.

Und jetzt kommt der letzte Schritt: Wenn wir nun die 16Bytes (Größe aller Array-Elemente) durch die Speichergröße eines einzelnen Elementes 2Byte teilen, erhalten wir die Elementen-Anzahl von 8.

int elements = sizeof(sequenz); / sizeof(int);

Hier der vollständige Sketch:

const int piezoPin = 8;// Piezo-Element an Pin 13 

int sequenz[] = {523, 659, 587, 698, 659, 784, 698, 880}; 
int arrayElements = sizeof(sequenz) / sizeof(int);

void setup()
{  
  Serial.begin(9600);
  
  for(int i=0; i<=arrayElements; i++)
  {
    tone(piezoPin, sequenz[i], 1000);
    delay(500);
    Serial.println(sequenz[i]);
  }
}

void loop(){/* leer */}

####text zusammenfassung

Arrays sind mächtige und sehr nützliche Programmstrukturen, besonders wenn sie mit for()-Schleifen kombiniert werden. Sie machen den Code übersichtlicher