***

Programmierlogik der prozeduralen Programmiersprachen

Programmier-Anfängern wird hier gezeigt, worauf es beim Programmieren ankommt.
Behandelt wird die Programmierlogik der prozeduralen Programmiersprachen.

Verfasser: Otto Praxl

Inhalt

Einleitung
Programmiersprachen
Syntax und Semantik
Voraussetzungen zum Programmieren
Schlüsselwörter
Deklarationen
Anweisungen
Ausdrücke
Operatoren
Programmsteuerung (Kontrollstrukturen)
Funktionen, Unterprogramme
Schlusswort

Einleitung

Viele Leute beginnen mit dem Programmieren von PC-Anwendungen oder programmierbaren wissenschaftlichen Taschenrechnern und haben keine Ahnung davon. Sie probieren so lange herum, bis ein Programm "läuft". Diese Art des Lernens kostet Zeit und Mühe und bringt keine Erfolgserlebnisse.

Programmieren ist ein Handwerk, das gelernt werden muss. Es gibt einige Grundlagen, die man beherrschen muss. Diese Grundlagen werden in dem Begriff "Programmierlogik" zusammengefasst.

Mit der Programmierlogik allein ist es aber nicht getan. Man muss auch das Fachgebiet beherrschen, für das man Programme schreibt.

Beispiel:

Wenn man ein Programm für die Berechnung eines Staudamms schreiben will, dann nützt es wenig, wenn man nur die Programmierlogik beherrscht. Man muss auch wissen, wie man einen Staudamm berechnet.

Man muss das Problem (z.B. Staudamm berechnen, ein Problem aus dem Wasserbau) mit allen Nebeneffekten kennen. Dieses Problem muss analysiert werden. Dann findet der Fachmann auch die Problemlösung. Diese wird umgesetzt in eine Programmstruktur. Nun wird beides, Programmstruktur und Problemlösung, unter Berücksichtigung der Programmierlogik in einer bestimmten Programmiersprache formuliert, es entsteht der Quellcode (engl.: source code).

Der Quellcode wird dann mittels eines Übersetzungsprogramms (Compiler) in eine maschinenlesbare Form umgesetzt, die der Computer versteht. Durch Dazubinden der Systembibliotheken mittels eines Bindeprogramms entsteht dann das lauffähige Programm, das dann als ausführbare Datei im Rechner gespeichert wird.

Bei neueren Programmiersystemen (z. B. für Windows-Programme) sind die Systembibliotheken (Runtime-Umgebung, auch "Runtimes" genannt) so umfangreich, dass sie nicht in die Programme eingebunden werden, sondern getrennt installiert werden müssen. Das hat den Vorteil, dass sie auch für andere Programme im System zur Verügung stehen. Auch die Ansteuerung von Peripheriegeräten muss man nicht mehr selber programmieren. Diese stehen als "Treiber" im System zur Verfügung, das Programm muss nur darauf zugreifen.

Programmiersprachen

Es gibt maschinennahe (Assembler-Sprachen) und höhere Programmiersprachen (Compiler-Sprachen). Die Programmierlogik ist bei allen ähnlich. Unterschiede bestehen natürlich hinsichtlich der mathematischen Formulierungen, der Umsetzung der Eingabe- und Ausgabeanweisungen und des Fachbereichs, für den ein Programm geschrieben wird. Beispielsweise brauchen Programme zur Steuerung von Robotern Funktionen für Aktoren und Sensoren, während Programme für astronomische Berechnungen mathematische Funktionen zur Berechnung genauer Zahlenwerte benötigen.

Die alten höheren Programmiersprachen (z.B. ALGOL, FORTRAN, PASCAL, BASIC, C, C++) sind statisch, prozedural und zeilenorientiert. Statisch bedeutet, dass das Programm nur die beschriebene Aufgabe hat, die sich im Ablauf des Programms auch nicht ändert. Prozedural heißt, man muss beim Programmieren die Prozedur, also den Weg zur Lösung des Problems, in Quelltextzeilen beschreiben. Dazu kann man einen beliebigen Texteditor verwenden. Spezielle Programmierumgebungen, sind dafür nicht notwendig. Die Programmierlogik dieser prozeduralen Sprachen wird nachfolgend erläutert.

BASIC ist eine interpretierende Programmiersprache. Das Quellprogramm wird über einen Basic-Interpreter aufgerufen, der jeden Befehl des Quelltextes liest, interpretiert und ausführt. Interpretersprachen sind deshalb langsam.

ALGOL, FORTRAN, PASCAL, C und C++ sind Compilersprachen, bei denen der Quelltext von einem Compiler in eine Assemblersprache und vom Assemblerprogramm dann in den Binärcode übersetzt werden muss. Diese Assembler-Programme laufen sehr schnell, weil durch die vorherige Übersetzung das lauffähige Programm im maschinenlesbaren Binärcode vorliegt. Immer wieder vorkommende Befehle und Funktionen sind meist in schon übersetzten Funktionsbibliotheken (DLL = dynamic link library) vorhanden, die der Programmierer im Quelltext nur aufrufen, aber nicht programmieren muss. Diese DLLs bindet der automatische Programmlader (Loader, Binder) am Schluss zu den kompilierten Teilen dazu. Um die Programme selbst klein zu halten, werden die DLLs meist gesondert gespeichert und beim Installieren verlinkt (an das Programm angebunden). Dadurch können sie auch von anderen Programmen genutzt werden und müssen nur einmal auf dem Computer gespeichert sein.

