BASIC-Kurs: "Von Adam und Eva..." (Teil 4)
Hiermit möchte ich Sie zum vierten Teil unseres Basickurses herzlichst begrüßen. Diesen Monat werden
wir uns noch ein wenig mit der formatierten Programmierung befassen und werden uns anschließend endlich
den lang versprochenen Schleifenbefehlen zuwenden.
Letzten Monat hatten Sie ja gelernt, wie man, mit
Hilfe von REM und sogenannten " Doppelpunktzeilen" ein
wenig Ordnung in einen Programmtext bringt. Eine
richtige " Programmierung" war das ja noch nicht, zumal die von uns eingefügten Zeilen und Kommentare ja
nichts mit dem eigentlichen Programmablauf zu tun
hatten, und wir sie genausogut auch hätten weglassen
können, wie ich zum Schluß andeutete.
Deshalb kommen wir heute zum GOSUB-Befehl, der in
zusammenhang mit dem RETURN-Befehl uns ungeheuerliche
Weiten zur platzsparenden, einfachen und formatierten
Programmierung öffnet.
GOSUB steht für GO to SUBroutine, was soviel heißt, wie GEHE zu UNTERprogramm, und ist in etwa vergleichbar mit GOTO. Hinter GOSUB wird ebenfalls eine Zeilennummer angegeben, zu der der Computer springen
soll. Bis hierhin tut GOSUB genau dasselbe, was auch
GOTO tut, nämlich ganz einfach zu einer bestimmten
Zeile im Programm springen. Die Programmzeilen, die
dort stehen und folgen werden ganz normal abgearbeitet. Doch nun kommt der Clou: nachdem diese Zeilen
abgearbeitet wurden, können Sie mit dem RETURN-Befehl
wieder an die Stelle im Programm zurückspringen, von
wo der GOSUB-Befehl in das Untersprogramm ( so nennt
sich das nämlich) eingesprungen ist. Dies hat den
Vorteil, daß Sie beliebige Programmsequenzen, die Sie
innerhalb eines Programms benötigen, beliebig oft
benutzen können, aber nur EINMAL schreiben müssen.
Der Computer merkt sich jedesmal die Stelle, von welcher Sie in das Unterprogramm eingesprungen sind, und
wird jedesmal auch wieder dorthin zurückkehren. In
der Praxis sieht das so aus:
5 REM ***************** 6 REM * hauptprogramm * 7 REM ***************** 8 : 10 GOSUB 200 20 PRINT"Hallo Leute..." 30 GOSUB 200 40 PRINT"Unn weils so schön war, grad nochmal..."; 50 GOSUB 200 60 END 90 : 195 REM ************ 196 REM * demotext * 197 REM ************ 198 : 200 PRINT 205 PRINT"Das ist ein Text, der hier zur Demon-" 210 PRINT"stration insgesamt 3 Mal ausgedruckt" 220 PRINT"wird." 230 PRINT 240 RETURN
Genau so sollte ein gut formatiertes Programm übrigens aussehen. Vor jedem Modul (= Programmabschnitt, das hatten wir letzten Monat ja schon einmal. . .) steht ein unübersehbarer Kommentar. Zuerst haben wir
das " HAUPTPROGAMM" . Der Programmteil also, der am
Anfang auch mit RUN gestartet wird, und der alle
benötigten Unterprogramme, so wie zum Beispiel das
Programm " DEMOTEXT", zu dem Zeitpunkt aufruft, zu dem
sie benötigt werden.
Schauen wir uns doch einmal unser Programm ein wenig
näher an. Gleich am Anfang, in Zeile 10, wird unser
kleines Unterprogramm schon beansprucht und aufgerufen. Dann wird in Zeile 20 der Text " Hallo Leute. . ." ausgegeben. Anschließend kommt wieder das Unterprogramm dran. Dann kommt etwas aus dem Hauptprogramm, nämlich der Text " Unn weils so schoen war, grad nochmal. . ." . Schließlich und endlich wird DEMOTEXT noch
ein letztes Mal aufgerufen und das Hauptprogramm mit
END beendet. Der Ausdruck, den Sie somit erhalten, sieht im Endeffekt dann so aus:
Das ist ein Text, der hier zur Demon- stration insgesamt 3 Mal ausgedruckt wird.
Hallo Leute. . .
Das ist ein Text, der hier zur Demon- stration insgesamt 3 Mal ausgedruckt wird.
Unn weils so schoen war, grad nochmal. . .
Das ist ein Text, der hier zur Demon- stration insgesamt 3 Mal ausgedruckt wird.
Sie sehen, obwohl Sie den Text, der hier, wie so oft
angezeigt," insgesamt 3 Mal ausgedruckt wird", nur
einmal eingegeben haben, erscheint er tatsächlich
drei Mal auf dem Bildschirm. Sie haben sich also ersteinmal ein wenig Tipparbeit gespart, und dann auch
noch Speicherplatz, da drei mal mehr Platz verbraucht worden wäre, hätten Sie jedesmal unseren Text nochmal
eingegeben. Außerdem sieht unser Programm so jetzt
schön sauber und ordentlich aus - Unterprogramm schön
vom Hauptprogramm getrennt. . .
Und es gibt da noch einen kleinen Vorteil: angenommen, Sie sind gerade dabei ein Programm zu schreiben, zu dem Sie ein bestimmtes Unterprogramm benötigen, das eine ganz bestimmte Aufgabe erfüllen soll. Welche
Aufgabe im Einzelnen, sei jetzt einmal dahingestellt.
Dieses Unterprogramm haben Sie vor längerer Zeit allerdings schon einmal in einem anderen Programm benutzt, und haben es dort noch voll funktionsfähig
drin stehen. Das einzigste, was Sie jetzt zu tun haben, ist das Unterprogramm aus Ihrem alten Programm
herauszuisolieren, und es dann in Ihr neues einzubinden. Also ein weiterer Vorteil von Unterprogrammen, da Sie sie jederzeit wiederverwenden können, können
Sie sich Ihre Programme sozusagen aus vielen kleinen
Modulen ( also Unterprogrammen)" zusammenbauen", wie
als wenn Sie mit Bauklötzen einen Turm konstruieren
würden.
Ich muß Ihnen allerdings gestehen, daß dies gar nicht
so einfach ist, wie es sich anhört, da man beim BA-SIC V2 .0 des C64 nicht so einfach riesige Programmabschnitte löschen kann, geschweige denn, daß man einzelne Module so einfach aneinander hängen könnte.
Doch nicht verzagen, in einer der nächsten Ausgaben, wird wahrscheinlich ein kleines Hilfsprogramm hierzu
erscheinen, daß diese Aufgaben bewältigen wird.
Wie oben schon erwähnt, kann man GOSUB auch zum " herumspringen" genauso wie GOTO verwenden, doch möchte
ich Ihnen DRINGENDST davon abraten. Denn wie ebenfalls schon gesagt, merkt sich der GOSUB-Befehl ( im
Gegensatz zu GOTO) eben jene Stelle, von wo aus er in
ein Unterprogramm eingesprungen ist. Da der Computer
allerdings nur einen begrenzten Speicherplatz für
solche Rücksprünge bereithält, kann es Ihnen somit
passieren, daß Ihr Programm irgendwann aus Speichermangel einen Fehler ausspuckt. Benutzen Sie also immer GOTO, wenn Sie " nur" springen möchten. Dies ist
auch ein kleiner Hinweis für Sie, falls Sie mal ein
Programm haben sollten, das nicht so laufen sollte, wie Sie es wünschen. Eine häufige Fehlerquelle ist nämlich auch die Tatsache, daß vergessen wurde, das
Unterprogramm mit RETURN abzuschließen. Sollte nämlich jetzt zufällig wieder der Programmteil folgen, von dem aus das Unterprogramm aufgerufen wurde, dann
wiederholt sich dieser Aufruf solange, bis der Computer abbrechen muß, da sein Merkspeicher " überläuft"( so nennt man das, wenn bei einer internen Operation
der Computer über die Speichergrenze hinaus einen
Zugriff machen muß) . Das soll jetzt natürlich NICHT
heißen, daß Sie ein Unterprogramm nicht wiederum von
einem weiteren Unterprogramm aus aufrufen könnten.
Natürlich geht das, Sie müssen nur jedes Unterprogramm immer wieder ornungsgemäß mit dem RETURN-Befehl
abschließen, um keinen Ärger zu bekommen. Theoretisch
könnten Sie sogar 24 Unterprogramme untereinander
verschachteln, doch werden Sie diese Grenze wohl nie
erreichen. . .
Wollen wir uns nun endlich den Scheifenbefehlen zuwenden. Zuerst einmal, was ist eine Schleife? Wie
Sie sich vielleicht erinnern, hatten wir, beim Abhandeln des GOTO-Befehls eine sogenannte " Endlosschleife" geschrieben. Deshalb Endloschleife, weil ein ganz bestimmter Programmteil immer und immer wieder abgearbeitet wurde, so, daß das Programm endlos lange
weitergelaufen wäre, hätten wir es nicht mit RUN/ STOP
angehalten. Hier nochmals ein solches Programm:
10 PRINT" Das ist eine Endlosschleife. . ." ;
20 GOTO 10
Hier wird der Text " Das ist eine Endlosschleife. . ." also immer wieder ausgegeben, da in Zeile 20 ja immer
wieder zu Zeile 10 verzweigt wird, womit sich unser
Programm also immer wieder selbst aufruft. Klarer
wird es, wenn Sie Zeile 20 wie folgt abändern:
10 PRINT" Das ist eine Endlosschleife. . ." ;
20 RUN
Jetzt startet sich das Programm also immer wieder
selbst, ohne daß es jemals zu einem Ende kommen würde.
Sie müssen allerdings zugeben, daß solche Endlosschleifen, so wie sie hier dargestellt sind zumindest, wenig Sinn ergeben. Es wäre doch viel besser, wenn man eine solche Schleife unter Kontrolle hätte, und sie endlich machen könnte, so also, daß sie nach
eine bestimmten Anzahl von Durchläufen beendet wird.
Zum Einen könnte man das, wenn wir uns auf unser bisheriges Wissen stützen, sehr gut mit der IF-THEN- Klammer lösen. Nämlich so:
5 i=0 10 i=i+1 20 PRINT"DAS IST EIN TEXT" 30 IF i<>5 THEN 10 40 END
Zuerst wird in Zeile 5 die Variable I auf 0 gesetzt.
Anschließend wird diese Laufvariable ( so wollen wir
es einmal nennen), ihres Zeichens eine Floatvariable, um eins erhöht. Dann drucken wir den Text " DAS IST
EIN TEXT" aus. In Zeile 30 vergleichen wir nun, ob I
den Wert 5 enthält. Wenn nicht, dann wird wieder zu
Zeile 10 gesprungen und der Vorgang des Um-Eins-
Erhöhens und des Ausdruckens wiederholt sich. Andernfalls wird das Programm beENDet. Sie sehen, daß diese
Schleife nur 5 Mal durchlaufen werden kann, da sich
nämlich bei jedem Durchlauf die Variable I um eins
erhöht, hat sie nach 5 Durchgängen den Wert 5 tatsächlich erreicht. Also wird die Schleife abgebrochen, und es geht in Zeile 40 weiter im Programm.
Hiermit hätten wir also eine Endlichschleife geschaffen, doch dies geht auch einfacher und übersichtlicher, denn BASIC stellt uns extra zur Schleifenprogrammierung zwei Befehle zur Verfügung, FOR und NEXT, die die FOR-NEXT- Schleife bilden.
FOR-NEXT arbeitet ähnlich, wie unsere IF-THEN- Schleife. Auch hier benötigen wir eine Laufvariable, nur, daß wir hier gleich in einem Zug angeben können, von welchem Wert zu welchem Wert gezählt werden soll.
Also haben wir hier die Zeilen 5 und 30 unseres ersten Schleifenprogramms in EINEM zusammengefaßt. Sehen Sie sich doch einfach einmal dieses kleine Programm an, das die selbe Arbeit verrichtet, wie unser
letztes Programm, allerdings mit Hilfe von FOR-NEXT:
10 FOR I=1 to 5 20 PRINT"DAS IST EIN TEXT" 30 NEXT
Das war alles! Auf den ersten Blick sieht das zwar
genauso lang aus, wie unser erstes Schleifenprogramm, doch der FOR-Befehl hat noch einige Eigenarten, die
ihn zum einen komfortabler machen, und zum anderen
ÜBERSICHTLICHER, was ja außerordentlich wichtig ist, wie wir festgestellt hatten. Nicht umsonst nämlich
hatte ich ein ganzes Kapitel der formatiertien Programmierung gewidmet!
Das Übersichtliche an FOR-NEXT ist, daß der gesamte
Schleifenrumpf, der Teil also, der immer wieder abgearbeitet werden soll, durch FOR und NEXT eingegrenzt wird. Sehen wir uns nun einmal an, was im Innern unsers Computers abläuft, wenn er eine solche
Schleife abarbeitet:
In Zeile 10 erkennt der 64 er erst einmal ( an FOR), daß hier gleich eine Schleife folgt. Direkt hinter
dem FOR-Befehl wird dann die Laufvariable mit einem
Grundwert " initialisiert", das heißt, daß ein bestimmter Wert als Ausgangswert für diese Variable
festgelegt wird. Diese Initialisierung entspricht
Zeile 5 unseres ersten Programms, hier wurde die Variable ' I' auf 0 gesetzt. Daß wir sie nicht mit 1 initialisierten, wie bei FOR, liegt einfach daran, daß sie anschließend, in Zeile 10, schon auf 1 gezählt wurde. Womit sie den selben Anfangswert hat, wie in unserem zweiten Programmbeispiel.
Wie gesagt haben wir nun die untere und die obere
Grenze festgelegt, innerhalb der der Computer zählen
soll. In unserem Beispiel ist das von 1 bis 5 .
In Zeile 20 geht' s jetzt weiter mit dem Schleifenrumpf, der hier nur diese eine Zeile, mit Nummer 20, lang ist. Natürlich könnten Sie hier auch mehrere
Zeilen stehen haben, Hauptsache ist, daß Sie diese
dann auch zwischen FOR und NEXT sozusagen " einklammern" . Unser Schleifenrumpf besteht also aus der Anweisung, den Text " DAS IST EIN TEXT" auszudrucken.
In Zeile 30 nun trifft der Computer auf die NEXT-Anweisung. Jetzt zählt er die Schleifenoder Laufvariable erst einmal um 1 hoch. Entsprechend also der
Zeile 10 unseres ersten Programms:
10 I= I+1
Anschließend prüft er, ob der Inhalt dieser Variable
mittlerweile größer ist, als der obere Grenzwert, ob
dieser also schon überschritten wurde. Ist dies der
Fall, so wird die Schleife beendet und der Computer
fährt in Programm fort. Ist die Laufvariable allerdings noch kleiner oder gleich dem Grenzwert, so
wird wieder an den Befehl im Programm verzweigt, der
nach der FOR-Anweisung kommt. Dies wiederholt sich
dann halt solange, bis der Grenzwert dann endlich
überschritten wurde. Ich möchte hier auch noch darauf
aufmerksam machen, daß die Laufvariable VOR dem Vergleich hochgezählt wird. Deshalb hat Sie nach dem
Aussprung aus der Schleife immer den Inhalt des oberen Grenzwertes plus 1 ! ! ! Dies zu wissen kann äußerst wichtig sein, da hier manchmal Fehler gemacht
werden:
FOR i=0 TO 3:PRINT"TEXT":NEXT
Diese Schleife zum Beispiel wird insgesamt 4( !) mal
durchlaufen, da von 0 nach 3 gezählt wird ( also 3 Ziffern plus die Null. . .) . Nicht also, wie man
fälschlicherweise annehmen könnte, nur 3 mal!
Hier sehen Sie übrigens auch, daß man FOR und NEXT
nicht unbedingt in eigene Programmzeilen schreiben
muß, es ist nämlich auch durchaus möglich sie in EI-NER Zeile zusammenzufassen, vorrausgesetzt, der
Schleifenrumpf ist nicht zu lang.
Grundsätzlich gilt: alle Befehle, Anweisungen und
Funktionen, die zwischen FOR und NEXT stehen bilden
alle gemeinsam den Schleifenrumpf, den Teil also, der
immer wieder von der Schleife durchlaufen wird, unabhängig davon, wie die einzelnen Befehle innerhalb
von Programmzeilen verteilt sind.
Doch kann man mit FOR noch viel mehr anfangen! Angenommen Sie wollten nicht immer um 1 erhöhen, sondern
immer um 2, weil Sie, aus welchen Gründen auch immer, alle 2 er Zahlen, oder alle geraden Zahlen, benutzen
möchten. Hierzu kann man die STEP-Anweisung benutzen, die an den FOR-Befehl angehängt wird, ohne diesen sie
nicht existieren kann, sprich nicht verwendbar ist.
Geben Sie doch einfach einmal folgendes ein:
FOR I=0 to 10 STEP 2:PRINT I:NEXT
Die Ausgabe dieser Schleife sieht so aus:
0 2 4 6 8 10
Eigentlich nichts neues mehr für uns. Hier wurde ganz
einfach von 0 bis 10 gezählt, allerdings in 2 er
Schritten, wie man an der Ausgabe erkennen kann - der
Inhalt von ' i' war immer um 2 erhöht. Auch hier
galt: erst als NACH einem Hochzählen um den Zählwert
( oder die sogenannte Schrittweite) der obere Grenzwert überschritten wurde, wurde die Schleife verlassen.
Es mag sein, daß dieses Ihnen noch nicht ganz einleuchtet, deshalb also ein weiteres Beispiel. Wir
hatten bis jetzt immer von einem kleineren Wert bis
zu einem größeren gezählt. Manchmal könnte es aber
auch ganz nützlich für uns sein, rückwärts zu zählen, beispielsweise von 5 bis 0 in 1 er-Schritten, oder gar
in halben Zahlen, also in 0 .5 er-Schritten. Das ist
absolut kein Problem mit STEP. Der Wert hinter diesem
Anweisungswort muß ganz einfach negativ sein, also
mit einem Minuszeichen (-) davor. Etwa so:
FOR I=5 to 0 STEP -1:PRINT I:NEXT
Hier haben wir dann eine " Rückwärtsschleife" . Sie
zählt rückwärts von 5 bis 0 . Auch hier gilt: erst
wenn der zweite Grenzwert, diesmal ist er allerdings
kleiner als der erste, UNTERSCHRITTEN wurde, wird die
Schleife verlassen. Diesmal also erst, wenn der Inhalt der Zählvariable kleiner ist, als der Grenzwert, zu dem gezählt werden soll. Dies ist ein kleiner Unterschied, der bei Schleifen mit negativen Zählwerten
auftritt, an den man sich jedoch leicht gewöhnt, da
er im Grunde ja ganz logisch ist, oder?
Das zum Thema Schleifen. Ich hoffe, Ihnen dieses Problem verständlich dargelegt zu haben. Nun möchte ich
mich, quasi zur Entspannung, einem etwas leichteren
Themen zuwenden, sozusagen ein paar kleine Häppchen
als " Hors d' oevre" vorschicken, auf das was nächsten
Monat auf sie zu kommt. . .
Beginnen wir mit einem kleinen Rechenoperator, den
ich Ihnen bei unserer Rechnerei am Anfang dieses Kurses verschwiegen habe. Es handelt sich hierbei um den
Exponentialoperator, der durch den ' Pfeil nach oben'('↑') ausgedrückt wird. Mit ihm können Sie die nte Potenz einer Zahl berechnen. Etwa 2 hoch 8, oder 5 zum Quadrat. Geschrieben wird das so:
PRINT 2↑8 PRINT 5↑2
Sie können diesem Operator natürlich genauso benutzen, wie die anderen Operatoren auch, also ebenfalls
auch bei Variablenzuweisungen benutzen.
Sollten Sie übrigens darauf bedacht sein, Ihre Programme so zu programmieren, daß sie mit einem Minimum
an Zeit ablaufen, dann gebe ich Ihnen den Tip, Ihre
Quadrat-Potenzen ( also die Potenzen, die die 2 als
Exponenten, oder als ' Hochzahl' haben) mit dem Multiplikationsoperator '*' auszudrücken. Dies rechnet der
64 er nämlich bedeutend schneller aus, als wenn Sie
den Potenz-Operator verwenden würden. Also anstatt:
PRINT X↑2 schreiben Sie besser:
PRINT X* X
Dieses führt zum selben Ergebnis, verbraucht allerdings bedeutend weniger Zeit. Sie selbst dürften das
vielleicht nicht direkt merken, da es der Computer
für uns normal Sterbliche immer noch sehr schnell berechnet, aber schreiben Sie doch vielleicht einfach
einmal eine Schleife, die eine solche Potenzoperation
vielleicht 1000 oder 2000 Mal durchführt, und stoppen
Sie dann doch mal die Sekunden, ich denke, daß Sie
einen Unterschied feststellen müßten. . .
Das nächste, was ich Ihnen nicht vorenthalten möchte, ist die " DEF-FN"- Anweisung. Mit dieser Anweisung können Sie ganze Funktionen in einem Ausdruck definieren, so daß sie diesen Ausdruck nur noch durch ein
kleines Namenskürzel aufrufen müssen. Angenommen, Sie
haben eine Formel, mit der Sie durch Eingabe einer
Unbekannten eine gewisse Größe berechnen können. Als
praktisches Beispiel will ich mich mal ein wenig an
der Kreisberechnung auslassen. Nehmen wir an, Sie
wollten ein Programm schreiben, das Ihnen den Kreisumfang sowie den Kreisinhalt berechnet. Die dazugehörigen Formeln lauten, wie wir wissen, wenn wir alle
schön in der Schule aufgepaßt haben:
Kreisumfang: 2rπ (= 2*r*π) Kreisinhalt: r↑2π (= r↑2*π)
Da wir hier in unserem Kurs leider keine Sonderzeichen haben, habe ich, um das Quadrat auszudrücken, wie unser C64 auch, den Exponentenpfeil (↑) benutzt.
Sie kennen Ihn ja mittlerweile. In Klammern sehen Sie
dann die endgültige Computerschreibweise ( da ja noch
die Multiplikations-Zeichen '*' eingefügt werden mußten.
Die Formel für den Kreisinhalt werden wir allerdings
gleich nochmal ein wenig abändern. Da wir ja die Quadrate etwas schneller berechnen wollen, heißt es
jetzt also: r* r*π( was ja dasselbe ist wie r↑2*π) .
Nun müssen diese beiden Funktionen nur noch mit
DEF FN in einem Namen definiert werden. Dies geschieht folgendermaßen:
10 def fnu(r)=2*r*π 20 def fni(r)=r*r*π
Mit DEF zeigen Sie dem Computer also an, daß Sie hier
eine Funktion definieren wollen. Dann geben Sie den
Namen der Funktion an, der sich immer aus dem FN-Prefix, einem oder zwei Buchstaben und dem '( R)'- Suffix zusammensetzt. Das Prefix ist bei jeder Definition gleich, der eigentliche Name der Funktion wird
durch die beiden Buchstaben in der Mitte bestimmt, bei denen Sie nach den selben Regeln arbeiten müssen
wie bei den Variablennamen. Diese Regeln hatte ich
Ihnen, als wir die Variablennamensgebung hatten, ja
schon einmal aufgezählt. Zum Suffix sei nur noch zu
sagen, daß hier in Klammern immer die Unbekannte stehen muß, die in der zu definierenden Funktionsgleichung ( oder Formel) eingesetzt werden soll.
Warum, werden Sie beim Aufruf erkennen. Ich möchte
hier jedoch erst einmal wieder ein weiteres Stück
unseres Programmes einfügen:
30 print chr$(14)chr$(8) 40 print"[CLS]Programm zur Berechnung von Kreisum- fang" 50 print"und -inhalt." 60 input"[2 DOWN]Radius ";r 70 u=fnu(r) 80 i=fni(r)
Die Zeilen 30-50 drucken die Titelzeile des Programms
aus. In Zeile 30 wird übrigens wieder mit CHR$(14) die Kleinschrift eingeschaltet und mit CHR$(8) die
Umschaltmöglichkeit durch Drücken der SHIFTund der
COMMODORE-Tasten blockiert. Wir hatten dies ja schon
einmal bei unserem Zylinderberechnungsprogramm. . .
In Zeile 60 fragt das Programm jetzt nach dem Radius, der nach Eingabe eines beliebigen Wertes in der Variablen ' r' gespeichert wird.
Jetzt folgt endlich unser langerwarteter Funktionsaufruf. Sie sehen, daß in Zeile 70 das Ergebnis der
Funktion erst einmal der Variablen ' u' zugeornet
wird. Der Aufruf ansich gestaltet sich höchst einfach
und schmerzlos. Sie schreiben ganz einfach wieder den
Prefix ' FN' gefolgt vom Funktionsnamen und dem Suf- fix, mit der unbekannten Variablen in runden Klammern
eingeschlossen - das wars schon. Jetzt müssen wir das
Ergebnis nur noch ausdrucken, und das geschieht folgendermaßen:
90 print" Der Kreisumfang ist:" u 100 print" Der Kreisinhalt ist:" i
Was ja hoffentlich keinerlei Erklärung bedarf. . .
Der Clou an den vordefinierten Funktionen ist also, daß man eine Unbekannte gleich in den Klammern am
Ende angeben kann. Sie hätten die Funktion ebenso
auch so aufrufen können:
print fnu(1 .5)
Hier haben wir den Wert der Funktion also gleich numerisch angegeben, nicht also in einer Variablen. Der
Vorteil von solchen Funktionsdefinitionen liegt auf
der Hand. Angenommen, Sie haben eine bestimmte Formel, die Sie in einem Programm wahnsinnig oft benutzen müssen. Mit DEF-FN können Sie diese also immer
abkürzen, und haben Ihre Funktion immer sofort parat.
Mit FN haben Sie also eine Art Variable für Formeln
( oder Funktionen), weshalb FN als ' normaler' Variablenname nicht zulässig ist. Sie können gerne einmal
versuchen der Variable ' fn' einen Wert zuzuweisen, doch wird Sie der C64 dann nur mit einem lapidaren
SYNTAX ERROR belohnen. . .
Außerdem sei noch hinzuzufügen, daß Sie eine Funktionsdefinition ausschließlich NUR innerhalb von Programmen durchführen können. Versuchen Sie dies im
Direktmodus, so quittiert Ihnen das der Computer mit
einem " ILLEGAL DIRECT ERROR", einem " UNERLAUBTEN DI-REKTANWEISUNGS FEHLER" also. Ebenso wie INPUT beispielsweise ist DEF außerhalb von Programmen unsinnig, weshalb dieser Fehler auftritt. Einmal definiert
allerdings, können Sie jede Funktion aus dem Direktmodus aus aufrufen - andersherum geht es also. . .
Beschäftigen wir uns nun noch ein wenig mit der benutzerfreundlichen Programmierung. Das heißt, daß wir
unsere Programme so schreiben wollen, daß sie auch
jeder Computeranfänger problemlos bedienen kann. Genauergesagt möchte ich Ihnen die komfortable Programmierung von sogenannten " Menüs" näherbringen. BASIC
stellt uns hierzu 2 äußerst nützliche und komfortable
Befehle zur Verfügung, die auch sehr gut noch für
weitere Aufgaben zu verwenden sind.
Als erstes will ich den Begiff " MENÜ" einmal klären.
Bei einem Menü handelt es sich um eine Zusammenfassung von Unterpunkten innerhalb eines Programms, die
der Benutzer einzeln aufrufen kann. Sie kennen dies
bestimmt schon von meinem kleinen ASCII-Druck- Programm namens " SHOWASC", das dem zweiten Teil dieses Kurses beigefügt war. Hier wurden Sie nämlich
gefragt, welche Funktion des Programms Sie wünschen.
Ich zeige Ihnen hier am besten einmal das Menü von
SHOWASC, damit Sie sich ein besseres Bild machen können:
----------------------------------------------------- ASCII-Tabellen-Druck. Written in 1988 by Uli Basters.
Bitte druecken Sie:
==================== F1 - Ausgabe der Liste auf Drucker F7 - Ausgabe der Liste auf Bildschirm E - fuer Programmende -----------------------------------------------------
Sie können hier also zwischen 3 sogenannten " Menüpunkten" wählen, die Sie durch das Drücken einer bestimmten Taste erreichen können. Kommen wir hier nun
zum ersten der beiden Befehle, die ich Ihnen vorstellen wollte: dem GET-Befehl.
Mit ihm können Sie einen Buchstaben von der Tastatur
einlesen, der dann - in einer Stringvariable gespeichert - jederzeit abgerufen werden kann. Hier ein
Auszug aus dem Programm des Menüs von oben ( ich habe
es aus Gründen der besseren Verständlichkeit ein wenig abgeändert. . .) :
... 25 print"Bitte druecken Sie: " 26 print"====================" 30 print" F1 - Ausgabe der Liste auf Drucker" 40 print" F7 - Ausgabe der Liste auf Bildschirm" 50 print" E - für Programmende" 60 get a$:if a$=""then 60
In den Zeilen 25-50 wird erst einmal der Text zu unserem Menü auf dem Bildschirm ausgegeben. Wie das
dann aussieht haben wir oben ja schon einmal gesehen.
In Zeile 60 haben wir jetzt unseren GET-Befehl. Wie
Sie sehen, steht ihm die String-Variable ' a$' nach.
Die Taste, die also auf der Tastatur gedrückt wird, wird im ASCII-Code in dieser Stringvariablen gespeichert. Hier könnte natürlich auch jede andere Stringvariable stehen, nicht aber eine Numerische, oder
eine Intgervariable.
Direkt anschließend, aber immer noch in Zeile 60, kommt ein IF-THEN- Vergleich. Es wird geprüft, ob der
Inhalt der Variablen a$="" ist. Sie werden sich vielleicht fragen, was diese 2 Hochkommas ausdrücken.
Nun, ganz einfach, schreiben Sie irgendwo in BASIC
für einen String, bei einer Zuweisung, oder wie hier
zum Vergleich, ein "" dann steht das für NICHTS, oder
auch KEIN STRING. Es wird also hier bei uns geprüft, ob ' a$' leer ist, oder ob ein String in ihr gespeichert ist. Dieser Vergleich ist notwendig, da der
Computer ja eine Taste in ' a$' gespeichert haben
könnte, obwohl Sie gar keine gedrückt haben. Das
hängt ganz einfach mit internen Vorgängen zusammen.
Mit GET fragen Sie nämlich grundsätzlich immer die
Tastatur ab, egal, ob jetzt eine Taste gedrückt ist, oder nicht - GET holt sich immer den aktuellen Tastaturstand in die ihm nachgestellte Stringvariable.
Sollte also beim Aufruf von GET keine Taste gedrückt
sein, so brauchen wir gar nicht erst weiterzumachen, sondern schicken den Computer gleich wieder auf GET.
Solange bis endlich eine Eingabe gebacht wurde. Wir
haben hier also praktisch eine Endlosschleife produziert, die erst dann beendet wird, wenn eine Taste gedrückt wird.
Jetzt können wir prüfen, welche Taste dies war. Dies
funktioniert ganz einfach über ein paar IF-THEN- Abfragen, siehe auch die folgenden Zeilen:
70 if a$="[F1]" then 300 80 if a$="[F7]" then 200 90 if a$="e" then end 100 goto 60
Wie die eckigen Klammern ja anzeigen, haben wir hierwieder 2 neue Sonderzeichen, die sehr leicht zu
erklären sind. Sie entstehen, wenn Sie innerhalb der
Gänsefüßchen die F1-( in Zeile 70) oder die F7- Taste
( in Zeile 80) drücken. Diese beiden Zeichen sind
übrigens gute Beispiele für die Sonderzeichen, denn
obwohl sie nicht sichtbar sind, wenn man sie ausdruckt, sind sie doch relativ wichtig, da man ohne
sie die Abfrage der F-Tasten nur schwer realisieren
könnte. Sie könnten hier übrigens ebenso schreiben:
70 if a$=chr$(133) then 300 80 if a$=chr$(136) then 200
Dies würde dasselbe bewirken, da die ASCII-Codes 133 und 136 ja den Tasten F1, und F7 entsprechen, die sie
nebenbei auch der ASCII-Tabelle im Bedienungshandbuch
des 64 ers, Anhang F, entnehmen können, oder Sie benutzen ganz einfach SHOWASC.
Es wird hier also nach Zeile 300 verzweigt, wenn der
Drucker die Tabelle drucken soll, oder zu Zeile 200, wenn sie auf dem Bildschirm dargestellt werden soll.
Anschließend kommt in Zeile 90 unseres Programms noch
der Vergleich, ob ' a$' nicht den Buchstaben ' e' beinhaltet. Ist dies der Fall, so wird das Programm mit
END beendet.
Interessant ist noch Zeile 100 . Hier wird wieder in
Zeile 60 zum GET-Befehl gesprungen, also zurück in
unsere Abfrageschleife. Dies ist notwendig, da ja
auch noch andere Tasten, als F1, F7 oder e, gedrückt
worden sein könnten - sei es aus Versehen, oder nur
weil der User das Programm einmal ärgern wollte. War
dies der Fall, so hat der Computer bis in Zeile 90 verglichen und festgestellt, daß keiner der 3 ASCII-Codes in ' a$' gespeichert ist. Jetzt würde er ja im
Programm ganz normal weitermachen. Da ich in ( der nun folgenden) Zeile 200 allerdings das Modul abgelegt
habe, das die Ausgabe auf den Bildschirm übernimmt, müssen wir ihn hier dann abgefangen, damit er nicht
unkontrolliert in eine Unterroutine reinläuft, was
eben durch jenen besagten Sprung in die Zeile 60 realisiert wird.
Der zweite Befehl, den ich Ihnen noch vorstellen
möchte, heißt ON, und wird in Verbindung mit GOTO und
GOSUB benutzt. Er ist sozusagen eine spezielle Version des IF-Befehls. Hinter ON folgt eine Formel, die
vom Computer errechnet wird. Dies ist im einfachsten
Fall eine numerische Variable. Dann kommt entweder
der GOTOoder der GOSUB-Befehl, gefolgt von einer
Liste mit Zeilennummern, die durch Kommata getrennt
werden. Praktisch sieht das etwa so aus:
20 on x goto 100,200,300,400,500
Jetzt wird geprüft, welcher Wert in ' x' enthalten
ist. Ist x=1, dann wird die erste Zeilennummer, die
in der Liste steht, angesprungen ( wie wenn sie ein
GOTO 100 ausführen würden) . Ist x=2 dann wird die 2 .
Zeilennummer angesprungen, bei x=3 die 3 . und so
fort. . .
Diese eine Zeile entspricht also den 5 IF-THEN- Zeilen:
10 if x=1 then 100 20 if x=2 then 200 30 if x=3 then 300 40 if x=4 then 400 50 if x=5 then 500
Sollte x gleich 0, beziehungsweise negativ, oder gar
größer als die angegebenen Glieder der Liste sein, so
wird ganz normal im Programm fortgefahren. Wollten
wir unser Programm von vorhin also umschreiben, so
müßte das folgendermaßen aussehen.
60 input"Menüpunkt ";x 70 on x goto 200,300,400 80 goto 60
Das sieht doch schon gleich viel kürzer aus! Allerdings darf man hier nicht vergessen, daß in Zeile 400 dann auch wirklich noch ein END-Befehl steht, da dieser ja in unserem alten Programm direkt in der IF-THEN- Abfrage kam.
Ich habe hier übrigens ganz bewußt den INPUT-Befehl
benutzt, da wir ja gelernt haben, daß man bei GET nur
Stringvariablen einlesen kann. Hierbei haben wir dann
im Endeffek keine Möglichkeit mit ON zu arbeiten, es sein denn man greift zu einem kleinen Trick:
die Ziffern der Zahlen sind nämlich im ASCII-Code
alle hintereinander angeordnet. Die 0 hat den Code
48, die 1 den Code 49 und so weiter, bis zur 9, die
den Code 57 belegt. Wird bei einer GET-Abfrage also
die 1 gedrückt, so enthält a$ den CHR$- Code 49 . Wenn
wir jetzt von dieser Zahl einfach den Wert 48 subtrahieren, so erhalten wir das Ergebnis 1, was ja genau
die Taste ist, die gedrückt wurde, nur haben wir
jetzt einen Zahlwert, mit dem ON etwas anfangen kann.
Das Programm hierzu müßte dann so aussehen:
60 get a$:if a$="" then 60 70 on asc(a$)-48 goto 200,300,400 80 goto 60
Hier haben Sie dann auch ein Beispiel, in dem wir
eine ganze Formel benutzen, die zuerst berechnet und
dann ausgewertet wird. Wir haben dabei die, uns mittlerweile schon altbekannte, ASC-Anweisung angewandt, um den CHR$- Code der in ' a$' gespeicherten Taste zu
erfahren.
Wie eingangs schon erwähnt, könnten Sie hier auch den
GOSUB-Befehl verwenden, nur müssen Sie dann Ihre Module auch mit RETURN wieder abschließen. Denkbar wäre
auch, daß man mit Buchstaben die Tasten abfrägt, wobei man alphabetisch vorgeht. Da der ASCII-Code des
Zeichens ' a' den Wert 65 hat, müßten Sie hier nur den
Wert 64 subtrahieren, um brauchbare Zahlwerte für ON
herauszubekommen.
Hiermit möchte ich nun für diesen Monat wieder einmal
schließen und mich bis Mai verabschieden. Wir werden
uns dann, wie ich diesmal schon angedeutet hatte, um
etwas höchst wichtiges kümmern, was unerläßlich ist, wenn man sich ein wenig mit der Grafikund Soundprogrammierung des C64 beschäftigen möchte. Ich rede von
dem sogenannten Binärsystem und dem Speicheraufbau
unseres kleinen Freundes. Mehr dann nächsten Monat.
Bis dann also, Ihr Uli Basters.