Michael Neuhold Homepage
Startseite >
Informatikunterricht >
Weiterführung in Turbo Pascal
Prozeduren ruft man mit ihrem Namen auf:
ClrScr;
Writeln ('Hallo du da!');
Gotoxy (5,10);
Eigene Prozeduren deklariert man so:
PROCEDURE Name (Parameter: Typ); {Deklarationsteil: CONST, TYPE, VAR} BEGIN {Programmteil der Prozedur} END;
WriteLn (zahl)
oder WriteLn (1000)
).GotoXY (x , y)
).Ohne Parameter:
PROCEDURE Ausgabe; BEGIN WriteLn ('Ergebnis: ',wert); {wert muß eine globale Variable sein} END;
Mit Werteparameter:
PROCEDURE Ausgabe2 (wert: Real; KommaStellen: Byte); BEGIN DelLine; Write (wert:0:KommaStellen); {wert und KommaStellen sind jetzt die formalen Parameter} {aus der Kopfzeile} END;
Mit Variablenparameter:
PROCEDURE Eingabe (grenze: Integer; VAR wert: Integer); BEGIN WriteLn ('Ganze Zahl (max ',grenze,'): '); REPEAT GotoXY (10, WhereY-1); ClrEol; ReadLn (wert); UNTIL wert <= grenze; END;
Das Hauptprogramm dazu könnte etwa so aussehen:
PROGRAM QuadratBerechnung; USES crt; VAR zahl: Integer; PROCEDURE Eingabe (grenze: Integer; VAR wert: Integer); {s.o.} PROCEDURE Ausgabe2 (wert: Real; KommaStellen: Byte); {s.o.} BEGIN {Hauptprogramm} ClrScr; WriteLn ('Berechnung der Quadratzahl'); Eingabe (1000,zahl); {Aufruf der Prozedur Eingabe} Ausgabe2 (Sqr (zahl),0); {Aufruf der Prozedur Ausgabe2} END. {Hauptprogramm}
Funktionen liefern einen Wert. Funktionen verwendet man wie Variablen: (1) auf der rechten Seite einer Zuweisung, (2) als Parameter von Prozeduren und Funktionen, (3) in booleschen Ausdrücken.
Zuweisung | Parameter | Ausdruck |
---|---|---|
zeile:= WhereY; |
WriteLn (SqRt (zahl)); |
IF Sqr (zahl) < 100 THEN BEGIN |
Der Aufruf SqRt (100);
ergibt so wenig Sinn wie 10;
.
Eigene Funktionen deklariert man so:
FUNCTION Name (Parameter:Typ): ErgebnisTyp; {Deklarationsteil: CONST, TYPE, VAR} BEGIN {Programmteil der Funktion} Name:= Zuordnungsvorschrift; END;
Ohne Parameter:
FUNCTION Fertig: Boolean; VAR taste: Char; BEGIN GotoXY (5,25); Write ('Wiederholen [Return] Beenden [Escape]'); REPEAT taste:= ReadKey UNTIL taste IN [#13,#27]; IF taste=#27 THEN Fertig:= TRUE ELSE Fertig:= FALSE; END;
Mit Werteparameter:
FUNCTION Fahrenheit (celsius: Real): Real; BEGIN Fahrenheit:= celsius *9/5+32; END;
Das Hauptprogramm dazu könnte etwa so aussehen:
PROGRAM TemperaturUmrechnung; USES crt; VAR c: Real; FUNCTION Fertig: Boolean; {s.o.} FUNCTION Fahrenheit (celsius: Real): Real; {s.o.} BEGIN {Hauptprogramm} REPEAT ClrScr; Write ('Wieviel °C? '); ReadLn (c); WriteLn ('Das sind ',Fahrenheit (c),' F'); {Aufruf der Funktion Fahrenheit} UNTIL Fertig; {Aufruf der Funktion Fertig} END. {Hauptprogramm}
Was macht die folgende Funktion?
FUNCTION ziffer (z: Char): Integer; BEGIN ziffer:= Ord (z)-48; END;
Benutzerdefinierte und strukturierte Datentypen werden durch TYPE = (Definitionszuweisung mit Gleichheitszeichen!) definiert. Dann muß mit VAR eine Variablendeklaration erfolgen:
TYPE NeuerTyp = Typendefinition; VAR Variable: NeuerTyp;
Man kann Datentypen auch bei der Variablendeklaration definieren (VAR Variable: NeuerTyp;), doch können solche Variablen nicht als Prozedur- und Funktionsparameter verwendet werden, da im Prozedurkopf als Parameter nur einfache und vordefinierte Variablentypen auftreten dürfen.
TYPE Teilbereichstyp = Bereichsanfang..Bereichsende;
Beispiel: TYPE Lottozahlen = 1..45;
TYPE Aufzählungstyp = (Wert1, Wert2, Wert3);
Beispiel: TYPE Wochentage = (so, mo, di, mi, do, fr, sa);
Ein Array ist ein Feld gleichartiger Daten, bei dem das einzelne Datum durch seine Indexnummer angesprochen wird. Typendefinition:
TYPE ArrayTyp = ARRAY [FirstIndex..LastIndex] OF Datentyp;
FirstIndex und LastIndex müssen Konstanten eines
ordinalen Datentyps sein!
TYPE ZahlenReihe = ARRAY [1..100] OF Real;
oder
CONST anfang = 1; ende = 100;
TYPE ZahlenReihe = ARRAY [anfang..ende] OF Real;
Index | [1] | [2] | [3] | [4] | [5] | [6] | [7] | [8] | [9] | [10] |
---|---|---|---|---|---|---|---|---|---|---|
Inhalt | 1.7 | 4.2 | -32.0 | 17.2 | 0.12 | 4.79 | -3.1 | 14.61 | 0.147 | -9.2 |
WriteLn (ZReihe[20]);
{Typenname und Variablenname müssen
verschieden sein}FOR index:= FirstIndex TO LastIndex DO WriteLn (ZReihe [index]);
Die häufigsten Operationen auf Arrays sind:
merk:= feld [index]; {in Hilfsvariable zwischenspeichern} feld [index]:= feld [index+1]; {mit Wert des Nachbarelementes überschreiben} feld [index+1]:= merk; {gespeicherten Wert auf Nachbarelement zurückschreiben}
FOR index:= actual TO last-1 DO {last ist der Index des letzten Elementes} feld [index]:= feld [index+1]; {actual ist der Index jenes Elementes,} last:= last-1; {das aus dem Array entfernt werden soll}
FOR index:= 1 TO last-1 DO IF feld [index] > feld [index+1] {wenn Nachbarelement größer, dann vertauschen} THEN vertauschen; {so wandert das größte Element nach oben}
Man kann einem Array einen ganzen Array desselben Typs zuweisen:
TYPE LottoSchein = ARRAY [1..45] OF Boolean; VAR Tip1, Tip2: LottoSchein; Tip1:= Tip2;
Vergleiche müssen jedoch elementeweise erfolgen, ein Ausdruck wie
IF Tip1=Tip2 THEN...
ist nicht möglich.
Der Typ String ist eigentlich ein ARRAY [0..255] OF Char, das 0-te Byte enthält die aktuelle Stringlänge:
[0] | [1] | [2] | [3] | [4] |
#4 | 'H' | 'a' | 'n' | 's' |
VAR s: String; i: Byte; FOR i:= 1 TO Length (s) DO {bei allen Zeichen des Strings s} s [i]:= UpCase (s [i]); {das i-te Zeichen durch den entspr. Großbst. ersetzen}
TYPE Reihe = ARRAY [first..last] OF Datentyp;
TYPE Feld = ARRAY [erstes..letztes] OF Reihe;
TYPE Feld = ARRAY [erstes..letztes] OF ARRAY [first..last] OF Datentyp;
TYPE Feld = ARRAY [first..last, erstes..letztes] OF Datentyp;
WriteLn (ZFeld [3,5]);
TYPE ScreenType = ARRAY [1..80,1..25] OF Char; VAR Screen: ScreenType; FOR x:= 1 TO 80 DO FOR y:= 1 TO 25 DO Screen [x,y]:=' '; {Leerzeichen = Löschen}
[1,1] | [2,1] | [3,1] | [4,1] | ... |
[1,2] | [2,2] | [3,2] | [4,2] | ... |
[1,3] | [2,3] | [3,3] | [4,3] | ... |
[1,4] | [2,4] | [3,4] | [4,4] | ... |
[1,5] | [2,5] | [3,5] | [4,5] | ... |
... | ... | ... | ... | ... |
Ein Datensatz, dessen Datenkomponenten unterschiedlichen Datentyps sein können:
TYPE DatenSatz = RECORD Komponentenname1: Datentyp; Komponentenname2: Datentyp; Komponentenname3: Datentyp; END;
TYPE PersDaten = RECORD name: String[30]; kontonr: LongInt; bruttoeinkommen: Real; angestellter: Boolean; END; VAR kunde: PersDaten;
WriteLn (kunde.kontonr)
.WITH kunde DO BEGIN ReadLn (name); ReadLn (kontonr); ReadLn (bruttoeinkommen); END;statt
ReadLn (kunde.name); ReadLn (kunde.kontonr); ReadLn (kunde.bruttoeinkommen);
TYPE person = RECORD nachname: String[20]; vorname: String[15] END; ktoverb = RECORD bank: String[20]; ktonr, blz: LongInt END; mitarbeiter = RECORD name: person; konto: ktoverb END; VAR abtlgleiter: mitarbeiter; abtlgleiter.konto.bank:= 'PSK'; ReadLn (abtlgleiter.konto.blz); WriteLn (abtlgleiter.name.nachname);
WITH abtlgleiter,konto DO BEGIN bank:= 'PSK'; blz:= 60000; END;statt
WITH abtlgleiter DO WITH konto DO BEGIN bank:= 'PSK'; blz:= 60000; END;
filialleiter:= abtlgleiter;
), vergleichen kann man Records
aber nur komponentenweise.TYPE kunde = RECORD name: String [80]; adresse: String [100]; ktostand: Real END; kundenliste = ARRAY [1..1000] OF kunde; VAR aboliste: kundenliste; PROCEDURE GetNeuKunde (KundenNr: Word); BEGIN WriteLn ('Daten des Kunden Nr. ',KundenNr); Write ('Name: '); ReadLn (aboliste [KundenNr].name); Write ('Adresse: '); ReadLn (aboliste [KundenNr].adresse); aboliste [KundenNr].ktostand:= 0; END;oder besser:
WITH aboliste [KundenNr] DO BEGIN Write ('Name: '); ReadLn (name); Write ('Adresse: '); ReadLn (adresse); ktostand:= 0; END;
TYPE Faecher = (D,E,L,M,GS,GW,Ph,Ch,BU,BE,ME,LUe); Noten = 1..5; Beurtlg = ARRAY [D..LUe] OF Noten; Schueler = RECORD name: String [60]; semnote, jahresnote: Beurtlg; {Array als Recordkomponente} END; Klasse = ARRAY [1..36] OF Schueler; {Array aus Records} VAR klassenbester: Schueler; _5A, _5B: Klasse; {Variablenbezeichner dürfen nicht mit einer Ziffer beginnen} klassenbester.semnote [M]:= 1; _5A [1].name:= 'Aldrich Karin'; _5B [21].jahresnote [L]:=4;Folgende Prozedur gibt für jeden Schüler der _5A Namen und Notendurchschnitt aus:
VAR last,nr: Byte; f: Faecher; summe, durchschnitt: Real; BEGIN FOR nr:= 1 TO last DO WITH _5A [nr] DO BEGIN Write (name,': '); summe:=0; FOR f:= D TO LUe DO summe:= summe+jahresnote [f]; durchschnitt:= summe/12; {Datentyp Faecher besteht aus 12 Elementen} WriteLn (durchschnitt:2:2); END; END;
Datentyp zum Übertragen von Daten von einem Gerät zum anderen (in erster Linie von und zu Disk).
Allen Filetypen gemeinsam ist, daß zuerst ihr "physikalischer"
Name einer Dateivariablen zugeordnet werden muß: ASSIGN (Dateivariable,
'Dateiname'): ASSIGN (datenbank, 'C:\PASPROGS\DATABASE.DAT')
.
Dateiname ist ein String, der den Namen der Datei, (optional) den
Pfad und (optional) das Laufwerk enthält. Fehlen die Angabe des
Laufwerks und des Pfads, werden das aktuelle Laufwerk und das aktuelle
Verzeichnis verwendet.
Files eines bestimmten Datentyps; auf die einzelnen Datenkomponenten kann wahlfrei zugegriffen werden (sog. Random Access Files). Typendefinition:
TYPE Dateityp = FILE OF Datensatztyp;
TYPE kunde = RECORD name, str, ort: String [30]; ktostand: Real; END; KundenDatei = FILE OF kunde; VAR ku: kunde; KuDat: KundenDatei; DatName: String; Write ('Dateiname: '); ReadLn (DatName); Assign (KuDat, DatName);
Reset (KuDat); {vorhandene Datei öffnen}
Read (KuDat, ku); {ersten Datensatz in die Variable ku einlesen}
WHILE NOT Eof (KuDat) DO BEGIN Read (KuDat, ku); Ausgabe (ku); {benutzerdefinierte Prozedur zur Ausgabe des Records ku} END;Versucht man, über das Dateiende hinaus Daten zu lesen, erfolgt Programmabbruch!
Reset (KuDat); {Positionszeiger auf 0 setzen} size:= FileSize (KuDat); FOR i:= 1 TO size DO {i und size vom Typ LongInt} BEGIN Read (KuDat, ku); Ausgabe (ku); END;
WriteLn ('Welchen Datensatz lesen: '); ReadLn (SatzNr); Seek (KuDat, SatzNr); Read (KuDat, ku); {Datensatz lesen, das setzt den Positionszeiger um eins weiter...} Ausgeben (ku); Aendern (ku); {benutzerdefinierte Prozedur zum Ändern eines Datensatzes} Seek (KuDat, SatzNr); {...daher muß Positionszeiger neuerlich gesetzt werden} Write (KuDat,ku); {geänderten Datensatz zurückschreiben}Um Datensätze an eine Datei anzuhängen, muß man den Positionszeiger ans Dateiende setzen:
Seek (KuDat, FileSize (KuDat));
Werden zeilenweise gelesen und geschrieben. Da die Zeilen unterschiedlich lang sein können, ist nur sequentieller Zugriff möglich (Zeilenendekennung ist die Sequenz #13#10 [Carriage Return + Line Feed]). Der Dateityp Text ist bereits vordefiniert.
VAR f: Text; s: String; BEGIN WriteLn ('Name der Textdatei: '); ReadLn (s); Assign (f,s); Reset (f); WHILE NOT Eof (f) DO BEGIN ReadLn (f,s); {Zeile von Datei einlesen} WriteLn (s); {und auf Bildschirm ausgeben} END; END.
Dienen zum Übertragen von Daten ungeachtet ihres Inhaltes. Das Übertragen kann nur blockweise stattfinden. Typendefinition:
TYPE UntypisierteDatei = FILE;
PROGRAM CopyFile; {Simple, fast file copy program with NO error-checking - aus der Online-Hilfe} {Aufruf: CopyFile Quelldatei Zieldatei, die Kommandozeilenparameter werden mit der Funktion} {ParamStr (n-terParameter) übernommen} VAR FromF, ToF: FILE; {untypisierte Dateien} NumRead, NumWritten: Word; Buf: ARRAY [1..2048] of Char; {Puffervariable} BEGIN Assign(FromF, ParamStr(1)); {erster Parameter = Quelldatei, öffnen} Reset(FromF, 1); {Blockgröße = 1} Assign(ToF, ParamStr(2)); {zweiter Parameter = Zieldatei, öffnen} Rewrite(ToF, 1); {Blockgröße = 1 } WriteLn('Copying ', FileSize(FromF), ' bytes...'); REPEAT BlockRead(FromF, Buf, SizeOf(Buf), NumRead); {Lesen} BlockWrite(ToF, Buf, NumRead, NumWritten); {Schreiben} UNTIL (NumRead = 0) {bis alle Blöcke gelesen} OR (NumWritten <> NumRead); {oder Übertragungsfehler} Close(FromF); Close(ToF); {Schließen nicht vergessen!} END.
Wenn versucht wird, nicht vorhandene Dateien zu öffnen, Dateien in nicht vorhandenen Verzeichnissen anzulegen, über das Dateiende hinaus auf Datensätze zuzugreifen, vom Diskettenlaufwerk zu lesen, obwohl keine Diskette eingelegt ist, o.ä., kommt es zu einem Laufzeitfehler = Programmabbruch (und meist auch Datenverlust).
Assign (recfile, filename); {$I-} Reset (recfile); {$I+} ErrCode:= IOResult; IF ErrCode = 0 THEN BEGIN ... END ELSE WriteLn ('Error #', ErrCode, ' -File not found!');
Die Unit DOS stellt einige Prozeduren und Funktionen zum Umgang mit externen Dateien bereit.
TYPE SearchRec = RECORD Fill: array[1..21] of Byte; {von DOS reserviert, Funktion unklar} Attr: Byte; Time: Longint; Size: Longint; Name: string [12]; END;Attribute ist vom Typ Word und enthält die Summe der Dateiattributkonstanten:
Konstante | Wert | h/d |
ReadOnly | $01 | 1 |
Hidden | $02 | 2 |
SysFile | $04 | 4 |
VolumeID | $08 | 8 |
Directory | $10 | 16 |
Archive | $20 | 32 |
AnyFile | $3F | 63 |
Um z.B. die versteckten und die Systemdateien zu finden, trägt man bei Attribute ein: Hidden+SysFile, oder: 6 (= 4+2). AnyFile ist einfach die Summe aller anderen Konstanten.
USES dos; VAR DirInfo: SearchRec; BEGIN FindFirst('*.PAS', Archive, DirInfo); {finde erstes PAS-File im aktuellen Verzeichnis} WHILE DosError=0 DO {mit gesetztem Archiv-Bit} BEGIN WriteLn(DirInfo.Name); FindNext(DirInfo); END; END.
USES dos; VAR path: PathStr; {String [79]} dir: DirStr; {String [67]} name: NameStr; {String [8]} ext: ExtStr; {String [4], der Punkt gehört also zur Extension} BEGIN Write ('Filename (WORK.PAS): '); ReadLn (path); FSplit(path, dir, name, ext); IF name='' THEN name:= 'WORK'; IF ext='' THEN ext:= '.PAS'; path:= dir+name+ext; WriteLn ('Resulting name is ', path); END.
Weitere Details dazu sehe man in der Online-Hilfe nach:
Autor: E-Mail-Kontakt)
Letzte Aktualisierung: 10. Juni 2024