C und C++ sind die weltweit wichtigsten Programmiersprachen, mit denen professionelle Programmierer arbeiten.

Nach der Entwicklung der Fenstertechnik und der Mausklicks bei den Betriebssystemen wurden auch BASIC, C und C++ an diese Visualsysteme angepasst und Visual Basic, Visual C , Visual C++ und noch andere Visual-Sprachen entwickelt, mit denen die Programmierer in ihrer vertrauten Programmiersprache moderne Programme mit Bildschirmfenstern erzeugen können.

Bei den neueren objektorientierten Programmiersprachen, muss man die Eigenschaften von Objekten definieren. Für die neuen Prozessoren mit mehreren Prozessorkernen und der 64-Bit-Technik sind auch neue Programmiertechniken erforderlich, mit denen eine echte Parallelverarbeitung mehrerer Aufgaben programmiert werden kann. Mit einem einzigen Prozessor wurde bisher nur eine Parallelverarbeitung (Multitasking) nachgebildet, indem viele Aufgaben stückweise abwechselnd hintereinander ausgeführt wurden.

Zusammen mit der Internetentwicklung wurden neue Programmiersprachen verwirklicht. Momentan (2011) sind die zahlreichen Sprachkonstrukte kaum zu überblicken. Für spezielle Zwecke gibt es domänenspezifische (DSL = domain-specific language) Sprachen, Skriptsprachen und dynamische Programmiersprachen. Wird der Programmablauf vom PC ins Internet verlagert, müssen die Programmierer das Cloud-Computing beherrschen, weil der PC vor Ort eigentlich nur ein Client (Ein- und Ausgabegerät mit Tastatur, Maus und Bildschirm) ist, der nur einen Browser hat, aber die Programme weder ausführt noch den Speicherplatz für Daten und Programme besitzt. Alles läuft im Internet wie in einer großen Wolke ab (engl.: cloud, Wolke).

Die Programmierlogik dieser neuen Sprachen wird hier nicht behandelt, weil immer eine Programmierumgebung (Entwicklungssystem, spezielle Entwicklungswerkzeuge: SDK = software development kit) dazugehört, die mit beschrieben werden müsste. Diese Sprachen sind dadurch gekennzeichnet, dass sie Visual-Umgebungen (Bildschirmfenster) schon während der Programmerstellung erfordern, während die alten Programmiersprachen mit einem zeilenorientierten Bildschirm (Betriebssysteme DOS, UNIX) und einer Tastatur auskommen.

Syntax und Semantik

Bei allen prozeduralen Programmiersprachen ist von grundlegender Bedeutung, dass man die Syntax und die Semantik kennt und genau einhält.

Voraussetzungen zum Programmieren

Man muss ...
1. ... sein Fachgebiet beherrschen, für das man Programme schreiben will.
2. ... die Grundlagen der Programmierlogik beherrschen.
3. ... die Programmiersprache richtig anwenden.
4. ... das Programm auf dem Zielsystem installieren und zum Laufen bringen.

Nur wenn alle vier Voraussetzungen bei einem "Programmierer" vorhanden sind, kann man erwarten, dass die Programme auch korrekt funktionieren werden. Über die ersten drei Voraussetzungen berichtet dieser Beitrag. Den letzten Punkt muss der Programmierer zusammen mit den Systemhandbüchern lösen.

"Programmierer" ist kein eigener Beruf, sondern nur eine Zusatzqualifikation zu einer schon vorhandenen fachlichen Qualifikation (Beruf, Spezialfach, Fachwissen).

Schlüsselwörter

Programmcode in Englisch!

Da Programme international austauschbar sein sollen, hat man sich weltweit darauf geeinigt, dass die Sprachelemente einer Programmiersprache aus dem englischen Wortschatz stammen sollen.

Namen für Programmbefehle und für Elemente der Syntax sind reservierte Wörter bzw. reservierte Namen aus dem englischen Wortschatz. Sie werden Schlüsselwörter (engl.: key words oder keys) genannt und haben in der Programmiersprache eine feste Bedeutung. Diese Schlüsselwörter dürfen nicht als Variablennamen oder in anderer Bedeutung innerhalb des Programms verwendet werden.

Deshalb ist der Wunsch mancher Anwender unsinnig, bei programmierbaren Taschenrechnern deutsche Schlüsselwörter zu verlangen. Die Programme wären dann nicht weltweit einsetzbar, weil andere Taschenrechner die deutschen Befehle nicht verstünden.

Da jeder bereits in der Schule Englisch gelernt hat, dürfte diese Sprache kein Problem für jemanden sein, der das Programmieren lernen will.

Dialog und Ergebnisse in Deutsch!

Obwohl die Programmbefehle und die Schlüsselwörter in Englisch geschrieben werden müssen, kann ein Programm so gestaltet werden, dass der gesamte Dialog zwischen Benutzer und Programm in Deutsch erfolgen kann. Eingabeaufforderungen und Ergebnisausgaben können von Programmierer mit deutschen Texten gestaltet werden. Der Benutzer des Programms merkt nichts davon, dass der Quellcode mit englischen Schlüsselwörtern programmiert werden musste.

