Magic Disk 64

home to index to text: MD8904-KURS-BASIC_KURS_TEIL_4-1_:_VON_ADAM_UND_EVA...(TEIL_4)-7.1.txt
     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.

Valid HTML 4.0 Transitional Valid CSS!