Programmierung 1 Studiengang MI / WI
Dipl.-Inf., Dipl.-Ing. (FH) Michael Wilhelm
Hochschule Harz
FB Automatisierung und Informatik
mwilhelm@hs-harz.de
http://mwilhelm.hs-harz.de
Raum 2.202
Tel. 03943 / 659 338
Inhalt der Vorlesung
Überblick:
•
Erste Beispiele, Interaktion
•
elementare Datentypen
•
Variablen und Kontrollstrukturen
•
Arrays und Funktionen
•
Objekte
•
Methoden
•
Algorithmen und Pseudocode
•
Laufzeitverhalten
•
Simulation
•
Bibliotheken
• Folien basierend auf Daniel Schiffman “Learning Processing” und Donald W. Smith
• Folien basierend auf Vorlesung „Programmierung1“ von Prof. Singer
Grundlegende Algorithmen und Methoden:
•
Suchen und Sortieren
•
Hashing
•
Rekursion
•
Graphen
•
Dynamische
Programmierung
Von Processing zu Java
Kapitel
Arrays
•
Wozu Arrays?
•
Was ist ein Array?
•
Deklaration und Erzeugung
•
Initialisierung
•
Operationen auf und mit Arrays
•
Mehrdimensionale Arrays
Funktionen
•
Rückgabewert
Wofür kann man Arrays benutzen?
•
Wie geht man mit mehreren Rechtecken, Bällen, Figuren usw. um?
•
int ball1X, ball1Y, ball2X, ball2Y, ....?
•
Könnte man die Daten nicht in einer Tabelle halten?
•
Etwa die ballX-Tabelle:
1 2 3 4 5 6 7 8 9 10 11
•
Jede Spalte hat eine Nummer,
•
Für den 3. Ball wird Spalte 3 in der ballX-Tabelle angesprochen.
Beachte:
•
Alle Daten in einer Zeile müssen vom selben Datentyp sein!
Wofür kann man Arrays benutzen?
•
Wie geht man mit mehreren Rechtecken, Bällen, Figuren usw. um?
•
int ball1X, ball1Y, ball2X, ball2Y, ....?
•
Könnte man die Daten nicht in einer Tabelle halten?
•
Etwa die ballX-Tabelle:
0 1 2 3 4 5 6 7 8 9 10
•
Jede Spalte hat eine Nummer,
•
Für den 3. Ball wird Spalte 3 in der ballX-Tabelle angesprochen.
Beachte:
Was ist ein Arrays?
•
Eine Variable ist eine benannte Speicherstelle.
•
Ein Array ist eine benannte Menge von Speicherstelle.
(Eine Liste von Variablen)
•
Gemeinsamer Name
•
Ein Datentyp
•
Feste Größe
•
Jedem Element der Liste ist ein Index zugeordnet
print( Feld[3] ); ??
0 1 2 3 4 5 6 7 8 9 10
4 17 19 21 5 88 4 9 77 3 14
int –Array mit dem Namen „Feld“
Wie deklariert man einen Array (1. Schritt)
int [] arrayOfInts;
Datentyp der Arrayelemente
Eckige Klammern geben an: Es
handelt sich um einen Array
Name des Arrays
Es gelten alle Regeln für Variablennamen
•
Es wurde noch nicht festgelegt:
•
Wie viele Elemente soll das Array enthalten?
•
(Es wurde noch kein Speicher für die Array-Elemente
Wie man einen Array erzeugt (2. Schritt)
Es soll Speicher für die Arrayelemente reserviert werden.
•
int numberOfElements = 42;
•
arrayOfInts = new int [numberOfElements];
Enthält
Referenz auf Array im Speicher
Schlüsselwort new:
Nutzt Datentyp und Anzahl um
Speicher zu
reservieren. Liefert Speicheraddresse zurück
Datentyp der Elemente
Anzahl der
Elemente
Fest, kann
nachträglich
nicht geändert
werden.
Wie man einen Array benutzt (3. Schritt)
int numberOfElements = 5;
arrayOfInts = new int numberOfElements];
arrayOfInts[0] = 12;
arrayOfInts[1] = 1;
arrayOfInts[2] = 22;
arrayOfInts[3] = 55;
arrayOfInts[4] = 43;
for (int i=0; i<5; i=i+1) { arrayOfInts[i] = i+44;
}
Übung: Deklarieren Sie Arrays inklusive dem zugehörigen Speicher
100 Fließkommazahlen:
float[] hundredFloats = new float[100];
12 Ganzzahlarrays:
int faktor=33;
int[] someIntArrays = new int[12];
for(int i=0; i<12; i++) {
someIntArrays[i] = (i+2)*(faktor);
}
Mehrdimensionales Array
Beispiele:
Bild: Pixel pro Zeile, pro Spalte Matrix: Mathematik
Spielfeld: Schach, Dame
Anzahl der Dimensionen ist nur durch den Speicherplatz begrenzt
0 1 2 3
0 1 2 3
Beispiel einer
Matrix 4x4
Deklaration einer 10x10 Matrix
int n=10;
int m=10;
int[][] a = new int[n][m];
int[][] b = new int[n][m];
for(int i=0; i<n; i++) { for(int j=0; j<m; j++) {
a[i][j] = i+j;
b[i][j] = i+i + j<<1;
} }
// << bedeutet Multiplikation mit zwei
// >> bedeutet Multiplikation mit 0,5
Sichere Initialisierung von Arrays
Anstatt
float[] werte = new float[6];
for(int i = 0; i < 6; i++) { werte[i] = 0;
}
lässt sich sicherer schreiben:
int[]
float[] werte = new float[6];
for(int i = 0; i < werte.length; i++) {
werte[i] = 0;
Kurzform für kleine Arrays:
Anstatt
int[] meinFeld = new int[3];
meinFeld[0] = 8;
meinFeld[1] = 3;
meinFeld[2] = -1;
lässt sich kürzer schreiben:
int[] meinFeld = { 8, 3, -1};
•
prog1
Übungen
int[] nums = { 5, 4, 2, 7, 8, 14, 6, 4};
Aufgabe
•
Addieren Sie zu jedem Arrayelement seinen Nachfolger im Array.
•
Ignorieren Sie den letzten Wert
Übungen
int[] nums = { 5, 4, 2, 7, 8, 14, 6, 4};
Aufgabe
•
Berechnen Sie die Summe aller Arrayelemente.
Übungen
int[] feldA = { 5, 4, 2, 7, 8, 14, 6, 4};
int[] feldB = { 1, 2, 3, 4, 5, 6, 7, 8};
Aufgabe
•
Addieren Sie die beiden Arrays in ein neues Feld feldC
Zusammenfassung
Arrays vereinfachen das Speichern von Gruppen oder Listen
•
Arrayelemente haben einen gemeinsamen Datentyp
•
Beliebige Länge, aber nach Festlegung unveränderlich
•
jedes Element hat einen Index (ab 0)
Erzeugen von Arrays geschieht in zwei Schritten:
•
Deklariere des Arrays (Typ und Name)
•
Reserviere Speicher (legt Länge fest, Schlüsselwort new)
•
Kann auch mit einer Zeile erledigt werden.
Arrays können direkt initialisiert werden: { 1, 17, 28 } For-Schleifen und Arrays treten oft gemeinsam auf:
•
initialisiere alle Elemente
•
Durchlaufe alle Elemente
Zugriff auf Arrayelemente erfolgt mit [index]
Übungen
int[] nums = { 5, 4, 2, 7, 8, 14, 6, 4};
•
Berechnen Sie die Summe aller Arrayelemente.
Teilkapitel Funktionen
• Modularität
• Deklaration und Definition
• Aufruf
• Parameterübergabe
• Rückgabewerte
• Wiederbenutzbarkeit
Was ist eine Funktion?
Ein benannter Code-Block Bereits bekannte Beispiele:
setup(), draw(), mousePressed() background(), ellipse(), rect()
In Pseudocode: Überschriften auf einer “höheren” Ebene
•
Lösche den Hintergrund
•
Zeichne Raumschiff
•
Zeichne Gegner
•
Bewege Raumschiff abhängig von der Tastatur
•
Bewege Gegner
Funktionsaufruf
Nassi-Shneiderman
Vom Pseudocode zu Funktionen
Bei jedem draw-Durchlauf:
•
Lösche den Hintergrund
•
Zeichne das Raumschiff
•
Zeichne die Gegner
•
Bewege das Raumschiff
•
Nimm Tastatureingabe entgegen
•
Bewege das Raumschiff
•
Bewege die Gegner
void draw() {
background(0);
drawSpaceship();
drawEnemies();
moveShip();
moveEnemies();
}
Vom Pseudocode zu Funktionen: Server
Schleife mit kompletten Code:
•
Ist am Port eine Nachricht
•
Lese Nachricht
•
Erzeuge freie Portadresse
•
Sende Empfänger den freien Port
void main() { isMessage();
readMessage();
createfreePort();
sendfreePort();
}
Vorteile:
•
Code wird ausgelagert
•
Kann mehrfach verwendet werden, auch von Kollegen
•
Aufruf-Code ist übersichtlich
•
Information-Hiding (Details interessieren JETZT nicht)
Weshalb nutzt man Funktionen?
Wird die draw-Funktion lang und unübersichtlich?
Zwei Grundprinzipien guter Programmierung:
•
1) Modularität
•
Teile den Code in kleinere Teile
•
Besser zu managen und lesen
•
Vermindert Anzahl lokaler Variable
•
2) Wiederverwendbarkeit
•
Duplizierter Code (Copy/Paste) ist nicht gut
•
Muss an mehreren Stellen unterhalten werden
•
Besser: Stecke duplizierten Code in eine neue Funktion
und rufe diese von verschiedenen Stellen auf.
Deklaration einer Funktion
Rückgabewert Fkt-Name ( Parameterliste ) { Variablendeklaration
Verarbeitender Code Optionale Rückgabe } // Ende von Fkt-Name
Funktionsdeklaration:
•
Teilt dem Compiler mit, dass ein neuer, benannter Codeblock vorhanden ist und wie dieser funktioniert
Weitere Regeln:
•
Funktionen werden außerhalb anderer Funktionen deklariert.
Namensgebung:
Gruppiere Code in verwandte Teile: Funktionen
void draw() {
background(255);
// Aendere Ort x um Geschw.
x = x + speed;
// Reflektieren von Kanten if(x > width || x < 0) {
speed = -speed;
}
// Zeichne Kreis bei x stroke(0);
fill(175);
ellipse(x, 100, 32, 32);
}
Bewege den Ball Init Screen
Reflektiere Ball an Kanten
Zeichne alle
Elemente
Benenne die Blöcke, deklariere Funktionen
// MAIN
void draw() {
initCanvas();
bewege();
abprallen();
zeichnen();
}
void abprallen() {
if(x > width || x < 0) { speed = -speed;
} }
void bewege() {
x += speed;
}
void zeichnen() {
stroke(0);
fill(175);
ellipse(x, 100, 32, 32);
void initCanvas() {
background(255)
}
Parameter
•
Wie geht man vor, wenn die Funktion beim Aufruf unterschiedliche Dinge tun soll?
•
„drawRectangles“ mit unterschiedlichen Farben Einige Beispiele:
•
size(200, 200);
•
ellipse(x, y, width, height);
Frage:
•
Wie schreibe ich eigene Funktionen, die Parameter empfangen?
Argumente und Parameter
Argumente werden gesendet, Parameter werden empfangen
/**
* Zeichne einen schwarzen Kreis
* Parameter: diameter, der Durchmesser
*/
void drawBlackCircle(int diameter) { fill(0);
// uebergibt den Durchmesser als Argument ellipse(50, 50, diameter, diameter);
}
Regeln für Funktionen
•
Es muss dieselbe Anzahl an Argumenten übergeben wie Parameter definiert sind
•
Die Argumente müssen einen zum Parameter kompatiblen Typ besitzen. Eventuelles Casting
•
double Parameter kann double, float, int, ... empfangen
•
int Parameter kann int, short, ..., aber kein float, double, long empfangen.
•
Die übergebenen Werte können sein:
•
Explizite Werte (Literale: 20, 4.3, ...)
•
Variablen (x, y, size, ...)
•
Der Wert eines Ausdrucks (8 + 3, 4*x)
•
Parameter werden wie lokale Variable behandelt:
•
Auf sie kann nur innerhalb der Funktion zugegriffen werden.
void draw() {
float aktuellerStundenlohn = 10.25;
float prozentErhoehung = 3.0;
zeigeNeuenStundenlohn(
aktuellerStundenlohn, prozentErhoehung);
} /*
•
Die Funktion gibt den neuen Stundenlohn aus.
•
lohnAktuell ist der zur Zeit gültige Stundenlohn
•
erhoehung ist die prozentuale Erhoehung
*/
schreiben Sie die passende Funktion:
Parameter und Code
Kann eine aufgerufenen Funktion die übergebenen Argumente verändern?
•
Die ist potentiell gefährlich.
•
In Processing und Java gelten folgende Regeln:
•
Die Werte aller atomaren Datentypen (int, float, ...) werden bei der Übergabe kopiert. (pass by value)
•
Die Adressen aller nicht atomaren Datentypen
(Arrays) werden bei der Übergabe kopiert, nicht jedoch
die Werte (pass by reference).
“Pass by Value” vs. “Pass by Reference”
void draw() {
int n = 10;
println(n);
byValue(n);
println(n);
}
void byValue(int num) {
num = 73;
println(num);
}
void draw() {
int[] n = { 10 };
println(n[0]);
byRef(n);
println(n[0]);
}
void byRef(int[] num) {
num[0] = 73;
println(num[0]);
}
Ausgabe1 Ausgabe2
10 10
73 73
Ausgabe1 Ausgabe2
10 10
73 73
✘ ✘
✔ ✔
Rückgabewerte
•
Bisher wurden von den Funktionen keine Werte zurückgegeben.
•
Die wird durch das Schlüsselwort void für den Rückgabewert ausgedrückt
•
Bei der Deklaration einer Funktion gibt der erste Teil den Rückgabetyp an:
Rückgabewert Fkt-Name ( Parameterliste ) { Variablendeklaration
Verarbeitender Code
Optionale Rückgabe
} // Ende von Fkt-Name
Rückgabewerte
void setup() {
int meinArray = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int meineSumme = calcSumme(meinArray);
} /**
* Berechnet die Summe der Elemente des Arrays
* Parameter: werte des aufzusummierenden int-Arrays
* Rueckgabewert: die Summe der Arrayelemente
*/
int calcSumme(int[] werte) { int sum = 0;
for(int i=0; i<werte.length; i++) { sum += werte[i];
}
return sum; // Gibt eine Kopie zurueck
Zusammenfassung
Funktionen sind nützlich:
•
1) Aufteilen des Codes in kleinere, benannte Teile
•
2) Verhindern Code-Duplizierung
•
3) können wiederbenutzt werden Processing ist eine Funktionsbibliothek:
•
gibt Funktionen vor: line(), ellipse(), rect(), ....
•
es kann Code in spezielle Funktionen geschrieben werden:
•
setup(), draw(), mousePressed(), ....
•
Es können eigene Funktionen definiert werden
•
Funktionen erhalten Argumente, die Ihr Verhalten beeinflussen
•
Funktionen übernehmen die Argumente in Parameter
•
Atomare Datentypen werden kopiert (pass by value).
•