Deklarationen

Am Anfang eines Programms muss man dem Computer Regeln vorgeben. Man muss ihm sagen, wie er die Inhalte der Speicherzellen behandeln soll. Der Inhalt einer Speicherzelle kann ein Programmbefehl, eine Zahl, ein Buchstabe, eine Benennung, eine Speicheradresse oder ein Zeiger sein. Außerdem muss man dem Computer sagen, wie er mit der Außenwelt in Verbindung treten soll. Da man mit dem Computer noch nicht reden kann, muss dies durch Eingabe von Zeichen und Zeichenfolgen über die Tastatur oder durch Einlesen von einem Datenträger oder einer Datenleitung erfolgen.

Die ersten Computer wurden noch direkt programmiert. Es gab noch keine Programmiersprachen. Der Mensch gab die Nummer der Speicherzelle über ein Schalterfeld an und musste sich merken, in welcher Speicherzelle welcher Wert gespeichert war. Das war sehr mühsam. Deshalb wurden symbolische Programmiersprachen entwickelt.

Anstelle der Speicherzellennummern (Speicheradressen) wurden Namen (engl.: identifier) verwendet. Der Compiler setzt die Namen in die entsprechenden Speicheradressen um und legt die Speicherzuordnung fest. Namen sind lediglich "Bezeichner", die aber eindeutig sein müssen. Der Programmierer kann sie frei wählen.

Beispiel:

Der eine Programmierer bezeichnet z.B. die Länge und Breite eines Rechtecks mit a und b, der andere verwendet dafür L und B und ein dritter nimmt die ausgeschriebenen Namen Laenge und Breite. Dem Computer ist dies egal. Er muss nur wissen, was er damit machen muss. In diesem Fall muss er die Werte dieser beiden so bezeichneten Speicherstellen multiplizieren und das Ergebnis in eine dritte Speicherstelle schreiben, die c, oder F, oder Flaeche (oder ganz anders, z.B. G23b56) heißen kann.

Wenn die Variablennamen einen Bezug zum Inhalt der Variablen haben, wie z.B. Laenge und Breite, so sind dies "sprechende Namen", weil sie auf die Bedeutung der Inhalte schließen lassen. Man könnte für Länge und Breite auch die Namen Gurke und Salat verwenden und den Flächeninhalt dann mit Gurkensalat bezeichnen. Diese Namen hätten aber dann keinen Bezug mehr zum tatsächlichen Inhalt und das Programm wäre für den Menschen "schwer lesbar".

Zur besseren Lesbarkeit von Programmen (Quelltexten) durch den Menschen sollten stets "sprechende Namen" verwendet werden. Auch genormte Formelzeichen können verwendet werden.

Für den Computer ist es unerheblich, wie die Namen lauten, sie müssen nur eindeutig sein.

Beispiel:

Bei E = m * c2 weiß jeder, was gemeint ist. (Das Sternchen * wird in Programmiersprachen meist als Multiplikationszeichen verwendet.)
Nimmt man aber andere Namen und schreibt Emil = Katze * Maus2,
dann weiß kein Mensch, was gemeint ist.

Für die Schreibweise der Namen muss eine Namenskonvention eingehalten werden, die von der jeweiligen Programmiersprache abhängt. So darf ein Name nicht mit einer Ziffer beginnen. Der Name 5NE6 ist nicht zulässig, während N5E6 ein zulässiger Name ist. Die Länge des Namens ist meist auf 8, 16, 32 oder auch 255 Zeichen beschränkt. Der zulässige Zeichensatz ist in der Sprachbeschreibung der Programmiersprache festgelegt. Der Zeichensatz enthält meist nicht alle Sonderzeichen. So fehlen meist die nationalen Zeichen, wie z.B. die deutschen Umlaute oder griechische Buchstaben, die man mit ae oe ue oder PI, LAMBDA umschreibt..

Durch Deklarationen muss dem Computer gesagt werden, wie er die Namen und die Werte im Speicher zuordnen muss. Der Datentyp und die Dimension müssen festgelegt werden. Es muss festgelegt sein, ob der gespeicherte Wert eine ganze Zahl (integer), eine reelle Zahl (real), eine komplexe Zahl (complex), ein binärer Wert (binary), ein logischer Wert (logical), ein Zahlenfeld mit einer bestimmten Dimension (array), ein Text bestimmter Länge (string), eine interne Datei (file) oder ein zusammengesetztes Objekt (object) sein soll. Diese Datenypen haben unterschiedlichen Speicherbedarf je nach Dimension oder Länge. Den Datentypen sind bestimmte Regeln und Variablengrößen (engl.: size) zugeordnet, die der Compiler kennt und bei der Berechnung beachtet. In neueren Programmiersprachen gibt es zusätzlich noch benutzerdefinierte Datentypen, die der Programmierer nach Wunsch selbst festlegen kann.

Hat man Dimensionen, Datentypen und Namen, dann kann man die Speicherbereiche festlegen, wo die Werte gespeichert werden. Eine Konstante ist bestimmt durch Datentyp und Name und enthält einen festen Wert, der sich für dieses Programm nie ändert. Deshalb baut der Compiler diesen Wert fest in den Programmcode ein. Man muss nur vorher den Datentyp (z.B. real) und den Namen (z.B. PI) für die Konstante (z.B. mit const real PI = 3.14159265359) festlegen.

