Zeiger


Bevor wir zu den anderen Dateitypen (Binary und Random Access) kommen, müssen wir uns mit "Zeigern" beschäftigen. "Zeiger " sind ein Programmierkonzept, ähnlich wie Unterprogramme oder Arrays. Zeiger tauchen fast überall in der Computerwelt auf - im Zusammenhang mit höheren Programmiersprachen, mit Datenbanken, mit Webseiten. Denn die Links von Webseiten sind im Grunde genommen auch nichts anderes als Zeiger.

In höheren Programmiersprachen gibt es Zeiger auf Variablen als eingebautes Sprachelement. Skriptsprachen fehlt so etwas. QBASIC auch. (Das hat nicht nur Nachteile!) Aber wie gesagt: Zeiger sind ein Programmierkonzept und so kann man Zeigermechanismen auch in QBASIC-Programmen einsetzen. Und das wollen wir jetzt mal tun.

Was sind Zeiger?

Zeiger sind Adressen von Daten. Sozusagen ihre Ortsangabe. Ein Verweis darauf (daher ist ein Weblink auch nichts anderes als ein Zeiger). Wir können in der Websprache sagen: Wir befassen uns mit "Links". Nur dass diese Links auf Daten und nicht auf Webseiten verweisen.

Eine ganz einfache Form eines Zeigers können wir uns verschaffen, wenn wir Arrays benutzen. Nehmen wir an, wir verwalten eine Postadressentabelle der Form DIM adr$(N,3). adr$(i,0) ist der Name, adr$(i,1) ist die Strasse und adr$(i,2) ist der Ort der i-ten Postadresse, die wir abspeichern. Nehmen wir nun an, wir wollen ein Unterprogramm schreiben, dass alle Einträge einer Postadresse, also Name, Strasse und Ort in Grossbuchstaben umwandelt. Es gibt nun zwei Möglichkeiten, dem Unterprogramm seine Strings zu übergeben.

  1. Wir kopieren dem Unterprogramm die Postadresseinträge in extra Stringvariablen. Also
    nam$=adr$(i,0)
    strass$=adr$(i,1)
    ort$=adr$(i,2)
    gosub grossbuch
    adr$(i,0)=nam$
    adr$(i,1)=strass$
    adr$(i,2)=ort$
    
    Das nennt man eine Übergabe by value. Wir übergeben die Werte selbst in eigene Bearbeitungsvariablen. Ändert die Routine etwas an den Bearbeitungsvariablen, müssen wir den Inhalt der Bearbeitungsvariablen erst noch explizit wieder zurück in die eigentlichen Variablen zurückkopieren.
  2. Wir übergeben dem Unterprogramm einfach den Index i. i ist dabei selbst so etwas wie eine Hausnummer, die der Routine sagt: "Bitte, hier steht der Postadresseneintrag, mit dem du arbeiten sollst!" Eben ein Zeiger auf den richtigen Arrayeintrag. Wir brauchen also nur eine Übergabevariable, nämlich i0 für den zu bearbeitenden Index i:
    i0=i
    gosub grossbuch
    
    grossbuch nimmt dann den Eintrag mit Index i0 und bearbeitet ihn. Das nennt man eine Übergabe by reference. Die "Referenz" ist praktisch der Zeiger. Der Nachteil dieses Verfahrens: Der Code von grossbuch muss adr$() kennen, ist also nicht universal auf drei Strings anwendbar.

Das Hantieren mit Zeigern u.a. dann von grossem Interesse, wenn man es mit grossen Datenstrukturen zu tun hat und nicht bei jeder Gelegenheit den Inhalt der ganzen Datenstruktur (oder Teile davon) übergeben können, wie wir das mit einzelnen Variablen tun.

Das beste Übungsbeispiel ist die Programmierung eines Editors. Überlegen Sie sich einmal, wie Sie das machen würden!

Programmierung eines Editors

Einen Editor kann man schon dann gut gebrauchen, wenn man in einem eigenen Programm den Benutzer einen eigenen kleinen Text in ein Feld auf dem Bildschirm eintragen lassen will. Eigentlich ganz easy. Der Text ist natürlich ein String-Array. Die Cursorbewegung bedeutet einfach, die Position innerhalb des Arrays (Zeile) und innerhalb des Strings (Spalte) zu ändern. Sehr schön. Und nun fügen wir am Anfang eine neue Zeile ein...

Merken Sie was? Wenn der User anfängt, irgendwo mitten im Text Zeilen einzufügen, dann muss jedesmal, wenn er einen Zeilenwechsel macht, der Inhalt des gesamten Arrays nach hinten verschoben werden! Damit vorne wieder eine Zeile Platz hat. Das ist natürlich schlecht. Weil das dauert und der User auf seinen zeilenwechsel nicht eine halbe Minute warten müssen soll. Ich hatte mal einen Mini-PC, bei dessen Editor das so war. Der Editor war nur für Texte bis zu 5K zu gebrauchen, also 2, 3 DinA4-Seiten. Danach wurde er bei jedem Zeilenwechsel so langsam, dass man besser eine neue Datei anlegte...

Sie können sich überlegen, wie Sie das lösen wollen. Wenn Sie eine saubere Lösung wollen und lange genug darüber nachgedacht haben, werden Sie schliesslich auf folgenden Weg kommen:

Beispiel einer Indextabelle: Die rechte Spalte gibt die Indexnummer im String-Array an, die linke Nummer die Zeilennummer, an der der String erscheinen soll. Finden Sie heraus, wie der Text zustande kam! Welche Zeilen hat der User zuerst eingegeben, wo hat er dann Text eingefügt?

Man könnte die Indextabelle natürlich auch andersherum sortieren: Die Zeilen in der richtigen Reihenfolge und die Arrayindizes entsprechend umsortiert. Das kommt auf das gleiche heraus. Wichtig ist nur: Die Indizies stellen Zeiger auf den eigentlichen Speicherinhalt, die Strings dar.

Übung: Schreiben Sie einen kleinen Editor für QBASIC mit bis zu 255 Zeichen Breite und einem schnellen Zeilenmanagement!