1 Programmiersprachen

Werbung
1
Programmiersprachen
• Um einen Algorithmus in einer von einer Maschine
ausführbaren Form beschreiben zu können, verwenden wir eine
formale Sprache.
– formale Beschreibung des Aufbaus der ”Worte” und ”Sätze”,
die zur Sprache gehören
– Anfällig gegenüber Mehrdeutigkeit, Veränderungen und
Spontanität
• Eine Beschreibung eines Algorithmus in einer formalen (formal
beschriebenen) Sprache heisst ein Programm, die formale
Sprache eine Programmiersprache
1
Programmiersprache vs. natürliche Sprache
Eine natürliche Sprache ist ein komplexes System aus Lauten und
Zeichen
• Historisch gewachsen
• Ständig im Wandel
• Robust, Mehrdeutig, Ungenau
• Verwendung willkürlicher gesprochener Symbole mit
festgelegter Bedeutung (Wörterbücher, Rechtschreibregeln,
Trennungsregeln, Grammatikregeln, Ausnahme-Listen,
Sprach-”Gefühl”)
2
Eine Programmiersprache soll:
•
Datenstrukturen anbieten — zum Speichern und effizienten
Bearbeitung von Daten
•
Operationen auf Daten erlauben
•
Kontrollstrukturen zur Ablaufsteuerung bereitstellen.
3
In dieser Vorlesung diskutieren wir Imperative
Programmiersprachen, die eng mit dem von Neumann’schen
Maschinenmodell verknüpft sind.
•
Ein imperatives Programm beschreibt eine Berechnung durch
eine Folge von Anweisungen, die den Programmstatus
(Speicherzellen, Programmzähler) verändern.
•
Der Programmzähler der CPU arbeitet Anweisung nach
Anweisung sequentiell ab (der Programmierer hat seine
Anweisungen explizit aufzureihen und
Wiederholungen/Sprünge zu kodieren)
•
Der Speicher der Maschine dient zur Zustandsprotokollierung
(der Zustand eines Algorithmus wird durch
Variablenzuweisung bzw. -auslesen explizit kontrolliert)
Diese Vorgehensweise ist unterschiedlich zur Programmierung in
einer (↑funktionalen Programmiersprache)
4
1.1
Java - eine Programmiersprache
5
Ein erstes Java-Programm:
public class Hello {
public static void main ( String[] args ) {
int zahl, quadrat;
zahl = 4;
quadrat = zahl * zahl; // offensichtlich eine Operation
String text = "Das Quadrat von ";
System.out.println(text + zahl + " ist " + quadrat);
}
}
6
Erläuterungen:
•
Jedes Programm hat einen Namen (hier: Hello).
•
Der Name steht hinter dem Schlüsselwort
Klasse, was public ist, lernen wir später.
•
Der Name der Datei, die den Programmtext speichert, muss
zum Namen des Programms “passen”, d.h. in diesem Fall
Hello.java heißen.
•
Das Programm ist der Rumpf des Hauptprogramms, d.h. der
Funktion main().
•
Die Programm-Ausführung eines Java-Programms startet stets
mit einem Aufruf von dieser Funktion main().
7
class (was eine
•
Jedes Programm sollte Kommentare enthalten, damit man sich
selbst später noch darin zurecht findet!
•
Ein Kommentar in Java hat etwa die Form:
// Das ist ein Kommentar!!!
•
Wenn er sich über mehrere Zeilen erstrecken soll, kann er auch
so aussehen:
/* Dieser Kommentar geht
über mehrere Zeilen! */
8
Der ”Edit-Compile-Run”-Zyklus:
• Erstellen (Editieren) des Programms mit einem Text-Editor
z.B. Editor, Emacs, Word, etc.
• Speichern des Programms als Textdatei
• Übersetzen (Kompilieren) des Programms in eine
maschinennnahe Sprache
• Ausführen des übersetzten Programms
9
Java Programm Übersetzung:
Stufe 1: Übersetzen des Quelltextes duch den Java-Compiler javac in
Bytecode
c http://www.gailer-net.de/tutorials/java/Notes/chap05/ch05_3.html
⃝
10
Java Programm Übersetzung:
Stufe 2: Der Java-Interpreter java führt den Code aus — Interpreter
und CPU bilden eine Java Virtual Machine (JVM)
c http://www.gailer-net.de/tutorials/java/Notes/chap05/ch05_4.html
⃝
11
1.2
Variablen
• Um Daten zu speichern und auf gespeicherte Daten zugreifen zu
können, stellt Java Variablen zur Verfügung.
• Variablen beziehen sich auf Speicherstellen im Hauptspeicher,
die Daten eines ganz bestimmten Typs speichern können.
• Variablen müssen erst einmal eingeführt, d.h. deklariert werden.
12
Beispiel:
int zahl, quadrat;
String text = "Das Quadrat von ";
Diese Deklaration führt die drei Variablen mit den Namen zahl,
quadrat und text ein.
13
Erklärung:
•
Das Schlüsselwort int besagt, dass diese Variablen ganze
Zahlen (”Integers”) — der Typ der Variablen — speichern
sollen.
•
Das Schlüsselwort String besagt, dass diese Variable
Zeichenketten speichern soll.
•
Variablen können dann benutzt werden, um anzugeben, auf
welche Daten Operationen angewendet werden sollen.
•
Variablen in einer Aufzählung sind durch Kommas “,”
getrennt.
•
Am Ende steht ein Semikolon ”;”.
14
Java-Datentypen
In Java können unterschiedliche Arten von Datentypen verwendet
werden:
•
Primitive Datentypen
• Ganzzahlige numerische Datentypen: short, int, long, ...
• Logischer Datentyp: boolean
• Rationale numerische Datentypen: float, double, ...
• Alphanumerischer Datentyp: char
•
Vordefinierte Datentypen (z.B. : String, BufferedReader,
InputStreamReader)
•
Selbstdefinierte Datentypen
15
Java-Basistypen
Der Typ int gehört zu den Basistypen (primitive Datentypen), die
von Java bereitgestellt werden.
•
Zu jedem Basistyp gibt es eine Menge möglicher Werte.
•
Jeder Wert eines Basistyps benötigt die gleiche Menge Platz, um
ihn im Rechner zu repräsentieren.
•
Der Platz wird in Bit gemessen.
(Wie viele Werte kann man mit n Bit darstellen?)
16
Es gibt vier primitive Datentypen für ganze Zahlen:
Typ
Platz
kleinster Wert
größter Wert
byte
8
−128
127
short
16
−32 768
32 767
int
32
−2 147 483 648
2 147 483 647
long
64
−9 223 372 036 854 775 808
9 223 372 036 854 775 807
Die Benutzung kleinerer Typen wie byte oder short spart Platz.
17
Es gibt zwei primitive Datentypen für Gleitkommazahlen:
Typ
Platz
kleinster Wert
größter Wert
float
32
ca. -3.4e+38
ca. 3.4e+38
7 signifikante Stellen
double
64
ca. -1.7e+308
ca. 1.7e+308
15 signifikante Stellen
•
Für die Auswahl des geeigneten Typs sollte die gewünschte
Genauigkeit des Ergebnisses berücksichtigt werden.
•
Eine Konstante gilt als Gleitkommazahl, wenn sie einen
Dezimalpunkt oder einen Exponenten (durch E oder e
eingeleitet) enthält (z.B.: 2.34, 1.7e+308, 3.2E-2).
•
Durch Anhängen von f oder F bzw. d oder D werden
Gleitkomma-Konstanten als float- bzw. double-Werte
kenntlich gemacht (z.B.: 2.34f, 1.7e8D).
•
Ohne Zusatz werden Konstanten als double interpretiert.
18
... weitere Basistypen:
Typ
boolean
char
Platz
Werte
1
true, false
16
alle Unicode-Zeichen
Unicode ist ein Zeichensatz, der alle irgendwo auf der Welt gängigen
Alphabete umfasst, also zum Beispiel:
•
die Zeichen unserer Tastatur (inklusive Umlaute);
•
die chinesischen Schriftzeichen;
•
die ägyptischen Hieroglyphen ...
char-Konstanten schreibt man mit Hochkommas: 'A', ';', '\n'.
19
Weitere Java-Datentypen
Der Datentyp String für Wörter ist kein Basistyp, sondern eine
Klasse (dazu kommen wir später ...)
Hier behandeln wir nur zwei Eigenschaften:
•
Man kann Wörter in Variablen vom Typ String abspeichern.
•
String-Konstanten haben die Form "Hello World!";
•
Man kann Wörter mithilfe des Operators “+” konkatenieren.
20
Beispiel:
String s0 = "";
String s1 = "Hel";
String s2 = "lo Wo";
String s3 = "rld!";
System.out.println(s0 + s1 + s2 + s3);
... schreibt
Hello World!
21
auf die Ausgabe
1.3
Operationen
Die Operationen sollen es gestatten, die Werte von Variablen zu
modifizieren.
Operationen auf ganzen Zahlen:
•
Negation -
•
Addition, Subtraktion, Multiplikation +, -, *
•
Ganzzahlige Division /, Modulo (Divisionsrest) %
•
Gleichheit, Ungleichheit ==, !=
•
Größer, größer gleich, kleiner, kleiner gleich >, >=, <, <=
•
Bitoperationen (später)
22
Operationen auf Gleitkommazahlen:
•
Negation -
•
Addition, Subtraktion, Multiplikation +, -, *
•
Division /, Modulo (Divisionsrest) %
•
Gleichheit, Ungleichheit ==, !=
•
Größer, größer gleich, kleiner, kleiner gleich >, >=, <, <=
23
Operationen auf Variablen vom Typ boolean:
Kann bei Zuweisungen von logischen Ausdrücken verwendet
werden und wird implizit bei Kontrollstrukturen verwendet.
Logische Operatoren:
•
logische Negation: !
•
logisches UND: &&
(a && b) ist nur dann wahr, wenn a und b beide wahr sind.
•
logisches ODER: ||
(a || b) ist nur dann falsch, wenn a und b beide falsch sind.
Beachte: Das Ergebniss einer Vergleichsoperation auf Ganz- oder
Gleitkommazahlen liefert einen booleschen Wert.
24
Eine wichtige Operation ist die Zuweisung.
Die Zuweisung weist der Variablen auf der linken Seite den Wert des
Ausdrucks auf der rechten Seite zu.
Ein Ausdruck ist eine Kombination von
•
Literalen — Zeichen, die einen Wert darstellen, z.B.: 3.456,
•
Operatoren — Symbole, wie ”+” oder ”*”, die Operationen auf
Operanden darstellen,
•
Variablen
•
Klammern — ”(” und ”)”,
die verwendet wird, um einen Wert zu berechnen.
25
Beispiele:
•
x = 7;
Die Variable x erhält den Wert 7.
•
result = x;
Der Wert der Variablen x wird ermittelt und der Variablen
result zugewiesen.
•
result = x + 19;
Der Wert der Variablen x wird ermittelt, 19 dazu gezählt und
dann das Ergebnis der Variablen result zugewiesen.
26
•
result = x - 5;
Der Wert der Variablen x wird ermittelt, 5 abgezogen und dann
das Ergebnis der Variablen result zugewiesen.
•
result = (x - 5) * (x + 3) + -x;
Beachte die richtige Klammerung und die Unterscheidung
zwischen unären und binären Operatoren.
27
Inkrementieren und Dekrementieren
Die unären Operatoren ++ und - inkrementieren bzw.
dekrementieren eine Ganz- oder Gleikommazahl um 1.
• ++ und - können vor (prefix) oder nach (postfix) dem
Operanden stehen.
• Wird die Prefix-Version in einem Ausdruck verwendet, so wird
der bereits inkrementierte/dekrementierte Wert verwendet.
• Wird die Postfix-Version in einem Ausdruck verwendet, so wird
der initiale Wert verwendet. Die Operation wird erst nach der
Ausdrucksauswertung durchgeführt.
28
Beispiel
class PrePostDemo {
public static void main(String[] args){
int i = 3;
i++;
System.out.println(i);
++i;
System.out.println(i);
System.out.println(++i);
System.out.println(i++);
System.out.println(i);
}
}
29
// "4"
//
//
//
//
"5"
"6"
"6"
"7"
Präzedenz (Auswertereihenfolge) der
Operatoren
Unäre Operatoren ++, -, +, binäre arithmetische Operatoren *, /, +, Vergleichsoperatoren <, <=, >, >=, == !=
Logische Operatoren &&, ||
Zuweisungs-Operator =
30
Achtung:
Java warnt nicht vor Überlauf/Unterlauf !!
Beispiel:
int x;
x = 2147483647; // grösstes int
x = x+1;
... setzt x auf
-2147483648
31
Achtung:
•
Java bezeichnet die Zuweisung mit “=”anstelle von “:=”
(Erbschaft von C ...)
•
Jede Zuweisung wird mit einem Semikolon “;” beendet.
•
In der Zuweisung x = x + 1; greift das x auf der rechten Seite
auf den Wert vor der Zuweisung zu.
•
Zuweisung können auch direkt bei der Variablendeklaration
durchgeführt werden, z.B.: String name = Hello World!;
•
Konstanten ändern ihren Wert während der Laufzeit des
Programms nicht, z.B.: final float PI = 3.1415;
32
1.4
Typen und Casts
Werden die Operatoren +, -, *, /, % auf ein Paar von Argumenten
verschiedenen Typs angewendet, wird automatisch vorher der
speziellere in den allgemeineren umgewandelt (implizite
Typumwandlung oder implicit Type Cast) a
a http://en.wikibooks.org/w/index.php?title=Java_Programming/Primitive_Types
33
double
float
Gleitkomma-Zahlen
long
int
ganze Zahlen
short
byte
char
34
Implizite Typumwandlung: Eine Variable wird einer anderen von
anderem, erlaubten Typ zugewiesen oder eine Operation eines
solchen Typs auf sie angwandt.
Beispiel:
short s = 123;
int i;
int j = 1024;
i = s;
i = j + s;
35
Beispiel:
short xs = 1;
int x = 999999999;
(x + xs) liefert den int-Wert
1000000000
float xs = 1.0f;
int x = 999999999;
(x + xs) liefert den float-Wert
36
1.0E9
Achtung:
•
Das Ergebnis einer Operation auf float kann aus dem Bereich
von float herausführen. Dann ergibt sich der Wert Infinity
oder -Infinity.
Das gleiche gilt für double.
•
Das Ergebnis einer Operation auf Basistypen, die in int
enthalten sind (außer char), liefern ein int.
•
Wird das Ergebnis einer Variablen zugewiesen, sollte deren Typ
dies zulassen
•
Mithilfe von expliziten Type Casts lässt sich das (evt. unter
Verlust von Information) stets bewerkstelligen.
•
Java lässt keine Konvertierung von boolean zu anderen
Datentypen zu.
37
Beispiel:
int i, j;
double d;
...
i = j + d;
i = (int) (j+d);
// Fehler: i ist int, aber j + d ist double
/* Korrekt: aber Verluste bei der Konversion
werden in Kauf genommen */
38
Beispiel:
byte x = 1;
...
x++;
x = x + 1;
// Korrekt: x ist nun 2
39
Beispiel:
byte x = 1;
...
x++;
x = x + 1;
// Korrekt: x ist nun 2
// Fehler: Auswertung von x+1 liefert int-Wert
40
Beispiele:
(float) 1.7e+308 liefert Infinity
(long) 1.7e+308
liefert 9223372036854775807
(d.h. den größten long-Wert)
(int) 1.7e+308
liefert 2147483647
(d.h. den größten int-Wert)
(short) 1.7e+308 liefert -1
(int) 1.0e9
liefert 1000000000
(int) 1.11
liefert 1
(int) -2.11
liefert -2
41
Beachte:
•
Jeder Wert in Java hat eine Darstellung als String.
•
Wird der Operator “+” auf einen Wert vom Typ String und
einen anderen Wert x angewendet, wird x automatisch in seine
String-Darstellung konvertiert ...
==⇒ ... liefert einfache Methode, um float oder double
auszugeben !!!
Beispiel:
double x = -0.55e13;
System.out.println("Eine Gleitkommazahl: " + x);
... schreibt
Eine Gleitkommazahl: -0.55E13
42
auf die Ausgabe
1.5
Java-IO (Input/Output)
Sehr häufig benötigen wir Operationen, um Daten (Zahlen) einlesen
bzw. ausgeben zu können.
•
System.out.println(Meine Ausgabe);
Diese Operation schreibt den Text ”Meine Ausgabe” auf die
Ausgabe.
•
System.out.println(42);
Diese Operation schreibt 42 auf die Ausgabe.
•
System.out.println(result);
Diese Operation bestimmt den Wert der Variablen result und
schreibt dann diesen auf die Ausgabe.
43
Das Einlesen von Daten ist komplizierter!
44
import java.io.*;
class ReadMe {
public static void main (String[] args) throws IOException {
// Catch me if you can
BufferedReader stdin =
new BufferedReader (new InputStreamReader(System.in));
String inData;
inData = stdin.readLine();
// inData in int konvertieren
int zahl
= Integer.parseInt(inData);
}
}
45
Online-Tutorial
Java IO
http://www.gailer-net.de/tutorials/java/Notes/chap10/ch10_1.html
46
Bemerkung
Zur Vereinfachung werden wir im Folgenden oft zum Lesen von
Daten die Funktion read() und zum Schreiben des Wertes einer
Variablen die Funktion write(varname) oder
write(Literal)verwenden.
Beide Funktionen sind nicht Bestandteil von Java und werden nur
zur Vereinfachung eingeführt!
47
1.6
Kontrollstrukturen
Sequenz:
int x, y, result;
x = read();
y = read();
result = x + y;
write(result);
48
•
Zu jedem Zeitpunkt wird nur eine Anweisung (Statement)
ausgeführt.
•
Jede Anweisung wird genau einmal ausgeführt. Keine wird
wiederholt, keine ausgelassen.
•
Die Reihenfolge, in der die Anweisungen ausgeführt werden,
ist die gleiche, in der sie im Programm stehen (d.h.
nacheinander).
•
Mit Beendigung der letzten Anweisung endet die
Programm-Ausführung.
==⇒ Sequenz alleine erlaubt nur sehr einfache Programme.
49
Selektion (bedingte Auswahl):
Allgemein:
if ( cond ) stmt else stmt
50
Selektion (bedingte Auswahl):
int x, y, result;
x = read();
y = read();
if (x > y)
result = x - y;
else
result = y - x;
System.out.println(result);
•
Zuerst wird die Bedingung ausgewertet.
•
Ist sie erfüllt, wird die nächste Anweisung ausgeführt.
•
Ist sie nicht erfüllt, wird die Anweisung nach dem else
ausgeführt.
51
Beachte:
•
Anweisungen können selbst wieder aus Selektionen bestehen:
int x;
x = read();
if (x == 0)
write(0);
else if (x < 0)
write(-1);
else
write(+1);
52
•
... oder aus (geklammerten) Folgen von Anweisungen:
int x, y;
x = read();
if (x != 0) {
y = read();
if (x > y)
write(x);
else
write(y);
} else
write(0);
53
Beachte: ein else bezieht sich immer auf das zuletzt öffnende if im
selben Block
if (x > 0)
if (x < 10)
write("aaa");
else
write("bbb");
54
Beachte: durch Klammerung wird ein seprater Block definiert
if (x > 0) {
if (x < 10)
write("aaa");
}
else
write("bbb");
55
Iteration (wiederholte Ausführung):
Auch mit Sequenz und Selektion kann noch nicht viel berechnet
werden ... oder wie sollten sich wiederholende Aktionen mit sich
ändernden Werten durchgeführt werden?
Allgemein:
while ( cond ) stmt
56
Iteration (wiederholte Ausführung):
int x, y;
x = read();
y = read();
while (x !=
if (x <
y =
else
x =
write(x);
y)
y)
y - x;
x - y;
57
•
Zuerst wird die Bedingung ausgewertet.
•
Ist sie erfüllt, wird der Rumpf des while-Statements ausgeführt.
•
der Rumpf besteht aus einer Anweisung oder aus einer
geklammerten Sequenz von Anweisungen
•
Nach Ausführung des Rumpfs wird das gesamte
while-Statement erneut ausgeführt.
•
Ist die Bedingung nicht erfüllt, fährt die
Programm-Ausführung hinter dem while-Statement fort.
58
Jede (partielle) Funktion auf ganzen Zahlen, die
überhaupt berechenbar ist, läßt sich mit Selektion,
Sequenz, Iteration, berechnen
Beweis:
↑ Berechenbarkeitstheorie.
Idee:
Eine Turing-Maschine kann alles berechnen...
Versuche, eine Turing-Maschine zu simulieren!
59
Und nun der Euklidische Algorithmus in Java
import java.io.*;
public class GGT {
public static void main (String[] args) throws IOException {
BufferedReader stdin = new BufferedReader (new InputStreamReader(System.in));
}
}
int x, y;
String inData = stdin.readLine();
x = Integer.parseInt(inData);
inData = stdin.readLine();
y = Integer.parseInt(inData);
while (x != y)
if (x < y)
y = y - x;
else
x = x - y;
System.out.println(x);
60
2
Mehr Java
Oft müssen viele Werte gleichen Typs gespeichert werden.
Idee:
•
Lege sie konsekutiv ab!
•
Greife auf einzelne Werte über ihren Index zu!
Feld:
17 3
-2
9
0
1
Index:
0
2
3
4
5
1
61
Beispiel:
Einlesen eines Felds
int[] a; // Deklaration
int n = read();
a = new int[n];
// Anlegen des Felds
int i = 0;
while (i < n) {
a[i] = read();
i = i+1;
}
62
•
type [] name ; deklariert eine Variable für ein Feld (array),
dessen Elemente vom Typ type sind.
•
Alternative Schreibweise:
type name [];
•
Das Kommando new legt ein Feld einer gegebenen Größe an
und liefert einen Verweis darauf zurück:
a
a = new int[6];
a
63
•
Der Wert einer Feld-Variable ist also ein Verweis.
•
int[] b = a; kopiert den Verweis der Variablen a in die
Variable b:
a
int[] b = a;
a
b
64
•
Die Elemente eines Felds sind von 0 an durchnumeriert.
•
Die Anzahl der Elemente des Felds name ist name.length.
•
Auf das i-te Element des Felds name greift man mittels
name[i] zu.
•
Bei jedem Zugriff wird überprüft, ob der Index erlaubt ist, d.h.
im Intervall {0, . . . , name.length-1} liegt.
•
Liegt der Index außerhalb des Intervalls, wird die
ArrayIndexOutofBoundsException ausgelöst (↑Exceptions).
65
Mehrdimensionale Felder
•
Java unterstützt direkt nur ein-dimensionale Felder.
•
Ein zwei-dimensionales Feld ist ein Feld von Feldern a
a http://chortle.ccsu.edu/java5/Notes/chap49C/ch49C_1.html
66
a
a = new int[5][6];
a
67
2.1
Mehr Kontrollstrukturen
Typische Form der Iteration über Felder:
•
Initialisierung des Laufindex;
•
while-Schleife mit Eintrittsbedingung für den Rumpf;
•
Modifizierung des Laufindex am Ende des Rumpfs.
68
Beispiel (Forts.):
Bestimmung des Minimums
int result = a[0];
int i = 1;
// Initialisierung
while (i < a.length) {
if (a[i] < result)
result = a[i];
i = i+1; // Modifizierung
}
write(result);
69
Mithilfe des for-Statements:
int result = a[0];
for (int i = 1; i < a.length; ++i)
if (a[i] < result)
result = a[i];
write(result);
70
Allgemein:
for ( init; cond; modify ) stmt
... entspricht:
{ init ; while ( cond ) { stmt modify ;} }
... wobei
++i äquivalent ist zu
i = i+1
71
Warnung:
•
Die Zuweisung x = x+1 ist in Wahrheit ein Ausdruck.
•
Der Wert ist der Wert der rechten Seite.
•
Die Modifizierung der Variable x erfolgt als Seiteneffekt.
•
Der Semikolon “;” hinter einem Ausdruck wirft nur den Wert
weg ...
==⇒
... fatal für Fehler in Bedingungen ...
boolean x = false;
if (x = true)
write("Sorry! This must be an error ...");
72
•
Die Operatoranwendungen ++x und x++
inkrementieren beide den Wert der Variablen x.
•
++x tut das, bevor der Wert des Ausdrucks ermittelt wird
(Pre-Increment).
•
x++ tut das, nachdem der Wert ermittelt wurde
(Post-Increment).
•
a[x++] = 7; entspricht:
a[x] = 7;
x = x+1;
•
a[++x] = 7; entspricht:
x = x+1;
a[x] = 7;
73
Herunterladen