Eine Variable ist ebenfalls bestimmt durch Datentyp und Name (z.B. var real Laenge) und enthält einen Wert, der sich während des Programmablaufs ändern kann. Der Compiler weist der Variablen entsprechend dem Datentyp einen Speicherbereich zu.

Variablen enthalten bei Programmstart irgendeinen unbestimmten Wert, der in der zugeordneten Speicherstelle zufällig vorhanden ist. Deshalb sollte der Programmierer einen definierten Anfangswert vorgeben (Initialisierung der Variablen). Wenn man die Variablen ohne vorherige Initialisierung verwendet, kann es Fehler im Berechnungsergebnis geben, weil der ursprünglich gespeicherte (zufällige) Wert verwendet wird.

Der Programmierer kann für Konstanten und Variablen festlegen, ob sie auch in den Unterprogrammen gelten sollen. Dann werden sie in einem gemeinsamen Speicherbereich (common) gespeichert.

Bevor das Computerprogramm die Eingabewerte von der Außenwelt übernehmen kann oder Ergebnisse ausgeben kann, muss man die Ein- und Ausgabekanäle festlegen. Das sind Speicheradressen, die mit einem Gerät (engl.: device code) oder einer Schnittstelle (engl.: port number) verbunden sind. Dieser Teil des Programms ist sehr stark abhängig vom verwendeten Computerfabrikat (hardware-abhängig) und vom angeschlossenen Gerät, dessen Möglichkeiten meist über ein vom Gerätehersteller mitgeliefertes Unterprogramm (Geräte-Treiber) zugänglich gemacht werden.

Bei manchen Computern muss man noch den Modus deklarieren, wie Winkel oder Fehlerrückmeldungen zu behandeln sind.

Winkel werden bei programmierbaren wissenschaftlichen Taschenrechnern entweder in Grad (°), Gon (g) oder im Bogenmaß Radiant (rad) verarbeitet. Die Einstellung erfolgt über bestimmte Flags oder Modus-Masken. Bei höheren Programmiersprachen wird meist nur Radiant verwendet. Der Programmierer muss dann selber in Grad oder Gon umrechnen.

Fehlerrückmeldungen erfolgen meist durch Ausgabe von Fehlernummern, die man je nach Einstellung des Fehlermodus auch im Klartext angezeigt bekommen kann. Fängt der Programmierer diese Fehler nicht durch entsprechende Fehlerroutinen ab, dann bricht das Programm bei einem Fehler mit einer Fehlermeldung ab. Bei längeren Programmen ist die Fehlerbehandlung innerhalb des Programmes für die Benutzerfreundlichkeit von großer Bedeutung. Man kann zwar kein Programm idiotensicher machen, aber man sollte Fehler, die jedem passieren können (Eingabefehler), durch entsprechende Fehlerroutinen abfangen.

Anweisungen

Anweisungen sind Befehle des Programmierers an das Programm, etwas zu tun.

Die oben angegebenen Deklarationen sind nicht-ausführbare Anweisungen. Sie sagen dem Compiler, wie er die Vorgaben umsetzen soll. Das Programm ist entsprechend diesen Anweisungen kompiliert und erzeugt worden. Im lauffähigen Programm selbst sind diese Deklarationen nicht als Anweisungen vorhanden.

Ein- und Ausgabeanweisungen sind ausführbar, das heißt das Programm muss sie entsprechend den programmierten Vorgaben ausführen.

Die Anweisung "Hole den Wert von der Tastatur und speichere ihn in der Variablen a" lautet z. B. in der Programmiersprache FORTRAN: READ(1) a.
Für den Computer heißt das: "Lese von Eingabekanal 1 und schreibe den Wert in a". Nach Ausführung dieser Anweisung enthält a den eingegebenen Wert. Der Eingabekanal 1 (= Tastatur) muss im Quelltext durch eine OPEN-Anweisung zugeordnet worden sein oder ist für die Programmiersprache allgemein festgelegt (voreingestellt, engl.: default)

Die Anweisung, den Wert aus a auf den Bildschirm zu schreiben, lautet: WRITE(2) a, wobei Ausgabekanal 2 = Bildschirm ist.

Wenn Ausgabekanal 5 z.B. dem Druckeranschluss zugeordnet ist, kann man schreiben: WRITE(5) a, dann wird der Wert ausgedruckt. Wenn Ausgabekanal 6 vorher durch eine OPEN-Anweisung einem Dateinamen zugeordnet worden ist, bewirkt die Anweisung WRITE(6) a, dass der Wert a in eine Datei mit dem betreffenden Namen geschrieben wird.

Die Kanalnummern (engl.: unit number oder unit specification) können beliebig gewählt werden.

Beispiel:

Wenn aus einer Datei (z.B. Eingabekanal = 51) gelesen werden soll und das Ergebnis in eine andere Datei (z.B. Ausgabekanal = 52) geschrieben werden soll, dann ordnet man mit jeweils einer OPEN-Anweisung den betreffenden Dateinamen einem Kanal zu. Dann liest man z.B. für eine Koordinatentransformation mit READ(51) r,phi,rho drei Zahlen aus der Eingabedatei und schreibt die daraus transformierten Koordinatenwerte der Variablen x, y und z mit WRITE(52) x,y,z in die Ausgabedatei.

