Hallo Marc,
die Sache mit dem Dateiformat (Stichwort „typisierte Datei“) hast Du ja schon von Jochen erklärt bekommen.
Du lässt alle Schleifen von 0 bis Konstante-1 ablaufen. Was
für Vorteile hat das?
Ein einstelliger Dezimalzähler kann 10 verschiedene Zustände annehmen, nämlich „0“, „1“, „2“, „3“, „4“, „5“, „6“, „7“, „8“ und „9“. Somit „zählt“ er nicht von 1 bis 10, sondern von 0 bis 9. Ein zweistelliger Dezimalzähler kann 100 verschiedene Zustände annehmen, und zwar „00“, „01“, „02“… „98“, „99“. Er zählt also von 0 bis 99.
Computer funktionieren mit dualen Zählern (Basis 2), aber auch die zählen von Null ab. Von 0 bis 255 zählt ein Byte-Zähler (acht Bits), von 0 bis 65535 zählt ein 16-Bit-Zähler, und von 0 bis 1 kann ein einstelliger Dualzähler „zählen“.
Fazit: Die „natürliche“ Art zu zählen ist, bei Null anzufangen, nicht bei Eins, wie es die Menschen gemeinhin tun. Alle (guten) Programmierer halten sich deshalb an die sinnvolle (!) Konvention, Schleifen immer von „0“ bis „N – 1“ laufen zu lassen. Wenn eine Schleife zwölf mal durchlaufen werden soll, dann sollte dies
also nicht so:
FOR i := 1 TO 12 DO ...
und auch nicht so:
FOR i := 0 TO 11 DO ...
sondern so programmiert werden:
CONST N = 12;
...
FOR i := 0 TO N-1 DO ...
Diesen Stil solltest Du Dir frühzeitig angewöhnen. Auf den ersten Blick sieht das sicher etwas „seltsam“ aus, aber Du wirst es schnell verinnerlicht haben. Fortan wird Dir dann ein „FOR k := 1 TO 1000 DO“ in fremdem Code sofort ins Auge springen („Hoppla, da war ein Laie am Werk!“). Irgendwann wirst Du vielleicht auch auf Funktionen aus Codebibliotheken zurückgreifen; spätestens dann sollte Dir in Fleisch und Blut übergegangen sein, daß das erste Element eines Arrays den Index Null hat („a[0]“) und das n-te Element den Index n – 1 („a[n–1]“).
Muss ich alle Dateipfade, deren zugehörigen Daten ich zu
verwenden gedenke zu Beginn als Konstante definieren, oder
würde es auch genügen im ASSIGN Befehl den Dateipfad zu
nennen?
Der Compiler hat nichts dagegen, wenn Du den Dateipfad direkt in den Assign-Befehl schreibst (wie Du durch Ausprobieren leicht feststellen kannst), aber Du solltest etwas dagegen haben!
Warum? Nehmen wir an, Du möchtest den Benutzer des Programms noch durch eine Meldung informieren, daß die Ausgabe auch in die besagte Datei geschrieben wurde. Das sähe dann so aus:
begin
Assign(f, 'UMSAETZE.TXT');
ReWrite(f);
FOR ... TO ... DO
begin
...
end;
Close(f);
WriteLn('Ausgabe wurde in die Datei "UMSATZE.TXT" geschrieben!");
end;
Vielleicht gibt es noch weitere Aktionen, an denen die Datei „UMSAETZE.TXT“ beteiligt ist. Niemand verbietet Dir, den Namen jedes mal „direkt“ dorthin zu schreiben, wo er gebraucht wird. Nur: Dein Programm umfaßt eventuell irgendwann mal 4000 (oder auch 40000) Codezeilen, und 29 mal steht darin „verstreut“ an allen möglichen und unmöglichen Stellen der String „UMSAETZE.TXT“. Es ist unterdessen auch so leistungsfähig geworden, daß der Name „UMSATZE.TXT“ gar nicht mehr paßt, und Du ihn in „BILANZ.TXT“ abändern willst. Dann bleibt Dir nichts anderes übrig, als Deinen Code nach allen 29 Einträge zu durchforsten, um sie dann alle zu ändern. Klar, das geht auch automatisch mit Suchen&Ersetzen. Aber: 4 von den 29 Einträgen werden sich vielleicht in einer anderen Datei befinden (der Code eines Programms kann auf mehrere Dateien aufgeteilt werden, z. B. Include-Dateien oder Units), und Du kannst nicht ausschließen, einen davon aus irgendeinem „ganz dummen“ Grund zu übersehen. Und schwupps, hast Du einen hübschen Bug im Programm. Was Du möglicherweise erstmal gar nicht gar bemerken wirst. Wenn sich ein Benutzer Deines Programs dann drei Wochen später beschwert, daß da was nicht stimmt, und Du anfangen mußt, über den Grund dafür nachzudenken (während Du schon am nächsten Projekt arbeitest), hast Du die „banale“ Suchen&Ersetzen-Aktion natürlich längst vergessen.
Erfahrene Programmierer wissen, daß „direktes Hineinschreiben“ von z. B. Dateinamen in Code Fehler der beschriebenen Art geradezu provozieren. Und wer sich mal über ein (zwei, drei…) Stündchen mit mühsamer, lästiger und frustrierender Fehlersuche verschwendete Zeit ärgern durfte (und intelligent genug ist, daraus zu lernen), wird künftig nie wieder
begin
Assign(f, 'UMSAETZE.TXT');
ReWrite(f);
FOR ... TO ... DO
begin
...
end;
Close(f);
WriteLn('Ausgabe wurde in die Datei "UMSATZE.TXT" geschrieben!");
end;
sondern immer
CONST
FILNAME = 'UMSAETZE.TXT';
~
begin
Assign(f, FILENAME);
ReWrite(f);
FOR ... TO ... DO
begin
...
end;
Close(f);
WriteLn('Ausgabe wurde in die Datei '+FILENAME+' geschrieben!");
end;
schreiben. In der zweiten, „guten“ Version ist die Gefahr durch 29 verstreute Dateinamen prinzipiell eliminiert. Und Du hast es auch viel leichter, möchtest Du statt „UMSAETZE.TXT“ mal „BILANZ.TXT“ haben: Die Änderung einer einzigen Zeile (der CONST-Zeile) genügt. Ein minimaler Aufwand bringt hier einen Riesengewinn in punkto Sicherheit, und das ist gar nicht hoch genug einzuschätzen. Programmieren ist nämlich von Haus aus ein so fehleranfälliges Geschäft, daß man einfach jede Möglichkeit, Fehler (und damit möglicherweise eine unnötige und sehr teure spätere Fehlersuche) von vornherein zu vermeiden, unter allen Umständen ausnutzen muß. Dateinamen aus Code „herauszuhalten“ zählt deshalb zu den Selbstverständlichkeiten guten Programmierens. Profis gehen übrigens noch viel weiter: Sie halten sogar alle Zahlenkonstanten – bis auf „0“ und „1“ – peinlich sorgfältig aus ihrem Code heraus. Sie würden also nicht schreiben (nur als Beispiel):
Jahreslohn := 220 \* Tageslohn;
sondern
CONST
ARBEITSTAGPROJAHR = 220;
...
Jahreslohn := ARBEITSTAGPROJAHR \* Tageslohn;
Und noch etwas: Es gibt keine untere Grenze für die Größe eines Programms, unterhalb derer sich das Beherzigen dieses Tips nicht lohnen würde. Der Einwand „Mein Gott, mein Proggi hat lächerliche 200 Zeilen, da werde ich doch nicht mit „CONST FILENAME = …“ anfangen“, gilt nicht! Es ist auch bei einem Programm mit 10 (ja, 10!) Zeilen sinnvoll.
Vielleicht noch ein paar Tips zur Code-Stilistik:
- Schalte das Syntax-Highlighting Deines Editors ein. Bewährt hat sich unter anderem folgendes Farbschema:
Schlüsselwörter grün, Strings + Zahlkonstanten rot, Kommentare hellgrau, Inline-Assemblercode weiß oder pink, alles andere gelb. Hintergrund dunkelblau.
Rotdarstellung von Strings und Zahlkonstanten hat den Vorteil, daß man es sich dann zur Aufgabe machen kann, alles (bis auf „0“ und „1“) was rot wird, in CONST-Teile „auszulagern“.
-
Schreibe die Pascal-Schlüsselwörter durchgehend groß:
PROGRAM, UNIT, CONST, VAR, FOR, TO, DO, PROCEDURE, FUNCTION…
Ausgenommen:
begin
end
-
Schreibe Konstanten (= alles, was mit „CONST“ vereinbart wurde) ebenfalls durchgehend groß.
-
Schreibe Namen von Variablen und Namen von Prozeduren und Funktionen gemischt: WriteLn, Assign, AusgabeInDatei, Berechnen.
-
Aufeinanderfolgende Prozeduren und Funktionen kann das Auge viel besser voneinander abgrenzen, wenn man ihm mit Trennern wie
(* *************************************************** *)
dabei hilft.
-
Keine Leerzeichen bei Klammern:
„(a, b, c, d)“; nicht: „( a, b, c, d )“
-
nach Kommas ein Leerzeichen:
„(a, b, c, d)“; nicht: „(a,b,c,d)“
-
vor und nach Zuweisung „:=“ ein Leerzeichen:
„a := b“; nicht: „a:=b“
-
bei Vergleichsoperatoren kein Leerzeichen:
„IF (a=b) OR (cd) THEN…“; nicht: „IF (a = b) OR (c d) THEN…“
-
bei Rechenzeichen kann man Leerzeichen verwenden oder nicht:
„p-q+r-s“, „a*x*x*x + b*x*x + c*x + d“
-
Einrücktiefe genau zwei Zeichen. Das Einrücken sollte so vorgenommen werden:
FOR i := 0 TO N-1 DO
begin
TueIrgendwas(i);
TueNochIrgendwasAnderes(i)
BeendeTuen(i)
end;
Nicht:
FOR i := 0 TO N-1 DO
begin
TueIrgendwas(i);
TueNochIrgendwasAnderes(i)
BeendeTuen(i)
end
und nicht:
FOR i := 0 TO N-1 DO
begin
TueIrgendwas(i);
TueNochIrgendwasAnderes(i)
BeendeTuen(i)
end
und auch nicht (brrr… schrecklich):
FOR i := 0 TO N-1 DO
begin
TueIrgendwas(i);
TueNochIrgendwasAnderes(i)
BeendeTuen(i);
FOR k := 0 TO TOTALCOUNT-1 DO
begin
TueWasNeues(i, k)
...
end
end
Manche Programmierer pflegen folgenden Einrückstil:
FOR i := 0 TO N-1 DO begin
TueIrgendwas(i);
TueNochIrgendwasAnderes(i)
BeendeTuen(i)
end;
Darüber kann man sich streiten. Mir gefällt es überhaupt nicht, weil ich finde, daß das „begin“ es nicht verdient hat, in die hinterletzte Ecke geschrieben zu werden, wo es doch mit dem „end“ logisch auf derselben Stufe steht. Ich sehe jedenfalls keinen Grund, es nicht auch optisch auf dieselbe Stufe zu stellen:
FOR i := 0 TO N-1 DO
begin
TueIrgendwas(i);
TueNochIrgendwasAnderes(i)
BeendeTuen(i)
end;
So, das soll mal genügen (sorry, so viel wollte ich eigentlich gar nicht schreiben).
Mit freundlichem Gruß
Martin