Samstag, 23. Februar 2013

Teil 4: Kontrollstrukturen - Einfache Bedingungen


Kontrollstrukturen bestimmen in allen Programmiersprachen den Programmfluss. Sie unterteilen sich grob gesehen in Bedingungen und Schleifen. Wie der Name vermuten lässt, sind Bedingungen dazu da bestimmte Anweisungen auszuführen, wenn eine bestimmte Bedingung erfüllt ist. Schleifen sorgen dafür, dass Anweisungen immer wieder wiederholt werden, bis eine bestimmte Bedingung eintritt. Sie laufen in einer Schleife.

Doch bleiben wir vorerst bei den Bedingungen. Bedingungen in Programmiersprachen haben prinzipiell 3 grundlegende Bauweisen.

1. wenn die Bedingung erfüllt ist, mache XY
2. wenn die Bedingung erfüllt ist, mache XY, sonst mache YZ
3. wenn die Bedingung erfüllt ist, mache XY, sonst prüfe die nächste Bedingung und erst wenn alle nicht zutreffen, mache YZ

Und fast genau so, kann man das auch in Programmcode umsetzen. Schauen wir uns zuerst einmal die einfachste Form der Bedingungen an: "Wenn die Bedingung erfüllt ist, mache XY." Eine Bedingung ist im Fall eine Programms zumeist die Überprüfung eines Wertes. Ein paar Beispiele für Bedingungen:

a) Hat Variable XY einen bestimmten Wert?
b) Bekommt man beim Ausführen von Anweisung funktion() ein bestimmtes Ergebnis?

Das sind auch die beiden typischsten Bedingungen, auch wenn es noch ein paar mehr gibt. Im Programmcode kann man unsere Bedingung 'a' so umsetzen:

PHP und Perl: if($variable == meinwert) meineanweisung();
Java und C/C++: if(variable == meinwert) meineanweisung();
Python: if(variable == meinwert): 
    meinanweisung
Ruby: if variable == meinwert then meineanweisung end

Natürlich sind das nur sehr einfache Beispiele der ersten Bauweise. Wie Bedingungen syntaktisch im einzelnen auszusehen haben, sollte man wie üblich einer Sprachreferenz entnehmen. Die Beispiele zeigen uns aber in verschiedenen Programmiersprachen wie man mit Bedingungen den Programmfluss steuern kann. Nur wenn die Variable 'variable' den Wert 'meinwert' hat, wird die Anweisung 'meineanweisung' ausgeführt. 

Abstrahieren wir das ganze auf die Grundsyntax um es besser zu verstehen. Eine Bedingung besteht immer aus folgenden Elementen:
  • Schlüsselwort um die Bedingung einzuleiten
  • Wert 1
  • Vergleichsoperator
  • Wert 2
  • Anweisung(en)
Wert 1 wird mit Wert 2 verglichen, wobei der Vergleichsoperator bestimmt was für ein Vergleich vorgenommen wird. In unseren Beispielen überprüft das doppelte Gleichheitszeichen ob Wert 1 (variable) identisch zu Wert 2 (meinwert) ist. Weitere typische Vergleichsoperatoren sind > (Wert 1 muss grösser sein als Wert 2), < (Wert 1 muss kleiner sein als Wert 2), >= (Wert 1 muss grösser oder gleich Wert 2 sein) uvm..

Wert 1 und Wert 2 können in den meisten Programmiersprachen auch die Ergebnisse von Anweisungen sein, ohne dass man diese Ergebnisse zuvor in Variablen ablegen muss. Man schreibt dann einfach die Anweisung an diese Stelle. Ausserdem ist es zumeist möglich mehrere Bedingungen miteinander zu verknüpfen. Details dazu sollte man der entsprechenden Sprachreferenz entnehmen.

Will man mehrere Anweisungen ausführen, wenn eine Bedingung erfüllt ist, spricht man von Anweisungsblöcken. Anweisungsblöcke werden in vielen Programmiersprachen "geklammert". Das heisst es wird markiert wo der Anweisungsblock beginnt und wo er endet. In unseren Beispielen oben sehen wir bei Ruby bereits ein Beispiel dafür. Ruby geht davon aus, dass nach dem 'then' immer ein Anweisungsblock folgt, der beim 'end' abgeschlossen ist. Die Markierung des Anweisungsblocks erfolgt also über Schlüsselwörter. - Schlüsselwörter sind Zeichenketten, die nur zu ihrem Zweck im Code vorkommen dürfen. Es ist z.B. nicht erlaubt seine Variablen nach Schlüsselwörtern zu benennen. Dies führt immer zu einem Fehler. - In vielen anderen Programmiersprachen werden aber tatsächlich Klammern verwendet, wobei { } die am häufigsten vorkommende Klammerung ist. Bei Python erfolgt die Markierung von Anweisungsblöcken über das Einrücken von Code:
if(variable == meinwert): 
    meineanweisung1
    meineanweisung2