Beide Dateien sind während der Berechnung "geöffnet", die Kanäle 51 und 52 sind aktiv, die Dateien sind für die Dauer dieser Zuordnung für andere Programme gesperrt. Sind die Aktionen abgeschlossen, dann schließt das Programm die Dateien mit CLOSE(51) und CLOSE(52) wieder und gibt sie damit für andere Programme frei.

In höheren Programmiersprachen muss bei Ein- und Ausgabe von Werten das Format angegeben werden, weil die Werte Texte oder Zahlen sein können, für die man eine bestimmte Darstellungsart vorgeben muss. Also sagt man dem Computer in der Anweisung noch, was es ist (Zahl oder Text) und wie man bei Ausgaben das Ergebnis sehen will.

Man fügt den Ein- und Ausgabeanweisungen sogenannte Formatanweisungen hinzu.

Beispiele (FORTRAN):

Bei vielen höheren Programmiersprachen ist bei Eingabeanweisungen eine automatische Typerkennung eingebaut. Das Programm erkennt den Typ des eingegebenen Objekts automatisch und wandelt ihn selbständig in den passenden Speichertyp um. Dann können die Formatanweisungen für den Eingabekanal weggelassen werden.

Bei der Ausgabe sollte der Programmierer aber das Ausgabeformat angeben, sonst wählt das Programm die interne Darstellung als Ausgabeformat.

Beispiel:

Eine reelle Zahl 1234.56 müsste mit Formatanweisung "F6.2" ausgegeben werden, wenn man sie in der gewohnten Weise darstellen will, sonst schreibt der Computer 0.123456E+4 (interne Darstellung ist halblogarithmisch).

Formatanweisungen benutzt man hauptsächlich bei der Ausgabe von Werten für die Formatierung des Textes. Zeilenvorschübe, Leerzeilen, Einrückungen, Tabulatoren und andere Attribute können in Formatanweisungen gesetzt werden. Das Programm steuert die Ausgabe in eine Datei oder auf den Drucker entsprechend diesen Vorgaben. Der Programmierer muss diese Formatanweisungen richtig einsetzen, sonst ist die Ausgabe nicht wunschgemäß.

Bei Taschenrechnern wird das Format meist durch Flags (Nachkommastellen, Winkelformat, Zeitformat, Zahlentyp, Formeldarstellung, Dezimalkomma oder Dezimalpunkt) oder Textattribute (Font, Leerzeichen, Zeilenvorschub) in der Eingabeanweisung (INPUT, INFORM) oder Ausgabeanweisung (DISP, MSGBOX) vorgegeben.

Man kann aber die Daten auch binär (Binärformat, Maschinenformat) ohne Formatanweisungen einlesen oder ausgeben, so dass die Ergebnisse wieder nur von Computern gelesen werden können. Solche Lese- und Schreibvorgänge erfolgen meist bei Magnetbändern. Weil beim Binärformat die Formatumwandlungen wegfallen, wird es für schnelle Übertragungen verwendet.

Ausdrücke

Ein Ausdruck (engl.: expression) ist die symbolische Formulierung einer mathematischen oder logischen Anweisung. Ein Ausdruck steht meist auf der rechten Seite einer Gleichung.

Beispiel:

c a2 + d ⋅ b2 ist ein solcher Ausdruck,
der im Programm so geschrieben wird: c*a^2+d*b^2

Hier wird das Sternchen (*) (engl.: asterix) als Multiplikationszeichen verwendet, weil der Multiplikationspunkt und das Multiplikationskreuz (×) im Zeichensatz meist nicht vorhanden sind.

Ebenso wird die Potenzierung im Ausdruck c ⋅ a2 + d ⋅ b2 meist als c*a^2+d*b^2 oder, wenn das Zeichen "^" nicht verfügbar ist, auch mit Doppelsternchen als c*a**2+d*b**2 geschrieben.

Die Anweisung A = c*a**2+d*b**2 sagt dem Computer, den Ausdruck rechts vom Gleichheitszeichen auszuwerten (zu evaluieren) und den berechneten Wert in die Variable A zu schreiben.

In Programmen dürfen Multiplikationszeichen nicht weggelassen werden.

Beispiel:

Der mathematische Ausdruck c⋅a2 + d⋅b2 ist auf dem Papier als mathematische Formel ca2 + db2 mit den Variablen a, b, c und d eindeutig. Der Compiler betrachtet aber ca und db im Ausdruck ca**2+db**2 als eigene Variablennamen und wird Fehlermeldungen oder zumindest Warnungen ausgeben, weil diese Variablennamen nicht deklariert sind.

Schwieriger wird es, wenn die Variablen ca und db neben den Variablen a, b, c und d innerhalb des Programms tatsächlich existieren. Dann wundert man sich über die falschen Ergebnisse, weil nicht c*a**2+d*b**2, sondern ca**2 + db**2 berechnet wurde. Wir erinnern uns: Variablennamen sind Bezeichner und bestehen meist aus mehreren Zeichen.

