ANHANG A: Antworten zu den Fragen
Fragen zu Kapitel 4
-
Mit dem Strichpunkt in einer
PRINT
-Anweisung können mehrere Ausdrücke aneinandergereiht werden. Sie werden hintereinander ausgegeben. Ein Strichpunkt am Ende derPRINT
-Anweisung verhindert den Zeilenumbruch.
Der Unterschied zwischen einem Komma und einem Strichpunkt ist beiPRINT
, dass ein Komma die Einrückung zur nächsten Tabulatorposition bewirkt. -
Das Komma dient bei den meisten Anweisungen zur Trennung der einzelnen Parameter.
-
Anführungszeichen werden benötigt, wenn Zeichenketten unverändert ausgegeben werden sollen. Um Variablenwerte und Ergebnisse von Berechnungen auszugeben, werden die Anführungszeichen weggelassen.
-
Erlaubt sind alle Buchstaben von a-z (Groß- und Kleinbuchstaben), Ziffern 0-9 und der Unterstrich _. Eine Variable darf jedoch nicht mit einer Ziffer beginnen.
-
„Sprechende Namen“ sind Bezeichnungen, die dem besseren Verständnis des Programmablaufs dienen. Beispielsweise kann man am „sprechenden Namen“ einer Variablen sofort erkannt werden, welche Bedeutung diese Variable besitzt.
-
TAB
setzt den Textcursor auf die angegebene Position vor.SPC
rückt den Textcursor um die angegebene Zahl an Stellen vorwärts.
COLOR 4, 14 ' rot auf gelb CLS LOCATE 1, 15 PRINT "Mein erstes FreeBASIC-Programm" LOCATE 2, 15 PRINT "==============================" PRINT ' Leerzeile PRINT "Heute habe ich gelernt, wie man mit FreeBASIC Text ausgibt." PRINT "Ich kann den Text auch in verschiedenen Farben ausgeben." SLEEP
Fragen zu Kapitel 5
-
In der Anweisung
INPUT
kann der Strichpunkt nur direkt nach der Meldung stehen, die als Frage ausgegeben werden soll. In diesem Fall wird an die Frage ein zusätzliches Fragezeichen angehängt. Folgt auf die Frage ein Komma statt eines Strichpunkts, dann wird kein zusätzliches Fragezeichen ausgegeben.
Außerdem dient das Komma zum Trennen verschiedener Variablen, falls Sie mehrere Eingaben gleichzeitig abfragen wollen. Auch der Benutzer muss dann seine Eingabe durch Kommata trennen. -
Die Anweisung
INPUT
erwartet vom Benutzer die Eingabe einer Zeile — d. h. es werden so viele Zeichen von der Tastatur gelesen, bis Return gedrückt wird. Bis dahin hat der Benutzer die Möglichkeit, die Eingabe z. B. durch Backspace und Delete zu bearbeiten.
Die FunktionINPUT()
fragt eine festgelegte Anzahl an Zeichen ab. Dabei ist es egal, ob es sich um normale Zeichen oder Sondertasten wie Return, Backspace oder Pfeiltasten handelt (dabei ist zu beachten, dass eine Reihe von Sonderzeichen, z. B. die Pfeiltasten, als zwei Zeichen behandelt werden). Unter anderem gibt es also für den Benutzer keine Möglichkeit, seine Eingabe zu korrigieren oder vorzeitig zu beenden. -
INPUT()
wartet auf die Eingabe einer festgelegten Anzahl an Zeichen. Das Programm wird währenddessen angehalten.INKEY()
ruft genau eine Taste aus dem Tastaturpuffer ab (dabei kann es sich auch um eine Taste handeln, die zwei Zeichen belegt), wartet jedoch nicht auf einen Tastendruck.
DIM AS INTEGER zahl1, zahl2 PRINT "Gib zwei Zahlen ein - ich werde sie addieren!" INPUT "1. Zahl: ", zahl1 INPUT "2. Zahl: ", zahl2 PRINT PRINT "Die Summe aus"; zahl1; " und"; zahl2; " ist"; PRINT zahl1 + zahl2; "." PRINT PRINT "Druecke eine Taste, um das Programm zu beenden." SLEEP
Fragen zu Kapitel 6
-
Für Ganzzahlen im Bereich ±1 000 000 000 ist ein
LONG
oderLONGINT
nötig (oder auch einINTEGER
). Vorzeichenlose Datentypen bieten sich wegen des negativen Zahlenbereichs nicht an.
Prinzipiell könnten auchSINGLE
undDOUBLE
verwendet werden, dies wird jedoch für reine Ganzzahlbereichnungen aufgrund der Geschwindigkeit und (hier insbesondere im Falle vonSINGLE
) möglichen Problemen bei der Genauigkeit nicht empfohlen.1 -
Wenn die Speichergröße ein ausschlaggebendes Argument ist, genügt hier der Datentyp
UBYTE
. Wenn auf hohe Verarbeitungsgeschwindigkeit Wert gelegt wird, ist die Verwendung einesINTEGER
empfehlenswert. Möglich ist allerdings jeder Zahlendatentyp außerBYTE
. -
Für Gleitkommazahlen stehen die Datentypen
SINGLE
undDOUBLE
zur Verfügung.DOUBLE
rechnet mit höherer Genauigkeit, belegt dafür aber auch den doppelten Speicherplatz. -
Ein
ZSTRING
ist nullterminiert und kann daher kein Nullbyte enthalten. EinSTRING
unterliegt dieser Einschränkung nicht. Der Vorteil vonZSTRING
liegt in seiner Kompatibilität zu externen Bibliotheken. -
Einer Konstanten wird bei der Deklaration ein Wert zugewiesen, der zugleich ihren Datentypen festlegt und der später nicht mehr geändert werden kann. Im Gegensatz dazu können Variablen im späteren Programmverlauf geändert werden. Daher muss die Wertzuweisung auch nicht gleich bei der Deklaration erfolgen.
-
LONG
ist ein Datentyp mit der festen Größe232
. Die Größe einesINTEGERs
ist dagegen plattformabhängig. In 32-Bit-Systemen ist einINTEGER
genauso groß wie einLONG
(wird aber dennoch als eigenständiger Datentyp behandelt).
Vorteil desINTEGERs
gegenüber einemLONG
ist, dass es unter jeder Plattform die schnellste Zugriffszeit besitzt. Dafür kann die variable Größe zu Problemen bei der Portierung des Programms von 32 Bit zu 64 Bit oder umgekehrt führen.
Fragen zu Kapitel 7
Der Quelltext für alle drei Aufgaben steht unten in einem gemeinsamen Programm — die einzelnen Aufgabenteile wurden entsprechend gekennzeichnet. Das Programm weist viele Dopplungen auf. Mit den Kenntnissen aus dem folgenden Kapitel können Sie seinen Umfang fast um die Hälfte reduzieren.
' Aufgabe 1: Deklaration des UDT TYPE TProdukt AS STRING name_ AS DOUBLE einkaufspreis, verkaufspreis AS INTEGER stueckzahl END TYPE ' Aufgabe 2: Produkteingabe DIM AS TProdukt produkt1, produkt2 PRINT "Geben Sie, durch Komma getrennt, folgende Produktinformationen ein:" PRINT "Produktname, Einkaufspreis, Verkaufspreis, Stueckzahl" PRINT WITH produkt1 INPUT "1. Produkt: ", .name_, .einkaufspreis, .verkaufspreis, .stueckzahl IF .einkaufspreis < 0 OR .verkaufspreis < 0 THEN PRINT "WARNUNG: Negative Preise sind nicht vorgesehen!" END IF IF .verkaufspreis < .einkaufspreis THEN PRINT "WARNUNG: Sie wollen billiger verkaufen, als Sie eingekauft haben!" END IF IF .stueckzahl < 0 THEN PRINT "WARNUNG: Sie koennen keine negative Anzahl besitzen!" END IF END WITH WITH produkt2 INPUT "2. Produkt: ", .name_, .einkaufspreis, .verkaufspreis, .stueckzahl IF .einkaufspreis < 0 OR .verkaufspreis < 0 THEN PRINT "WARNUNG: Negative Preise sind nicht vorgesehen!" END IF IF .verkaufspreis < .einkaufspreis THEN PRINT "WARNUNG: Sie wollen billiger verkaufen, als Sie eingekauft haben!" END IF IF .stueckzahl < 0 THEN PRINT "WARNUNG: Sie koennen keine negative Anzahl besitzen!" END IF END WITH ' Aufgabe 3: Ausgabe WITH produkt1 PRINT "Das Produkt " & .name_ & " erzielt einen Gewinn von "; PRINT (.verkaufspreis + .einkaufspreis) & " pro Stueck." END WITH WITH produkt2 PRINT "Das Produkt " & .name_ & " erzielt einen Gewinn von "; PRINT (.verkaufspreis + .einkaufspreis) & " pro Stueck." END WITH
Fragen zu Kapitel 8
-
Ein statisches Array wird, wie eine Variable, mit
DIM
und der Angabe des Datentyps deklariert. Im Unterschied zur Deklaration einer Variablen folgen auf den Array-Namen geschweifte Klammern, in denen die Dimensionen des Arrays festgelegt werden. Mögliche Deklarationen wären also
DIM AS STRING array1(untereGrenze TO obereGrenze)
DIM array2(untereGrenze TO obereGrenze) AS INTEGER
Die untere Grenze muss nicht angegeben werden, wenn sie 0 sein soll:
DIM AS DOUBLE array3(obereGrenze)
Sollen die Werte des Arrays gleich initiiert werden, dann werden die Werte, die zusammen zur selben Dimension gehören, in geschweiften Klammern eingeschlossen. -
Im Gegensatz zu statischen Arrays werden bei der Deklaration dynamischer Arrays in den Klammern hinter dem Array-Namen keine Grenzen angegeben, oder man verwendet
REDIM
stattDIM
. Die Werte eines dynamischen Arrays können nicht sofort bei der Deklaration initiiert werden. -
Statische Arrays besitzen eine feste Länge, während die Länge eines dynamischen Arrays im Programmverlauf verändert werden kann. Mit
ERASE
wird ein dynamisches Array gelöscht, d. h. es wird in den Zustand eines nicht dimensionierten Arrays zurückgesetzt (wobei auch jetzt die Anzahl der Dimensionen nicht mehr verändert werden kann). Bei einem statischen Array werden durchERASE
lediglich die Werte „auf Null“ gesetzt. -
Ein Array, ob statisch oder dynamisch, kann maximal acht Dimensionen besitzen.
-
Wenn die bisherigen Werte erhalten bleiben sollen, ist beim Einsatz von
REDIM
das SchlüsselwortPRESERVE
notwendig. OhnePRESERVE
werden die Werte des Arrays zurückgesetzt.
Beachten Sie, dass bei einer Verkleinerung eines Arrays Werte verloren gehen. Bei einer Veränderung der unteren Grenze verschieben sich außerdem die Indizes. -
UBOUND(array, 0)
gibt die Anzahl der Dimensionen zurück; bei nicht dimensionierten Arrays ist das der Wert0
. Außerdem liefert bei nichtdimensionierten ArraysUBOUND(array)=-1
undLBOUND(array)=0
Fragen zu Kapitel 9
-
Variablen werden an Speicheradressen abgelegt. Pointer sind ganz einfach Zeiger auf diesen Speicherbereich. Ein Pointer enthält also nicht den Variablenwert, sondern die Adresse, unter der der Variablenwert gefunden werden kann.
-
Bisher können wir noch keine sinnvollen Anwendungen für Pointer umsetzen; dazu sind erst fundierte Kenntnisse über die Speicherverwaltung nötig. Wir werden in [KapGrafik] Pointer einsetzen, um Grafikpuffer zu verwalten. Ein beliebter Einsatzbereich für Pointer ist auch die Kommunikation mit externen Bibliotheken.
-
Ganz unabhängig vom Datentyp: Ein Pointer hat immer die Größe eines
INTEGERs
, also je nach Architektur 32 Bit oder 64 Bit. Die Größe des Speicherbereichs, auf den der Pointer verweist, unterscheidet sich natürlich je nach Datentyp.
Fragen zu Kapitel 10
-
Einrückungen werden vom Compiler ignoriert und dienen nur dem Programmierer bzw. jedem, der einen Blick in den Quelltext wirft. Ziel ist eine übersichtliche Strukturierung: Alle Zeilen, die sich bei (ggf. verschachtelten) Blöcken auf derselben Ebene befinden, werden gleich weit eingerückt. Dadurch wird die Verschachtelungstiefe sofort auf einem Blick erkennbar.
-
Der Zahlenwert
0
wird als falsch interpretiert, jeder andere Zahlenwert als wahr. Strings besitzen keinen Wahrheitswert. Natürlich werden auch dieBOOLEAN
true
als wahr undfalse
als falsch interpretiert.
Zur Auswertung von Bedingungen verwendet FreeBASIC-1
für wahr und0
für falsch. -
Zeichenketten werden von links nach rechts Zeichen für Zeichen verglichen, solange bis der erste Unterschied auftritt. Entscheidend ist der ASCII-Code des verglichenen Zeichens. Das bedeutet unter anderem, dass Großbuchstaben kleiner sind als Kleinbuchstaben.
-
Ein logischer Operator vergleicht die Wahrheitswerte der übergebenen Ausdrücke und liefert einen Wahrheitswert, also
-1
oder0
bzw.true
oderfalse
. Ein Bit-Operator vergleicht die Ausdrücke Bit für Bit, wodurch prinzipiell jeder Zahlenwert als Ergebnis in Frage kommt. NurANDALSO
undORELSE
sind echte logische Operatoren; beiAND
,OR
,XOR
,EQV
,IMP
undNOT
handelt es sich um Bit-Operatoren, die unter speziellen Bedingungen wie logische Operatoren verwendet werden können. -
(a > 3 AND a < 8) OR (a > 12 AND a < 20)
Beachten Sie, dass „zwischen 3 und 8“ die Zahlen 3 und 8 nicht einschließt.
Zum Programmier-Auftrag will ich zwei Lösungen vorstellen; einmal nur mit IF
:
DIM benutzername AS STRING, passwort AS STRING, alter AS INTEGER INPUT "Gib deinen Namen ein: "; benutzername INPUT "Gib dein Passwort ein: "; passwort INPUT "Gib noch das Alter an: "; alter IF benutzername = "Jerry" AND passwort = "supersicher" THEN ' korrekte Eingabe IF alter < 14 THEN PRINT "Du bist leider noch zu jung." ELSEIF alter < 18 THEN PRINT "Du darfst weiter, wenn du versprichst, dass ein Erwachsener dabei ist." ELSE PRINT "Willkommen!" END IF ELSE ' falsche Eingabe PRINT "Benutzername und/oder Passwort waren leider falsch." END IF SLEEP
Als zweites eine Altersüberprüfung mit SELECT CASE
(nur der relevante Teil)
IF benutzername = "Jerry" AND passwort = "supersicher" THEN ' korrekte Eingabe SELECT CASE alter CASE IS < 14 PRINT "Du bist leider noch zu jung." CASE 14 TO 17 PRINT "Du darfst weiter, wenn du versprichst, dass ein Erwachsener dabei ist." CASE ELSE PRINT "Willkommen!" END IF ELSE ' falsche Eingabe PRINT "Benutzername und/oder Passwort waren leider falsch." END IF
Für zwei Benutzernamen mit zugehörigen Passwörtern könnte Zeile 5 folgendermaßen aussehen:
IF (benutzername = "Jerry" AND passwort = "supersicher") _ OR (benutzername = "Tom" AND passwort = "strenggeheim") THEN
An dieser Stelle sei aber noch einmal darauf hingewiesen, dass eine Klartext-Angabe des Passworts im Quelltext nur zu Übungszwecken sinnvoll ist und keinesfalls einen sicheren Passwortschutz darstellt!
Fragen zu Kapitel 11
-
Bei einer kopfgesteuerten Schleife erfolgt die Abfrage der Lauf- oder Abbruchbedingung vor dem Schleifendurchlauf, bei einer fußgesteuerten Schleife erfolgt sie danach. Insbesondere bedeutet das, dass eine fußgesteuerte Schleife auf jeden Fall mindestens einmal durchlaufen wird.
-
Eine
FOR
-Schleife bietet sich an, wenn eine feste Anzahl an Durchgängen feststeht. Auch z. B. beim Durchlaufen eines Arrays ist sie hilfreich, da seine Länge bekannt ist (sie kann ggf. mitLBOUND()
undUBOUND()
bestimmt werden) und die Zählvariable als Index für den Array-Zugriff dienen kann. EineDO
-Schleife hat dagegen eine flexible Laufdauer und kann verwendet werden, wenn die letztendliche Anzahl der Durchläufe zu Beginn unbekannt ist. -
Eine
DO
-Schleife ohne Lauf- und Abbruchbedingung ist eine Endlosschleife. Sie kann nur durch den BefehlEXIT DO
verlassen werden. Allerdings spricht man auch bei Schleifen, deren Abbruchbedingung nie erfüllt werden kann (z. B.DO UNTIL 2>3
) oder deren Laufbedingung immer erfüllt ist, von einer Endlosschleife. -
Eine Zählvariable benötigt einen Datentyp, der um eine Schrittweite erhöht werden kann (man sagt dazu, dass sie einen Iterator besitzen). Also kommen alle Zahlendatentypen in Frage, nicht jedoch Zeichenketten.
In [KapUDTOperatorStep] werden eigene Datentypen behandelt, für die ein Iterator definiert werden kann. -
Gleitkommazahlen können bei
FOR
-Schleifen problematisch sein. Zum einen kommt es bei der Erhöhung um eine Gleitkkommazahl leicht zu Rundungsfehlern, zum anderen sollte eine Gleitkomma-Schrittweite nicht zusammen mit einer Ganzzahl-Laufvariablen verwendet werden, da die Schrittweite dann sowieso erst gerundet wird.
Ein anderes Problem tritt auf, wenn bis an die Grenze des Wertebereichs der (Ganzzahl-)Laufvariablen gezählt werden soll. Nach der letzten Erhöhung wird dann der Wertebereich überschritten, und die Laufvariable liegt wieder am unteren Ende des Wertebereichs. Analog gilt das natürlich auch bei negativer Schrittweite, wenn bis zum unteren Ende des Wertebereichs gezählt werden soll. -
Mit
CONTINUE DO
bzw.CONTINUE FOR
springt das Programm an das Ende der Schleife und überprüft, ob ein weiterer Durchlauf stattfinden muss oder nicht.EXIT DO
bzw.EXIT FOR
springt sofort aus der Schleife heraus.
CONTINUE
existiert auch für andere Blockstrukturen, z. B. für denSELECT
-Block. -
Programmieraufgabe:
' Namenseingabe DIM AS STRING eingabe, nachname() ' dynamisches Array deklarieren DIM AS INTEGER i = 0 ' Zaehlvariable fuer die Array-Laenge PRINT "Geben Sie die Namen ein - Leereingabe beendet das Programm" DO PRINT "Name"; i+1; ": "; INPUT "", eingabe IF eingabe <> "" THEN REDIM PRESERVE nachname(i) nachname(i) = eingabe i += 1 END IF LOOP UNTIL eingabe = "" PRINT "Sie haben"; UBOUND(nachname)+1; " Namen eingegeben." ' Namensausgabe FOR i AS INTEGER = UBOUND(nachname) TO 0 STEP -1 PRINT nachname(i) NEXT SLEEP
Fragen zu Kapitel 12
-
Wiederverwertbarkeit: Ein häufig benötigter Programmteil muss nur einmal geschrieben werden und ist dann beliebig oft aufrufbar. Durch die Verwendung von Parametern können auch unterschiedliche Verläufe im selben Unterprogramm erreicht werden.
Wartbarkeit: Durch die Reduktion des Quellcodes müssen Veränderungen nur noch an einer Stelle vorgenommen werden statt an mehreren Stellen gleichzeitig. Damit einher geht auch die Verringerung der Fehleranfälligkeit.
Lokale Verwendung der Variablen: Da Unterprogramme ihren Speicher selbständig verwalten, müssen Sie sich (bei korrekter Umsetzung) im Unterprogramm keine Gedanken über die Variablenbelegungen im Hauptprogramm oder anderen Unterprogrammen machen.
Rekursion: Unterprogramme können sich auch selbst rekursiv aufrufen. Damit lassen sich Probleme lösen, die auf anderem Weg deutlich schwerer zu bewältigen wären. -
Funktionen liefern einen Rückgabewert, Prozeduren dagegen nicht. Dementsprechend bieten sich Prozeduren an, wenn Sie keinesfalls einen Rückgabewert erwarten. Umgekehrt können aber alle Prozeduren auch als Funktionen definiert werden, die dann z. B. eine Erfolgsmeldung (oder Fehlermeldung) zurückgeben.
-
Mit
SHARED
definierte Variablen können im Hauptprogramm und allen Unterprogrammen verwendet werden — dies läuft jedoch dem Gedanken der lokalen Variablen zuwider. Die gängige Methode ist, benötigte Variablen als Parameter zu übergeben. Konstanten sind im gesamten Programm zugreifbar. -
Parameter können
BYVAL
(als Wert) oderBYREF
(als Referenz) übergeben werden. Ein mitBYVAL
übergebener Wert wird in der Prozedur lokal gespeichert. Änderungen an dieser Variablen innerhalb des Unterprogramms haben keine Auswirkungen auf das Hauptprogramm. Dagegen wird mitBYREF
eine Variable „direkt“ übergeben. In diesem Fall wirkt sich eine Veränderung der Variablen im Unterprogramm auch auf den Wert der Variablen im Hauptprogramm aus.
Fragen zu Kapitel 13
-
Zahlendatentypen werden untereinander immer implizit umgewandelt. Wenn Sie z. B. einer Ganzzahl-Variablen den Wert einer Gleitkommazahl zuweisen oder umgekehrt, wird der Wert automatisch an den richtigen Datentyp angepasst. Eine weitere Form der impliziten Umwandlung ist die String-Konkatenation mit
&
— hierbei werden die Werte ggf. in Strings umgewandelt.
Abgesehen von der String-Konkatenation findet jedoch keine automatische Umwandlung zwischen Strings und Zahlenwerten statt. Wenn Sie etwa mit den in Zeichenketten vorliegenden Zahlenwerten rechnen oder einen Zahlenwert als String speichern wollen, müssen Sie die notwendigen Umwandlungen explizit durchführen. -
ASCII ist eine standardisierte Zeichencode-Tabelle mit 128 Einträgen (die Werte von 0 bis 127). In einem ASCII-codierten Text können Sie sicher sein, dass ein bestimmter Zahlenwert immer dasselbe Zeichen repräsentiert. ANSI ist eine Erweiterung des ASCII-Codes auf 256 Einträge (die Werte von 0 bis 255). Während die Werte von 0 bis 127 mit den ASCII-Werten identisch sind, hängt die Bedeutung der weiteren Zeichen davon ab, welche Codierung verwendet wurde. Ein ANSI-codierter Text (der auch Nicht-ASCII-Zeichen verwendet) kann daher nur dann korrekt gelesen werden, wenn auch bekannt ist, welche Codierung verwendet wurde.
-
Unten ist ein mögliches Programm aufgeführt. Sondertasten werden aus
CHR(255)
und einem weiteren Wert zusammengesetzt. Beispiele:
CHR(8)
,CHR(9)
,CHR(13)
,CHR(27)
: Backspace, Tab, Return, Esc
CHR(255, 72)
,CHR(255, 75)
,CHR(255, 77)
,CHR(255, 80)
: Pfeiltasten oben, links, rechts, unten
CHR(255, 59)
, …CHR(255, 68)
: Funktionstasten F1, … F10
CHR(255, 71)
,CHR(255, 79)
,CHR(255, 73)
,CHR(255, 81)
: Pos1, Ende, BildAuf, BildAbDIM AS STRING taste PRINT "Tastenabfrage - Beenden mit ESC" DO taste = INKEY SELECT CASE LEN(taste) CASE 1 : PRINT ASC(taste) CASE 2 : PRINT ASC(taste), ASC(taste, 2) END SELECT SLEEP 1 ' Ich hoffe, Sie haben daran gedacht! LOOP UNTIL taste = CHR(27) ' Escape-Taste
Fragen zu Kapitel 14
-
Zufallszahl innerhalb eines Bereiches
Für den Fall, dass der Endwertbis
kleiner ist als der Startwertvon
, werden die beiden Werte in der Berechnungsformel einfach vertauscht.FUNCTION zufallszahl(von AS INTEGER, bis AS INTEGER) AS INTEGER IF bis > von THEN RETURN INT(RND*(bis-von+1)) + von ELSE RETURN INT(RND*(von-bis+1)) + bis ' vertauschte Werte END IF END FUNCTION
-
Bit-Manipulation
Die Varianten mitBITSET()
undBITRESET()
sind deutlich aufwändiger, allerdings muss man sich an die sehr eleganten Möglichkeiten mitAND
,XOR
usw. erst gewöhnen. lassen Sie sich am besten immer auch die Binärdarstellung der Zahlen ausgeben, um ein Gefühl für die Funktionsweise zu bekommen.DIM AS LONG alt, neu ' ohne Wertzuweisung; der Wert ist im Programm egal ' a) niedrigste vier Bit auf 0 ' mit BITRESET neu = alt FOR i AS INTEGER = 0 TO 3 neu = BITRESET(neu, i) NEXT ' mit AND neu = alt AND &hfffffff0 ' sehen Sie sich dazu bei Bedarf die Binaerwerte an ' b) alle Bitwerte umdrehen ' mit BIT(RE)SET neu = alt FOR i AS INTEGER = 0 TO 31 neu = IIF(BIT(neu, i), BITRESET(neu, i), BITSET(neu, i)) NEXT ' mit XOR neu = alt XOR &hffffffff ' mit NOT (sicherlich die beste Loesung fuer diese Aufgabe) neu = NOT alt ' c) niedrigste vier Bitwerte umdrehen ' mit BIT(RE)SET neu = alt FOR i AS INTEGER = 0 TO 3 neu = IIF(BIT(neu, i), BITRESET(neu, i), BITSET(neu, i)) NEXT ' mit XOR neu = alt XOR 15
-
Programmieraufgabe:
TYPE TFormat AS INTEGER fett : 1 AS INTEGER unterstrich : 1 AS INTEGER kursiv : 1 END TYPE DIM AS TFormat formatierung formatierung.fett = 1 formatierung.kursiv = 1 ' Ist Fettschrift aktiviert? IF formatierung.fett THEN PRINT "fett" ' Ist sowohl Fett- als auch Kursivschrift aktiviert? IF formatierung.fett AND formatierung.kursiv THEN PRINT "Fett und kursiv? Uebertreiben Sie es bitte nicht!" END IF ' Sind alle drei Formatierungsformen deaktiviert? IF formatierung.fett = 0 AND formatierung.kursiv = 0 _ AND formatierung.unterstrich = 0 THEN PRINT "Es wurde keine Formatierung gewaehlt." END IF SLEEP
Fragen zu Kapitel 15
-
Programm zur Eingabe des Namens
DIM AS STRING eingabe, vorname, nachname DIM AS INTEGER suchposition ' Namenseingabe PRINT "Geben Sie, durch Leerzeichen getrennt, Ihren Vor- und Nachnamen ein: " INPUT "", eingabe ' letztes Leerzeichen finden (funktioniert auch bei Eingabe mehrerer Vornamen, ' solange der Nachname nicht aus mehreren Einzelwoertern besteht) suchposition = INSTRREV(eingabe, " ") ' Eingabe aufsplitten und Ergebnis ausgeben IF suchposition THEN ' Leerzeichen gefunden vorname = LEFT(eingabe, suchposition-1) nachname = MID (eingabe, suchposition+1) PRINT "Vorname: " & vorname PRINT "Nachname: " & nachname ELSE ' kein Leerzeichen gefunden PRINT "Die Eingabe war fehlerhaft!" END IF SLEEP
-
Ersetzung eines Teilstrings
FUNCTION ersetzeUmlautA(eingabe AS STRING) AS STRING ' Bei einer Parameterbergabe BYREF kann direkt mit eingabe gearbeitet werden ' mir ist die Beibehaltung der originalen Uebergabe jedoch lieber. DIM AS STRING rueckgabe = eingabe DIM AS INTEGER suchposition =INSTR(rueckgabe, "ä") ' Solange ein Treffer erzielt wurde, ersetze und suche weiter. DO WHILE suchposition rueckgabe = LEFT(rueckgabe, suchposition-1) & "ae" _ & MID(rueckgabe, suchposition+1) suchposition = INSTR(suchposition+2, rueckgabe, "ä") LOOP RETURN rueckgabe END FUNCTION
-
MIRROR-Funktion
FUNCTION mirror(eingabe AS STRING) AS STRING DIM AS STRING rueckgabe = "" FOR i AS INTEGER = LEN(eingabe) TO 1 STEP -1 rueckgabe &= MID(eingabe, i, 1) NEXT RETURN rueckgabe END FUNCTION
Zusatzaufgabe zu Aufgabe 2: Erweitern Sie die Funktion so, dass sie noch einen Such- und einen Ersetzungsstring entgegennimmt und jedes Vorkommen des Suchstrings durch den Ersetzungsstring ersetzt.
Fragen zu Kapitel 16
-
Es gibt sequentielle Modi und binäre Modi.
Die sequentiellen Modi unterteilen sich noch einmal auf in den Lesezugriff (FOR INPUT
), den Schreibzugriff (FOR OUTPUT
) und einem Schreibzugriff zum Anhängen von Daten (FOR APPEND
). Der Lesezugriff erfordert eine bereits existierende Datei, wogegen die Schreibzugriffe bei Bedarf eine neue Datei anlegen. Beim ModusFOR OUTPUT
werden bereits existierende Daten gelöscht.
Als binären Modus gibt es das (starre und nicht mehr empfohlene)FOR RANDOM
und das universell einsetzbareFOR BINARY
. Im binären Modus kann auf die Daten an beliebiger Stelle sowohl lesend als auch schreibend zugegriffen werden. -
Es ist guter Programmierstil, alle Ressourcen, die man selbst öffnet, auch selbst wieder zu schließen. Besonders wichtig ist das allerdings innerhalb von Unterprogrammen sowie wenn sehr viele Dateien (kurzzeitig) geöffnet werden sollen. Außerdem werden Daten in der Regel erst dann tatsächlich auf den Datenträger geschrieben, wenn die Datei geschlossen wird (was bei einem Programmabsturz zum Datenverlust führt).
-
Der einzige wirklich ungeeignete Datentyp ist
INTEGER
, wenn das Programm sowohl auf 32-Bit- als auch 64-Bit-Systemen laufen soll. Ansonsten sind alle Zahlendatentypen gut geeignet. Zeichenketten fester Länge sind einfacher zu handhaben als Zeichenketten variabler Länge, allerdings lassen sich die Schwierigkeiten hier recht einfach lösen. -
Programmieraufgabe:
DIM AS STRING benutzername DIM AS INTEGER dateiNr = FREEFILE IF OPEN("letzerBenutzer.txt" FOR INPUT AS #dateiNr) THEN ' Fehler aufgetreten - Datei existiert moeglicherweise nicht PRINT "Dies scheint Ihr erster Besuch zu sein. Geben Sie Ihren Namen ein." INPUT benutzername ' Da die Datei nicht zum Lesen geoeffnet werden konnte, ist #dateiNr noch frei. OPEN "letzerBenutzer.txt" FOR OUTPUT AS #dateiNr PRINT #dateiNr, benutzername CLOSE #dateiNr ELSE ' kein Fehler - Datei konnte korrekt geoeffnet werden LINE INPUT #dateiNr, benutzername CLOSE #dateiNr PRINT "Hallo, " & benutzername & "!" PRINT "Wollen Sie Ihren Namen aendern? Geben Sie den neuen Namen ein! " PRINT "Wenn Sie den Namen nicht aendern wollen, druecken Sie nur RETURN." INPUT benutzername IF benutzername <> "" THEN ' Die Datei wurde oben geschlossen; #dateiNr ist wieder frei. OPEN "letzerBenutzer.txt" FOR OUTPUT AS #dateiNr PRINT #dateiNr, benutzername CLOSE #dateiNr END IF END IF
Fragen zu Kapitel 17
-
Absolute Pfadangabe beginnen unter Linux mit einem Slash
/
. Auch unter Windows werden Pfade, die mit einem Slash oder einem Backslash\
beginnen, als absolute Pfade ausgehend vom aktuellen Laufwerk interpretiert. Pfade, die mit einem doppelten Slash oder Backslash beginnen, werden als (absoluter) Netzwerkpfad behandelt.
Ansonsten beginnen unter Windows absolute Pfade mit dem Laufwerksbuchstaben gefolgt von einem Doppelpunkt. -
Der Rückgabewert
-1
bedeutet, dass das Verschieben fehlgeschlagen ist. Mögliche Gründe dafür sind, dass die Quelldatei nicht existiert, dass die Zieldatei bereits existiert oder auf den Zielpfad nicht zugegriffen werden kann, oder dass die Datei wegen fehlenden Rechten nicht verschoben werden kann. -
Programmieraufgabe:
#INCLUDE "vbcompat.bi" DIM attribute AS INTEGER, groesse AS STRING, dateiname AS STRING dateiname = DIR("*.*", fbNormal OR fbHidden OR fbDirectory, attribute) PRINT "Dateiname"; TAB(40); "Dateigroesse" DO WHILE LEN(dateiname) ' solange ein Eintrag gefunden wurde ' Kennzeichne versteckte Dateien durch graue Schrift IF attribute and fbHidden THEN COLOR 8 ELSE COLOR 15 END IF ' ermittle die Dateigroesse (Umwandlung zu einem String) groesse = STR(FILELEN(dateiname)) ' Gib den Dateinamen (bzw. Ordnernamen) aus IF attribute and fbDirectory THEN PRINT "* "; dateiname ELSE PRINT " "; dateiname; TAB(52 - LEN(groesse)); groesse END IF ' Suche nach dem naechsten Eintrag dateiname = DIR(attribute) LOOP SLEEP
Weitere Ideen zum Ausbau des Codes:
-
Sortierung nach Ordner und Dateien (erst alle Ordner, dann alle Dateien)
-
Auslagerung des Codes in eine Prozedur und rekursiver Aufruf zur Anzeige aller Unterordner
Fragen zu Kapitel 18
-
Countdown:
DIM AS INTEGER restzeit DIM AS DOUBLE zeit DIM AS STRING taste PRINT "Der Countdown laeuft! (Abbruch mit ESC)" FOR restzeit = 10 TO 1 STEP -1 PRINT restzeit; "..." zeit = TIMER DO IF INKEY = CHR(27) THEN EXIT FOR ' INKEY, da nicht gewartet werden soll SLEEP 1 LOOP UNTIL TIMER - zeit > 1 ' eine Sekunde vergangen NEXT IF restzeit >= 0 THEN PRINT "Countdown abgebrochen mit einer Restzeit von"; restzeit; " s." ELSE PRINT "START!" END IF SLEEP
-
Weihnachtsberechnungen:
#INCLUDE "vbcompat.bi" DIM AS INTEGER tage, wochen, minuten DIM AS DOUBLE heute = NOW ' heutiges Datum ' Berechne das Weihnachtsdatum dieses Jahres DIM AS DOUBLE weihnachten = DATESERIAL(YEAR(heute), 12, 25) ' Sollte Weihnachten schon vorbei sein, addieren wir ein Jahr hinzu IF weihnachten < heute THEN weihnachten = DATEADD("yyyy", 1, weihnachten) ' Ausgabe der gesuchten Informationen PRINT "Bis zum naechsten Weihnachtstag dauert es noch" PRINT DATEDIFF("d", heute, weihnachten) & " Tage, bzw." PRINT DATEDIFF("w", heute, weihnachten) & " Wochen, bzw." PRINT DATEDIFF("n", heute, weihnachten) & " Minuten." PRINT "Weihnachten faellt auf einen " & WEEKDAYNAME(WEEKDAY(weihnachten)) SLEEP
Fußnoten:
1) Wenn Sie die Genauigkeitsprobleme bei SINGLE
nachprüfen wollen, legen Sie doch einmal zwei SINGLE
-Variablen mit den Werten 1 000 000 000 und 999 999 999 an und berechnen Sie die Differenz.