Der Doppelpunkt markiert das Ende der Bedingung und den Beginn des Anweisungsblocks. Der Anweisungsblock endet, wenn der Code nicht mehr eingerückt wird.

Wir fassen zusammen: Kontrollstrukturen steuern den Programmfluss. Sie unterteilen sich in Bedingungen und Schleifen. Bedingungen sorgen dafür, dass bestimmte Anweisungen nur ausgeführt werden, wenn die angegebenen Bedingungen erfüllt sind. Die Bedingung selbst besteht immer aus einem Vergleich von Werten, wobei ein Vergleichsoperator angibt welche Art von Vergleich durchgeführt werden soll. Trifft eine Bedingung zu, können eine oder mehrere Anweisungen ausgeführt werden. Werden mehrere Anweisungen ausgeführt, spricht man von Anweisungsblöcken. Anfang und Ende eines Anweisungsblock werden durch Schlüsselwörter oder spezielle Zeichen, zumeist Klammern, markiert. Schlüsselwörter sind Zeichenketten, die man im Programm-Code nur für den vorgesehenen Zweck des Schlüsselworts verwenden kann.

Dienstag, 22. Januar 2013

Teil 3: Anweisungen


Hinweis: Im folgenden Teil wird der Begriff "Wert" im Sinne von Daten verwendet. Ein Wert kann eine Zahl oder ein Zeichen sein und natürlich sind Zahlen und Zeichen im Computer prinzipiell Daten.

Da wir nun wissen was Variablen sind und wofür man sie verwendet, sollten wir uns natürlich auch anschauen wie man sie verwendet. Um einen Wert in einer Variable abzulegen verwendet man eine Anweisung. Den Begriff "Anweisung" kann man dabei ruhig wörtlich nehmen. Wir erteilen dem Computer die Anweisung einen bestimmten Wert in einem bestimmten Speicherbereich abzulegen. 

Anweisungen können recht vielseitig sein. Wenn man einen Wert in einer Variable ablegt, spricht man z.B. von einer "Zuweisung". Man weist der Variable den angegebenen Wert zu. Wenn man überprüft ob eine Variable einen bestimmten Wert enthält, so spricht man von einer "Bedingung", da auf eine solche Überprüfung hin bestimmte Aktionen im Programm ausgeführt werden. Aber dazu später mehr. Bleiben wir vorerst bei den Variablen.

In allen Programmiersprachen erfordert das Verwenden einer Variable mindestens 2 Schritte. Schritt 1 ist die Deklaration der Variable. Dabei sagt man dem Computer, dass er eine Variable anlegen und entsprechend Speicher dafür reservieren soll. Schritt 2 ist dann die Zuweisung eines Wertes zu dieser Variable. 

Nehmen wir als Beispiel eine Integer(Ganzzahl)-Variable. In Java, C, C++ und diversen anderen Programmiersprachen mit strenger Typisierung (d.h. man muss bei der Deklaration der Variablen festlegen welchen Typ von Daten man darin ablegen will) sieht Schritt 1, die Deklaration, so aus:
int i;
'int' (steht für 'Integer') legt in diesem Fall den Datentyp fest. 'i' ist der Name der Variable. Mit dieser Anweisung sagen wir dem Computer also: "Reserviere Speicher für eine Ganzzahl." Auf die Sprachen ohne strenge Typisierung komme ich gleich im Schritt 2 zurück. Das Semikolon am Ende der Anweisung teilt dem Computer mit, dass die Anweisung hier beendet ist und nun eine andere Anweisung folgt. Es gibt aber auch Programmiersprachen, die voraussetzen, dass in jeder Zeile genau eine Anweisung steht. Bei diesen ist das Semikolon nicht notwendig. Ausserdem gibt es auch noch einige Sprachen, die andere Zeichen zum Beenden einer Anweisung verwenden. Details dazu kann man der jeweiligen Sprachreferenz entnehmen.

Im Schritt 2, der Zuweisung, wird nun der Wert zugewiesen. Dies geschieht in den meisten gängigen Programmiersprachen mit dem Gleichheitszeichen.
i = 1;
Mit dieser Anweisung teilen wir dem Computer mit: "Lege den Wert 1 in dem Speicherbereich ab, den du für 'i' reserviert hast." Bei Programmiersprachen ohne strenge Typisierung werden die beiden Schritte zumeist zusammengefasst. Wenn dort also steht 'i=1' dann wird damit automatisch Speicher reserviert und die Daten darin abgelegt, sofern 'i' nicht zuvor schon im Programm verwendet und nicht wieder gelöscht wurde. 