Bei Taschenrechnerprogrammen werden keine derartigen Fehler gemeldet, weil es dort Deklarationen im Sinne einer höheren Programmiersprache nicht gibt. Der Taschenrechner erkennt alles als Namen an, was der Namenskonvention entspricht. Den Typ einer Variablen entnimmt der Taschenrechner dem gespeicherten Inhalt. Wenn in a eine reelle Zahl gespeichert ist, dann ist die Variable a vom Typ real, wird anschließend dort Text gespeichert, ist sie vom Typ string. Der Typ hängt also vom momentanen Inhalt ab.

Operatoren

Mathematische Operatoren

Die Zeichen "+", "-", "*" und "/" sind mathematische Operatoren der vier Grundrechenarten. Dazu kommen noch andere Operatoren, z.B. für Potenzierung "**" und für Mengenoperationen. Darauf wird hier nicht weiter eingegangen.

Wertzuweisungen

Soll in der Variablen a (wenn sie als integer deklariert wurde) die ganze Zahl 123456 gespeichert werden,
dann schreibt der Programmierer: a = 123456.

"=" ist der Zuweisungsoperator. In manchen Programmiersprachen wird auch ":=" dafür verwendet.

Beispiele:

a = b heißt: In der Variablen a wird der Wert von b gespeichert.

a = a + 1 heißt: Erhöhe den Wert der Variablen a um 1 und speichere das Ergebnis wieder in der Variablen a.
Hinweis: Diese Schreibweise ist, rein mathematisch gesehen, Unsinn, aber hier ist es keine Gleichung, sondern eine Zuweisung.

S = a + b + c + d. Hier wird die Summe der Werte aus den vier Variablen a, b, c und d der Variablen S zugewiesen.

Vergleichsoperatoren und logische Operatoren

Um Bedingungen für Verzweigungen und Schleifen programmieren zu können, müssen Vergleichsoperatoren und logische Operatoren festgelegt sein. Die Schreibweise hängt vom Zeichensatz der jeweiligen Programmiersprache ab. Sonderzeichen für Operatoren sind nicht immer verfügbar.

Die Tabelle zeigt die wichtigsten Operatoren.

Bedeutung Operator Operator (Schreibweise in FORTRAN)
Vergleichsoperatoren:
"größer als" > .gt. oder .GT. (greater than)
"kleiner als" < .lt. oder .LT. (less than)
"größer als" oder "gleich" >= .ge. oder .GE. (greater than or equal)
"kleiner als" oder "gleich" <= .le. oder .LE. (less than or equal)
"ungleich" <> .ne. oder .NE. (not equal)
"gleich" = = .eq. oder .EQ. (equal)
Logische Operatoren:
logisch "ODER" \/ oder OR .or. oder .OR.
logisch "UND" /\ oder AND .and. oder .AND.
logisch "NICHT" NOT .not. oder .NOT.
logisch "XOR" XOR .xor. (exclusive or) oder .XOR.

Die Operatoren erfordern meist zwei Argumente, das heißt, sie stehen zwischen zwei Ausdrücken, Variablen oder Konstanten. NOT steht vor einem logischen Ausdruck bzw. vor einer logischen Variablen.

Wenn der Programmierer die logischen Operatoren ODER, UND, NICHT und XOR verwendet, sollte er die zweiwertige Logik (Boolesche Algebra) beherrschen, damit die Bedingungen eindeutig formuliert werden.

Beispiel:

NOT (a \/ b) ist gleichbedeutend mit (NOT a) /\ (NOT b), wobei a und b als Typ logical deklariert sein müssen.

Programmsteuerung (Kontrollstrukturen)

Verzweigungen

Programme ohne Verzweigungen kommen kaum vor. Meist werden Bedingungen formuliert, die beim Programmlauf geprüft werden. Treffen die Bedingungen zu, wird entsprechend verzweigt oder wiederholt.

Beispiel:

Umgangssprachliche Formulierung der Verzweigung für ein Programm:
"Wenn das Wetter schön ist, gehen wir spazieren, andernfalls bleiben wir zuhause".

Formulierung in einer Programmiersprache:
IF (WETTER = = "schön")
THEN (SPAZIERENGEHEN)
ELSE (ZUHAUSEBLEIBEN)
END

IF, THEN, ELSE und END sind Schlüsselwörter, die dem Computer eine Verzweigung anzeigen. Nach dem Wort IF kommt die Bedingung, die er auf den Wahrheitsgehalt überprüfen muss. Hinter jeder Bedingung muss man sich ein Fragezeichen denken.
WETTER = = "schön"? heißt die Frage. Der Operator "= =" prüft auf Gleichheit (das einfache Gleichheitszeichen ist bereits als Zuweisungsoperator vergeben, deshalb wird es beim Vergleichsoperator doppelt geschrieben).

Dazu muss vorher in der Variablen WETTER ein Wert gespeichert worden sein, der entweder "schön" oder irgendwie anders lautet. Durch Vergleich des Inhalts der Variablen und dem angegebenen Wert stellt der Computer fest, ob die Bedingung erfüllt ist oder nicht.

Ist in der Variablen WETTER der Wert "schön" gespeichert, dann ist die Auswertung der Bedingung "wahr" (die Frage wird mit "ja" beantwortet) und der Computer führt die Aktion im THEN-Zweig aus, die da lautet: SPAZIERENGEHEN. Dies sei eine Funktion, die z.B. den Text "Auf geht's, anziehen und Haus verlassen!" ausgeben könnte.

