Entwickler-Ecke
Sonstiges (Delphi) - Variablen und Rekursion
MK777 - Sa 06.11.10 00:22
Titel: Variablen und Rekursion
Hallo, ich schreibe am nächsten Montag eine Kursarbeit in Informatik. Leider verstehe ich manche Sachen nicht ganz und hoffe, dass ihr mir helfen könnt.
1.) Wenn ich eine Prozedur oder Funktion programmieren möchte, muss ich dabei betsimmte Variablen aus dem Hauptprogramm "importieren" (damit meine ich die erste Zeile der Prozedur).
Bei einer Variable gibt es zwei Möglichkeiteb:
Delphi-Quelltext
1:
| procedure bsp(x: integer); |
und
Delphi-Quelltext
1:
| procedure bsp(var x: integer); |
Wo ist der Unterschied?
Bei zwei Variablen gibt es jedoch vier Möglichkeiten:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8:
| procedure bsp(x: integer; y: integer);
procedure bsp(x: integer; var y: integer);
procedure bsp(x,y: integer);
procedure bsp(x: integer); var y: integer; |
Kann mir jemand den Unterschied erklären und wie sich jeweils die einzelnen Konstellationen auf die Prozedur auswirken?
Des Weiteren habe ich hier einen Ausschnitt aus einem Programm, dass aus einem Wort ein Palindrom erstellt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| var eingabe, ausgabe: string;
procedure mach_es(position: integer); var buchstabe: char; begin buchstabe := eingabe[position]; ausgeben := ausgabe + buchstabe; if position < length(eingabe) then mach_es(position + 1); ausgabe := ausgabe + buchstabe; end;
procedure TForm1.Button1Click(Sender: TObject); begin label2.caption := ' ': eingabe := Form1.Edit1.Text; ausgabe := ' '; mach_es(1); label2.caption := ausgabe; end; |
Sobald die Prozedur "mach_es" aufgerufen wird, bekommt die Variable "position" den Wert 1.
Doch dann steht da "buchstabe := eingabe[position];". Ich habe keine Ahnung was hier passiert. :shock: Was bedeuten die eckigen Klammern?
Ich würde mich freuen, wenn mir jemand das Programm in einfachen Schritten erklären könnte.
Leider bin totaler Anfänger und blicke noch bie vielen Sachen nicht so richtig durch. :oops:
Bitte um Hilfe. Vielen Dank im Voraus für die Mühe.
Moderiert von
Martok: Delphi-Tags gesetzt
BenBE - Sa 06.11.10 01:38
Bitte immer nur eine Frage pro Thread. Ich beantworte daher hier nur die erste. Es wird sonst zu unübersichtlich. Auch solltest Du für Code-Abschnitte den Delphi-Tag nutzen, da es dadurch wesentlich lesbarer wird.
Okay. Zu den Variablen sollte man wissen, dass Du in deinen Beispielen gerade Variablen (lokale, globale) und Parameter durcheinander gehauen hast. Während Variablen Werte speichern, werden mit Parametern Werte an andere Programmteile übergeben, damit diese etwas mit diesen anstellen können. Etwa so wie das x bei einer quadratischen Funktion
f(x)=x^2-1 an die Funktion f übergeben wird.
Je nach Notationsort legst Du in deinem Programm einen Parameter oder eine Variable an:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| unit Foo;
interface
var InterfaceGlobal: Integer;
implementation
var ImplementationGlobal: Integer;
procedure Bar(StdParameter:Integer; const ConstParameter: integer; var VarParameter: Integer; out OutParameter: Integer); var LocalVariable: Integer; begin LocalVariable := StdParameter + ConstParameter; StdParameter := StdParameter + 1; VarParameter := StdParameter + VarParameter; OutParameter := VarParameter + LocalVariable; end;
end. |
InterfaceGlobal: Globale Variable, die auch in fremden Units überall sichtbar ist, wenn diese Unit eingebunden wird
ImplementationGlobal: Überall in der aktuellen Unit sichtbar
LocalVariable: Nur innerhalb von
Bar sichtbar.
Zu den Parameter-Typen (Nicht wundern, dass Du viele noch nicht kennen wirst):
StdParameter: Veränderbar, aber Änderungen nur lokal in Bar sichtbar
ConstParameter: Konstant und Wert auch in Bar nicht veränderbar
VarParameter: Wie Std, jedoch werden Änderungen auch außerhalb von Bar sichtbar
OutParameter: Wie Var, jedoch ist der Wert bei Betreten von Bar undefiniert.
Allgemein gilt aber, unabhängig davon, was Du für einen Parameter hast, dass dieser immer nur innerhalb von der Prozedur oder Funktion gültig ist, wo dieser definiert wurde, bzw. in untergeordneten Prozeduren/Funktionen (das hat was mit der Syntax zu tun und ist hier nicht weiter wichtig, ggf. vgl. Scoping).
HTH.
Tranx - Sa 06.11.10 07:22
Ich versuche es mit der zweiten Frage. Zum Ersten, bitten einen Quelltext immer mit den reservierten Worten {delphi} ... {/delphi} (in eckigen Klammern!) eingrenzen. Dann ist der Quelltext besser vom restlichen Text zu unterscheiden:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22:
| var eingabe, ausgabe: string;
procedure mach_es(position: integer); var buchstabe: char; begin buchstabe := eingabe[position]; ausgeben := ausgabe + buchstabe; if position < length(eingabe) then mach_es(position + 1); ausgabe := ausgabe + buchstabe; end;
procedure TForm1.Button1Click(Sender: TObject); begin label2.caption := ' '; eingabe := Edit1.Text; ausgabe := ' '; mach_es(1); label2.caption := ausgabe; end; |
Also das Programm ruft beim Click auf den Button die Prozedur mach_es auf, welche dann sich selber solange wieder aufruft, bis der Parameter die Länge des im Editfeld angegebenen Textes erreicht hat. Das nennt man rekursive Prozeduraufrufe.
Wie das Programm das Ganze abarbeitet, kannst Du am Besten daran sehen, wenn Du in dem Programm einen Haltepunkt setzt. Und zwar in der Zeile "Ausgabe :=". Das Programm behält die Informationen für die Variable Buchstabe (lokale Variable der Prozedur mach_es) bei jedem Aufruf bei. Und gibt diese Variable am Ende der Bedingung - Position = Length(Eingabe) - der Reihe nach wieder aus. Das Ergebnis ist dann der in umgekehrter Reihenfolge erzeugte Text im Editfeld.
Ein weiteres Beispiel für rekursive Prozeduraufrufe ist die Auflistung von Dateien in Unterverzeichnissen. Das läuft nach dem gleichen Muster ab.
Für solche rekursiven Prozeduraufrufe gibt es allerdings eine große Gefahr, nämlich wenn die Abbruchbedingung nie erreicht wird. Dann wird das Programm irgendwann einmal mit einen Stackoverflow abbrechen oder im Nirwana verschwinden, weil es ja nie endet. Schließlich muss ja jeder Prozeduraufruf mindestens seine Variablen zwischenspeichern.
Die eckigen Klammern sind zur Unterscheidung zwischen Indices und Prozedurparametern.
Sicher hast Du schon mal was von Arrays gehört. Das sind Speicherbereiche, welche mit gleichen Variablentypen belegt sind, wo einzelne Variablen dann über Indices angesprochen werden. z.B. die Monate des Jahres:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| Var Monat : Array[1..12] of string = ('JAN','FEB','MRZ','APR','MAI','JUN','JUL','AUG','SEP','OKT','NOV','DEZ'); AktuellerMonat : string; i : integer; begin AktuellerMonat := Monat[3]; for i := 1 to 12 do WriteLn(Monat[i]); end; |
Vorteil dabei ist, Du kannst den Speicherbereich mit den Daten beliebig ansprechen, indem Du den Index benutzt (Wie die Seiten eines Buches). Siehe das kleine Beispiel.
Die Daten im Array können im Übrigen jede x-beliebige - im Programm definierte! - Struktur haben.
z.B.:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| type Adresse = Record Vorname, Name : string[50]; Strasse : string[90]; PLZ : string[5]; Ort : string[90]; Geburtstag : TDateTime; end;
var Kunde : Array [1..200] of Adresse; |
Dann kannst Du mit dem Index i (Kunde[i]) den i-ten Kunden direkt ansprechen. Vorausgesetzt, Du hast da etwas eingegeben. Für eine Datenbank allerdings ist dieses Verfahren nicht geeignet, nur so im Voraus, weil ja nur 200 Kunden möglich sind.
Die Eckigen Klammern bei string[90] sind hier keine Indices, sonder Speicherbegrenzungen. Das heißt, für PLZ sind maximal 5 Zeichen möglich, für Ort maximal 90 usw. Der Typ TDateTime ist speziell für Datums- und Zeitangaben gedacht. Schau hier einfach mal in der Delphi-Hilfe nach.
jaenicke - Sa 06.11.10 08:09
Tranx hat folgendes geschrieben : |
Ich versuche es mit der zweiten Frage. |
Und damit ist das Chaos perfekt. :roll: :autsch:
Aber nachdem du jetzt gleich mit Arrays mit Records und Strings darin losgelegt hast :shock: (was vermutlich einige Wochen im Kursablauf vorgreift), schreibe ich dann trotzdem kurz etwas dazu. Denn hier ging es ja eigentlich nur um Strings und den Zugriff auf die Buchstaben darin.
MK777 hat folgendes geschrieben : |
Doch dann steht da "buchstabe := eingabe[position];". Ich habe keine Ahnung was hier passiert. :shock: Was bedeuten die eckigen Klammern? |
Auf diese Weise greifst du auf den Buchstaben Nummer Position in eingabe zu.
Wenn in eingabe der Text "ABC" steht, bekommst du in eingabe[1] das A, in eingabe[2] das B und in eingabe[3] das C. Auf diese Weise kannst du auf die einzelnen Buchstaben zugreifen und hier umgekehrt wieder zusammenbauen.
Mehr zum oben genannten Debugger steht hier:
http://www.delphi-treff.de/ueber-delphi/entwicklungsumgebung-bis-delphi-7/debugger/
MK777 - Sa 06.11.10 15:39
Vielen Dank für die ausführlichen Antworten. Ich weiss zwar was Arrays sind, aber ich war verwirrt, da es nirgendwo definiert ist (sprich "array[1..x] of string...").
Außerdem habe ich nicht gewusst, dass man damit einzelne Buchstaben auslesen kann. Jetzt habe ich endlich das Programm verstanden.
PS: Sorry, dass ich den Delphi-Tag nicht benutzt habe. Ich wusste nicht wie es geht, werde es mir aber für die Zukunft merken.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!