Natürlich könnte ich noch auf diverse Ausnahmen eingehen, die in Sprachen vorkommen, aber diese Anleitung soll eher gemein gehalten bleiben. Daher will ich nur noch darauf hinweisen, dass es auch Programmiersprachen gibt, wo Variablen-Namen mit einem vorangestellten Sonderzeichen gekennzeichnet werden. In PHP und Perl wird z.B. das $-Zeichen jedem Variablennamen vorangestellt. Eine Variable mit Zuweisung in PHP und Perl sieht z.B. dann so aus:
$i = 1;
In Perl kann man auch noch ein 'my' vor den Variablennamen setzen:
my $i = 1;
Das ist notwendig, wenn man den strict-Modus von Perl verwendet, der sicherstellt, dass eine Variable deklariert wird, bevor man sie verwendet. Hierbei wird das Schlüsselwort 'my' genutzt um die Deklaration durchzuführen. Jede Programmiersprache ohne strenge Typisierung zerlegt bei der ersten Verwendung einer Variable eine solche Anweisung immer in unsere 2 Schritte. Man muss sie lediglich als Programmierer nicht gesondert angeben. Auch in C/C++, Java und anderen Sprachen mit strenger Typisierung kann man die 2 Schritte zumeist zusammenfassen.
int i = 1;
Mehr dazu kann man auch in diesem Fall der Sprachreferenz entnehmen. Es gibt aber neben Perl auch andere Programmiersprachen, die eine Variablen-Deklaration mit einem speziellen Wort einleiten.

Aber wie gesagt, können Anweisungen sehr vielfältig sein. Die grundlegenden Anweisungstypen, die in Programmen vorkommen sind aber schnell zusammengefasst:
- Deklarationen
- Zuweisungen
- Bedingungen
- Schleifen
- Funktionsaufrufe
- Funktionskörper
Bei objektorientierten Programmiersprachen kommen noch die Klassenkörper hinzu. Auf alle werde ich im Laufe dieser Anleitung eingehen. 

Wir fassen zusammen: Computer-Programme bestehen aus Anweisungen. Anweisungen sorgen dafür, dass der Computer bestimmte Aktionen ausführt. Sie können in verschiedene Kategorien eingeteilt werden. 
Will man Daten im Arbeitsspeicher des Computers ablegen, verwendet man dafür Variablen. Diese müssen deklariert werden, wodurch der Computer Speicher für die Variable reserviert. Bei manchen Programmiersprachen erfolgt die Deklaration im gleichen Schritt wie die Zuweisung. Unter einer Zuweisung versteht man das Ablegen eines Wertes in dem Speicherbereich, den wir mit dem Variablennamen ansprechen. Sowohl Deklaration als auch Zuweisung sind Anweisungen, da man den Computer anweist etwas bestimmtes zu tun. In diesem Fall das reservieren von Speicher und das Ablegen eines Wertes in diesem zuvor reservierten Speicher. 

Will man Programmieren lernen, muss man nur lernen wie man diese Anweisungstypen auseinanderhalten kann und wozu sie gut sind. Der Rest ist Syntax.

Samstag, 19. Januar 2013

Teil 2: Variablen und Daten


Damit ein Computer mit Daten etwas anfangen kann, muss er diese irgendwo speichern. Dafür hat er verschiedene Speicherorte wie den RAM, die Festplatte, Caches, CPU-Register usw. zur Verfügung. Während der Computer mit diesen Daten arbeitet, schiebt er sie zumeist lustig zwischen den einzelnen Speichern hin und her. Was da im Einzelnen geschieht und warum, müssen wir zum Programmieren aber nicht wissen. Für uns ist vorerst nur wichtig, dass ein Programm alle seine Daten, die es verarbeitet, im RAM ablegt.

Stell dir einen riesigen Platz vor, der in einzelne Quadrate (Lagerplätze) unterteilt ist. Jedes dieser Quadrate hat eine eindeutige Adresse, aber es ist vollständig leer. Dies ist unser Arbeitsspeicher. Wollen wir nun Daten auf diesem Platz sicher lagern und eindeutig zuordnen können, müssen wir auf dem Platz Lagerhäuser bauen. Ein Lagerhaus kann aber problemlos mehrere Lagerplätze umfassen. Wir können also mit der derzeitigen Adressierung der Plätze wenig Anfangen wenn wir einfach nur sagen wollen: „Lege diese Daten in einem bestimmten Lagerhaus ab.“ Mit der Adressierung der Lagerplätze könnten wir nur sagen „Lege diese Daten an einem bestimmten Lagerplatz ab“. Wir müssten uns als Programmierer also ganz viele Adressen merken, die unser Programm benutzt. Ausserdem müsste unser Programm erst einmal ermitteln welche Adressen gerade frei sind. Kurzum: Es wäre unheimlich kompliziert, wenn wir die Lagerhäuser, die wir in einem Programm für die Daten nutzen, nicht benennen würden. 