Steht in der Variablen WETTER aber ein anderer Inhalt, dann ist die Auswertung der Bedingung "unwahr" und der Computer führt die Aktion ZUHAUSEBLEIBEN im ELSE-Zweig aus. Auf dem Bildschirm erscheint dann z.B. "Zuhause bleiben". END sagt dem Computer, dass die Formulierung der Verzweigung hier aufhört.

Verzweigungen bei Fallunterscheidungen programmiert man meist mit CASE, wo mehrere verschiedene Bedingungen abgefragt werden und dann entsprechend verzweigt wird. Die Syntax für CASE ist in den verschiedenen Programmiersprachen unterschiedlich.

Schleifen

Auch Schleifen werden mit Bedingungen programmiert. Für Schleifen gibt es viele Syntax-Möglichkeiten.

Eine Schleife kann ausgeführt werden, solange eine Bedingung erfüllt ist (WHILE) oder bis eine Bedingung zum ersten Mal erfüllt ist (UNTIL). Man kann auch von Anfang an sagen, dass eine Schleife n-mal durchlaufen werden muss. Diese Wiederholungen werden mit DO oder FOR eingeleitet.

Sprünge (GOTO)

Die einfachste Art eine Verzweigung durchzuführen oder eine Schleife zu programmieren, wird mit dem GOTO-Befehl ("go to" = Sprung zu einer Adresse) realisiert. Man markiert eine Stelle im Programm mit einem Label (Zahl oder Namen), wo das Programm weiterlaufen soll und springt mit GOTO dort hin.

Beispiel:

In einem Programm-Quelltext steht die Zeile:
IF a > b THEN GOTO 123 ELSE GOTO 012 END

Die Labels 123 und 012 müssen in diesem Programm existieren, sonst meldet bereits der Compiler "Missing label 123" oder "Missing label 012".

GOTO-Befehle gibt's bei einfacheren Programmiersprachen, bei denen keine komplizierten Verzweigungsstrukturen zweckmäßig oder möglich sind (z. B. BASIC).

GOTOs sollten möglichst vermieden werden, weil sie jede Programmstruktur stören und zum unbeliebten "Spaghetti-Code" führen. Moderne höhere Programmiersprachen und auch programmierbare wissenschaftliche Taschenrechner kommen ganz ohne GOTOs aus.

Funktionen, Unterprogramme

Funktionen sind Unterprogramme, die nur einen einzigen Wert als Ergebnis liefern: den Funktionswert.

Bei den meisten höheren Programmiersprachen werden die Standardfunktionen (engl.: intrinsic functions) als Standardbibliothek mitgeliefert. Diese können vom Programmierer wie Konstanten in Ausdrücken verwendet werden. Dem Compiler sind diese Funktionen bekannt.

Nachfolgend eine Aufzählung einiger wichtiger Standardfunktionen. Die Namen der Funktionen können bei verschiedenen Programmiersprachen unterschiedlich sein. Die Klammern hinter dem Funktionsnamen weisen darauf hin, dass beim Aufruf Argumente (Parameter) in diesen Klammern mitgegeben werden müssen.

Mathematische Funktionen:

Quadratwurzel SQRT( ) oder ROOT( ),
dekadischer Logarithmus LOG10( ),
natürlicher Logarithmus LOG( ) oder LN( ),
trigonometrische Funktionen SIN( ), COS( ) und TAN( ) und
ihre Umkehrfunktionen ASIN( ), ACOS( ) und ATAN( ),
ex-Funktion EXP( ),
Absolutwert ABS( ),
Negativwert NEG( ),
Ganzzahlwert INT( ),
Nachkommawert FRAC( ),
Vorzeichenfeststellung SIGN( ),
Modulo-Funktion MOD( ),
.....

Logische Funktionen:

AND( ), OR( ), NOT( ) und XOR( ) (nicht zu verwechseln mit den logischen Operatoren!),

Funktionen für Bit-Manipulationen:

SHIFT( ), ROTATE( ), SWAP( ).

Außer den oben genannten Funktionen gibt es noch Funktionen für andere Zwecke (z.B. Stringbearbeitung, Zeitfunktionen, Dateifunktionen), die hier aber nicht aufgezählt werden, weil jede Programmiersprache ihre eigenen Sonderfunktionen anbietet.

Verwendung der Funktionen

Funktionen können wie Konstanten in Ausdrücken verwendet werden. Der einzige Unterschied ist, dass bei Funktionen Argumente in der Funktionsklammer mitgegeben werden müssen. Der Computer betrachtet den Inhalt der Funktionsklammer als einen mathematischen Ausdruck, den er zuerst berechnet, bevor er die Funktion aufruft.

Beispiel:

Soll der Sinus von 30° und der Cosinus von 75° addiert und in Z gespeichert werden, dann müssen die Winkel vorher von Grad in Radiant umgerechnet werden. Das kann in der Funktionsklammer beim Aufruf erfolgen.

Z = SIN(30*PI/180) + COS(75*PI/180)

Der Wert des Arguments kann auch in einer Variablen gespeichert sein.

Beispiel:

Wenn man Vielfache und Teile eines Winkels als Argument verwenden will, wird dieser Winkel zuerst in RAD umgerechnet und in der Variablen ALPHA gespeichert.

Für Winkel 30°:
ALPHA = 30*PI/180
Z = SIN(3*ALPHA) * SIN(ALPHA/5) + COS(2*ALPHA/3) * COS(ALPHA/10)

Benutzerdefinierte Funktionen und Unterprogramme

Der Programmierer kann auch selbst Funktionsunterprogramme schreiben und wie Standardfunktionen verwenden. Funktionsnamen sind frei wählbar, wenn man die reservierten Namen meidet.

Beispiel:

Wenn man immer wieder die Berechnung der Hypotenuse eines rechtwinkligen Dreiecks braucht, dann deklariert man eine Funktion (nach Pythagoras):
HYP(a,b) = SQRT(a**2+b**2)
und gibt beim Aufruf die Werte für die Katheten a und b als Wert oder Ausdruck mit.
Die Wertzuweisung c = HYP(3,4) liefert dann den Wert c = 5.

Wenn man aber nicht nur einen einzigen Funktionswert haben will, sondern aus den Parametern mehrere Werte ermittelt werden sollen, dann muss man ein Unterprogramm (engl.: subroutine) schreiben.

Ein Unterprogramm darf nicht wie eine Konstante in einem Ausdruck verwendet werden, weil es mehrere Werte liefert. Der Aufruf erfolgt mit dem Befehl CALL. Die mitgegebenen Parameter sind Variablen, die innerhalb des Unterprogramms deklariert sein müssen. Man unterscheidet zwischen Eingabe- und Ausgabeparametern.

Die Eingabeparameter enthalten beim Aufruf die Werte, die das Unterprogramm verarbeiten soll. Die Ausgabeparameter sind Variablennamen des aufrufenden Hauptprogramms, in die das Unterprogramm die Ergebnisse schreiben soll. Die Reihenfolge der Parameter ist im Unterprogramm festgelegt und damit für den Aufruf bindend.

Beispiel (mit Aufgabe):

Ein Unterprogramm

DREIECK(a,b,c,alpha,beta,gamma,Flaeche,Umfang)

berechnet aus den drei Dreieckseiten a,b und c die drei Eckwinkel in Grad (°), sowie Fläche und Umfang des Dreiecks. a, b und c sind die Eingabeparameter, alpha, beta, gamma, Flaeche und Umfang sind die Ausgabeparameter.

Nach dem Aufruf von
CALL DREIECK(4,6,8,alpha,beta,gamma,Flaeche,Umfang) stehen in den Variablen (vom Typ real) des aufrufenden Hauptprogramms folgende Werte, wobei die Winkel bereits in Grad (°) umgerechnet sind:
alpha = 28.955, beta = 46.567, gamma = 104.478,
Flaeche = 11.619, Umfang = 18.000.

Da es beim Aufruf nur auf die Reihenfolge der Parameter ankommt, kann der Aufruf auch mit
CALL DREIECK(4,6,8,a1,a2,a3,F,U) erfolgen. Das Ergebnis ist dann dasselbe, nur die Variablen, in die das Ergebnis geschrieben wird, haben andere (nicht "sprechende") Namen:
a1 = 28.955, a2 = 46.567, a3 = 104.478,
F = 11.619, U = 18.000.

Vertauscht man beim Aufruf die Variablennamen, dann steht das richtige Ergebnis in den falschen Variablen. Die Fläche steht (hier in diesem Beispiel) immer in der vorletzten und der Umfang in der letzten Variablen der Parameterklammer.

Aufgabe für den Leser:

Welche Werte stehen nach Aufruf von
CALL DREIECK(3,4,5,z1,z2,z3,z4,z5)

in den Variablen z1 bis z5 des aufrufenden Hauptprogrammes? Um die Aufgabe nicht zu leicht zu machen, wurden hier keine "sprechenden Namen" für die Variablen verwendet.

Der Leser weiß inzwischen, wie Unterprogramme funktionieren und kann die Werte selbst ausrechnen und die Variableninhalte richtig deuten.

Schlusswort

Diese wenigen Hinweise mögen genügen, um dem Anfänger einen Eindruck zu vermitteln, worauf es beim Programmieren ankommt.

Über Programmieren, Programmiersprachen und Programmierlogik gäbe es noch viel mehr zu sagen. Insbesondere die neuen Programmiersprachen und -methoden weichen zum Teil erheblich von den oben beschriebenen Prinzipien ab. Darauf kann im Rahmen dieses Beitrags nicht eingegangen werden.

Um das gründliche Studium der Sprachbeschreibung und das Lernen der Syntax und Semantik einer Programmiersprache wird der angehende Programmierer nicht herumkommen.

Auch hier gilt: Je besser man eine (Programmier-)Sprache beherrscht, desto besser wird man (vom Computer) verstanden.

Dann ist da noch das Problem, den Quellcode mit den Entwicklungswerkzeugen (z.B. Assembler, Compiler) des betreffenden Computersystems zu übersetzen, die System- und Funktionsbibliotheken (Runtime-Libraries, DLLs) mit den Bindeprogrammen (Binder, Linker) dazuzubinden, das Programm zu installieren und in der vorgesehenen Systemumgebung (z.B. MSDOS, Windows, Unix) zum Laufen zu bringen. Aber dieses Problem muss man mit den hoffentlich guten Handbüchern lösen.


© 2017 Otto Praxl. Alle Rechte vorbehalten.

Zur Startseite