Und das ist der Punkt, wo wir bei den Variablen sind. Variablen sind im Prinzip die Namen für die Lagerhäuser. Etwas fachlicher ausgedrückt: Variablen ermöglichen es uns Speicherbereiche zu reservieren, zu benennen und in ihnen Daten abzulegen. Und das alles geschieht mit winzig kleinen Ausdrücken in unserem Programmcode, aber auch dazu kommen wir erst etwas später. 

Für Computer sind aber Daten nicht gleich Daten. Ein Computer unterscheidet die Daten in verschiedene Typen. Grundlegend sind das Zahlen und Zeichen. Je nach Programmiersprache, werden diese Grundtypen noch unterteilt. So unterteilen sich Zahlen z.B. häufig noch in ganze Zahlen und Gleitkommazahlen und diese werden dann auch noch in verschiedene Grössen mit unterschiedlichen Möglichkeiten der Genauigkeit aufgeteilt. Es gibt aber auch Programmiersprachen, bei denen sich der Programmierer nicht darum kümmern muss, welchen Datentyp er in einer Variable ablegt. 

Je nachdem welchen Typ unsere Daten haben, benötigt der Computer unterschiedlich viel Platz für sie im Arbeitsspeicher. Eine Ganzzahl mit einem Wert zwischen -32768 und 32768 ist zum Beispiel 16 Bits gross. Grössere Zahlen brauchen dann auch schonmal 32 oder 64 Bits. Ein einzelner Buchstabe kommt üblicherweise mit 8 Bits aus. 

Um bei unserem Lagerhaus-Beispiel zu bleiben: Jedes der Quadrate ist ein Bit gross. Wollen wir also einen einzelnen Buchstaben lagern, benötigen wir ein Lagerhaus das 8 Quadrate gross ist. Bei 2 Buchstaben sind es bereits 16 Bits. 

Wir fassen zusammen: Variablen sind benannte Speicherbereiche im RAM, in denen Daten gespeichert werden können. Man spricht auch davon, dass Variablen Daten (manchmal auch Werte genannt) enthalten und dass man Daten (oder Werte) in ihnen ablegt. Der Datentyp und die gespeicherte Datenmenge definieren die Grösse des Speicherbereichs, der im Arbeitsspeicher belegt wird.

Teil 1: Die grundlegenden Elemente von Programmiersprachen


Hinweis: Zum Verständnis des folgenden Tutorials sind grundlegende Kenntnisse über den Aufbau eines Computers notwendig. Dieses Tutorial legt keinen Wert auf Vollständigkeit und soll lediglich eine grundlegende Einführung in die Programmierung von Anwendungen geben. Desweiteren wird eine gewisse Abstraktion verwendet um den Aufbau von Programmen besser zu veranschaulichen.

Immer wieder werde ich gefragt wie das funktioniert mit dem Programmieren, wie es möglich ist so viele Programmiersprachen zu beherrschen und ob ich für alle Programmiersprachen, die ich kann, Tutorials durcharbeiten musste. Zuerst einmal sei gesagt, dass ich die wenigsten Programmiersprachen wirklich beherrsche. Ich kenne sie nur in den Grundzügen. Lediglich mit einigen Sprachen habe ich mich intensiver beschäftigt, so dass ich sie wirklich beherrsche und beliebige Anwendungen damit schreiben kann.

Grundlegend haben aber fast alle Programmiersprachen die gleichen Elemente. Und wenn man diese kennt, kann man fast jede Programmiersprache lesen und kleinere Fehler in Programmen beheben oder selbst einfache Aufgaben damit lösen. Die gröbsten Unterschiede liegen in der unterschiedlichen Syntax der Sprachen und die kann man binnen weniger Minuten einer zugehörigen Sprachreferenz entnehmen sowie in der Strukturierung des Codes.

Diese Elemente kann man im Groben unterscheiden in:
- Anweisungen
- Variablen
- Kontrollstrukturen

Wobei Kontrollstrukturen eigentlich auch nur Anweisungen sind. Aus diesen 3 Elementen werden weitere Elemente gebildet. Bei prozeduralen Programmiersprachen sind das die Funktionen. Bei objektorientierten Programmiersprachen kommen noch Elemente wie Klassen und Interfaces hinzu. Was „prozedural“ und „objektorientiert“ bedeutet, schauen wir uns später genauer an und warum auch Funktionen, Klassen und Interfaces als Anweisungen betrachtet werden können, wird im Laufe dieses Tutorials auch geklärt.

Doch zuerst einmal wollen wir uns die 3 Grundelemente in den folgenden Teilen etwas genauer anschauen.