|
Das deutsche QBasic- und FreeBASIC-Forum Für euch erreichbar unter qb-forum.de, fb-forum.de und freebasic-forum.de!
|
Vorheriges Thema anzeigen :: Nächstes Thema anzeigen |
Autor |
Nachricht |
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 13.06.2024, 18:27 Titel: Zusammenhang Variable und Parameter einer SUB |
|
|
Hallo Leute, ich habe große Probleme mit o.g. Thema.
Ich bekomme regelmäßig die Fehlermeldung "Falscher Parameter".
'Vorbemerkung:
Sämtliche Variablen, egal ob sie als direkte Variable oder als Parameter einer SUB auftauchen, sind bei mir als DIM shared as integer definiert.
Integer reicht als Genauigkeit aus, shared für den allumfassenden Zugriff
(also nicht nur im Hauptprogramm , sondern auch in den einzelnen SUB's).
Im Hauptprogramm läuft eine 3-stufige For - Next-Schleife.
For x=1 to 10
For y=1 to 10
For r=1 to 10
'Hier wird jeweils die SUB Kreiszeigen mit den Parametern
'(kmx,kmy,kr) aufgerufen. 'Sie soll den Kreis mit
'Circle (kmx,kmy),kr, in gegebener Farbe grafisch darstellen.
'kmx und kmy sind die Koordinaten des jeweiligen Mittelpunktes
'kr steht für den Radius dieses Kreises.
'Für z.b. x=2, y=5, r=7 rufe sie also mit Kreiszeigen 2,5,7 auf.
'Damit übergebe ich also quasi die Originalwerte 2,5,7 an die
'Parameter kmx,kmy und kr der Sub Kreiszeigen.
'Wenn der Kreis gezeichnet wurde, frage ich nach, ob es korrekt
'erfolgte. Z.B. mit:
print using"Vorher: #:#:# Nachher: #:#:#" ;x;y;r;kmx;kmy;kr.
Da alle Variablen (x,y,r,kmx,kmy,kr) zuvor als shared definiert wurden,
müßte nach meinem Verständnis also:
Vorher: 2:5:7 Nacher:2:5:7 ausgegeben werden.
Tatsächlich wird aber ausgegeben: Vorher: 2:5:7 Nachher: 0:0:0
Warum? Wenn die Parameter kmx mit der Variablen x, kmy mit der
Variablen y und kr mit der Variablen r belegt wurden, dürfte es
die angezeigten "Nullen" doch gar nicht geben.
Wenn man jetzt, mit einer weiteren SUB die Fläche des soeben
bei kmx, kmy, kr gezeichneten Kreises berechnen und ausgeben
möchte, etwa mit der SUB Flaeche kmx, kmy, kr
bekommt man die Fehlermeldung "Falscher Parameter". Warum?
kmx, kmy und kr haben sich "unterwegs" doch nicht geändert.
Die Original-Werte x,y und r wurden doch nur "unter anderem Namen"
an die nachfolgenden SUB's "weitergereicht".
next r
next y
next x
Unterliege ich hier etwa einem Denkfehler?
Anders gefragt:
Sind Parameter an eine nachfolgende Sub "vererbbar" oder muß man
stets bei jeder Sub auf die ursprünglichen Originalwerte zurückgreifen?
Mit netten Grüßen Revilo |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 13.06.2024, 19:36 Titel: |
|
|
So ganz ohne konkretes Programm kann ich mir nicht vollständig vorstellen, wie genau du den Zugriff meinst. Was ich deiner Schilderung zu entnehmen glaube, ist folgendes: Durch die Übergabe der Parameter "überschreibst" du innerhalb der Prozedur die global definierte Variable durch eine lokale Variable. Das wird in der Referenz im Abschnitt "SHARED" beschrieben.
Ganz einfach gesagt: Es ergibt keinen Sinn, eine Variable als SHARED-Variable zu planen und gleichzeitig als Parameter zu übergeben. Der Sinn der Parameterübergabe ist ja gerade, dass die Prozedur mit einer lokalen Kopie der Variablen arbeiten kann (diese Formulierung ist nicht wirklich immer korrekt, ich lasse sie aber der Einfachheit halber mal so stehen) und eben gar keine SHARED-Variable nötig ist. Prinzipiell ist es besser, mit Parametern zu arbeiten und auf SHARED zu verzichten; wenn man sich aber für eine SHARED-Variable entscheidet, ist diese ja bereits in der Prozedur sichtbar und braucht nicht als Parameter übergeben werden (bzw. wenn man es trotzdem tut, ist diese Variable innerhalb der Prozedur nicht mehr global, selbst wenn sie genauso heißt wie eine globale Variable).
Code: | DIM SHARED AS INTEGER x = 1
DECLARE SUB test1(x AS INTEGER)
DECLARE SUB test2
test1(x)
PRINT x
test2
PRINT x
SUB test1(x AS INTEGER)
x = 8765 ' x ist eine lokale Variable, obwohl sie denselben Namen hat wie das globale x
END SUB
SUB test2
x = 8765 ' x ist eine globale Variable
END SUB |
_________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1261 Wohnort: Ruhrpott
|
Verfasst am: 13.06.2024, 19:51 Titel: |
|
|
Hallo Revilo,
um genaueres sagen zu können, bräuchte ich den Code deiner Sub (bitte in 'Code' Tags einschließen, das erhöht die Lesbarkeit enorm ). Ich nehme aber an, daß du in der Parameterliste einen falschen Datentyp deklariert hast.
Aber ganz allgemein: Mit dem SCOPE von Variablen ist das nicht ganz so einfach. Wenn du in der Parameterliste eine Variable deklarierst, erzeugst du damit einen Scope-Block, der innerhalb der Prozedur (SUB oder FUNCTION) gilt. Variablen gleichen Namens von außerhalb des Scope-Blocks werden dann ignoriert. Wenn du innerhalb einer Prozedur auf SHARED-Variablen zugreifen möchtest, dürfen diese nicht in der Parameterliste auftauchen.
Außerdem solltest du dir einmal BYVAL und BYREF anschauen.
Code: | Dim Shared As Integer a, b, e, f
Sub test(a As Integer, b As Integer, c As Integer, d As Integer)
Print a, b, c, d, e, f
End Sub
a= 1
b = 2
e = 3
f = 4
test(5, 6, a, b)
Sleep
|
Gruß
grindstone
EDIT: Ich sehe gerade, nemored war schneller. _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 14.06.2024, 20:02 Titel: |
|
|
Hallo nemored,
vielen Dank für deine schnelle Antwort.
Ohne konkreten Syntax sind Fernurteile immer schwierig.
Aber ich wußte einfach nicht, wie ich Programmzeilen aus meinen Q-Basic
Programmen hierher übertragen kann, ohne sie alle erneut tippen zu müssen. Ich habe schon monatelang daran 'rumprobiert, stets ohne Erfolg. Aber jetzt weiß ich es. Mein Weg mag nicht der eleganteste sein,
aber er funktioniert, hoffe ich zumindest.
Hier also die gewünschten Programmzeilen:
DIM SHARED x, y, r AS INTEGER 'Originalwerte im Hauptprogramm
DIM SHARED kmx, kmy, kr AS INTEGER 'Parameter zum Zeichnen des Kreises
DIM SHARED pi AS DOUBLE 'Kreiszahl Pi
DIM SHARED f AS DOUBLE 'Masszahl der Flaeche
DECLARE SUB Kreiszeichnen (kmx, kmy, kr) 'Zeichnet den Kreis
DECLARE SUB Flaeche (kr) 'Bestimmt die Flaeche
'Hauptprogramm
'--------------
SCREEN 12
'Bestimme Pi als Vorarbeit fuer Flaechenberechnung
pi = 4 * ATN(1)
'SUB's sollen ja das Hauptprogramm ueberschaubar halten.
'Sie strukturieren es und leisten die eigentliche "Arbeit".
'Ohne Aufruf der SUB's, funktioniert es ! 'Allerdings muss dann auch das Hauptprogramm die ganze "Arbeit " leisten.
FOR x = 1 TO 10
FOR y = 1 TO 10
FOR r = 1 TO 10
CIRCLE (x * 50, y * 50), r * 10, 14 'wie in Sub
f = pi * r ^ 2 'wie im Unter-Sub
LOCATE 20, 60: PRINT USING " F = ####.##########"; f
NEXT r
NEXT y
NEXT x
'Mit Aufruf der SUB's aber nicht! Hier erscheint die Fehlermeldung
'bereits fuer die Sub Kreiszeichnen.
'Bis zur Berechnung der Flaeche als Unter-SUB von Kreiszeichnen
'komme ich gar nicht erst, und das verstehe ich nicht.
'SUB und Unter-SUB enthalten doch dieselben Befehle, wie oben in der
'funktionierenden Variante.
FOR x = 1 TO 10
FOR y = 1 TO 10
FOR r = 1 TO 10
Kreiszeichnen x, y, r 'Hier kommt bereits die Fehlermeldung
LOCATE 20, 60: PRINT USING " F = ####.##########"; f
NEXT r
NEXT y
NEXT x
SUB Flaeche (kr)
f = pi * kr ^ 2
END SUB
SUB Kreiszeichnen (kmx, kmy, kr)
CIRCLE (kmx * 50, kmy * 50), kr * 10, 14
Flaeche kr
END SUB
Leider beherrsche ich nur die DIM-Shared-Variante.
Den Unterschied zu deiner, wahrscheinlich besseren Variante, ohne dim shared habe ich leider nicht verstanden.
Vielleicht kannst du mir jetzt zu einem Aha-Effekt verhelfen.
Würde mich freuen.
Gruß Revilo |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 14.06.2024, 22:05 Titel: |
|
|
Für die Variante ohne DIM SHARED lässt du einfach die zweite Zeile weg. In den anderen DIM-Zeilen kannst du dann auch noch das Schlüsselwort SHARED weglassen.
Das Problem mit der Fehlermeldung ist aber ein anderes. Einige Variablen werden ohne explizite Angabe des Datentyps deklariert und sind daher ... ich weiß es wieder nicht - SINGLE oder DOUBLE. An anderer Stelle deklarierst du explizit als INTEGER, übergibst dann aber an eine Stelle, an der (implizit) ein DOUBLE-Wert verlangt wird. Warum da nicht automatisch konvertiert wird, weiß ich nicht, aber mit konsequenter Deklaration funktioniert es.
Und noch etwas - das hatten wir schon mal:
Code: | DIM SHARED x, y, r AS INTEGER |
deklariert x und y implizit als DOUBLE und nur r explizit als INTEGER!
Das hier funktioniert bei mir unter FreeBASIC im QBasic-Kompatibilitätsmodus; in QBasic selbst kann ich nicht testen.
Code: | DIM x AS INTEGER, y AS INTEGER, r AS INTEGER 'Originalwerte im Hauptprogramm
DIM SHARED pi AS DOUBLE 'Kreiszahl Pi
DIM SHARED f AS DOUBLE 'Masszahl der Flaeche
DECLARE SUB Kreiszeichnen (kmx AS INTEGER, kmy AS INTEGER, kr AS INTEGER) 'Zeichnet den Kreis
DECLARE SUB Flaeche (kr AS INTEGER) 'Bestimmt die Flaeche
'Hauptprogramm
'--------------
SCREEN 12
'Bestimme Pi als Vorarbeit fuer Flaechenberechnung
pi = 4 * ATN(1)
FOR x = 1 TO 10
FOR y = 1 TO 10
FOR r = 1 TO 10
Kreiszeichnen x, y, r
LOCATE 20, 60: PRINT USING " F = ####.##########"; f
NEXT r
NEXT y
NEXT x
SUB Flaeche (kr AS INTEGER)
f = pi * kr ^ 2
END SUB
SUB Kreiszeichnen (kmx AS INTEGER, kmy AS INTEGER, kr AS INTEGER)
CIRCLE (kmx * 50, kmy * 50), kr * 10, 14
Flaeche kr
END SUB |
_________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 14.06.2024, 22:18 Titel: |
|
|
Hier noch die "Profi-Version" ganz ohne SHARED. PI ist eine mathematische Konstante, die entsprechend mit CONST deklariert werden kann, und um den Wert zurückzugeben, der innerhalb eines Programmes berechnet wird, nutze ich Funktionen.
Code: | DIM x AS INTEGER, y AS INTEGER, r AS INTEGER 'Originalwerte im Hauptprogramm
DIM f AS DOUBLE 'Masszahl der Flaeche
CONST pi = 4 * ATN(1)
DECLARE FUNCTION Kreiszeichnen (kmx AS INTEGER, kmy AS INTEGER, kr AS INTEGER) AS DOUBLE 'Zeichnet den Kreis
DECLARE FUNCTION Flaeche (kr AS INTEGER) AS DOUBLE 'Bestimmt die Flaeche
'Hauptprogramm
'--------------
SCREEN 12
FOR x = 1 TO 10
FOR y = 1 TO 10
FOR r = 1 TO 10
f = Kreiszeichnen(x, y, r)
LOCATE 20, 60: PRINT USING " F = ####.##########"; f
NEXT r
NEXT y
NEXT x
FUNCTION Flaeche (kr AS INTEGER) AS DOUBLE
Flaeche = pi * kr ^ 2
END FUNCTION
FUNCTION Kreiszeichnen (kmx AS INTEGER, kmy AS INTEGER, kr AS INTEGER) AS DOUBLE
CIRCLE (kmx * 50, kmy * 50), kr * 10, 14
Kreiszeichnen = Flaeche(kr)
END FUNCTION |
Wahrscheinlich wäre es aber sinnvoller, 'Kreiszeichnen' als SUB zu belassen und darin keine Flächenberechnung durchzuführen, sondern stattdessen die Funktion 'Flaeche' vom Hauptprogramm aus aufzurufen.
Code: | DIM x AS INTEGER, y AS INTEGER, r AS INTEGER 'Originalwerte im Hauptprogramm
CONST pi = 4 * ATN(1)
DECLARE SUB Kreiszeichnen (kmx AS INTEGER, kmy AS INTEGER, kr AS INTEGER) 'Zeichnet den Kreis
DECLARE FUNCTION Flaeche (kr AS INTEGER) AS DOUBLE 'Bestimmt die Flaeche
'Hauptprogramm
'--------------
SCREEN 12
FOR x = 1 TO 10
FOR y = 1 TO 10
FOR r = 1 TO 10
Kreiszeichnen(x, y, r)
LOCATE 20, 60: PRINT USING " F = ####.##########"; Flaeche(r)
NEXT r
NEXT y
NEXT x
FUNCTION Flaeche (kr AS INTEGER) AS DOUBLE
Flaeche = pi * kr ^ 2
END FUNCTION
SUB Kreiszeichnen (kmx AS INTEGER, kmy AS INTEGER, kr AS INTEGER)
CIRCLE (kmx * 50, kmy * 50), kr * 10, 14
END SUB |
_________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 15.06.2024, 15:46 Titel: |
|
|
Hallo nemored,
dass, DIM SHARED x, y, r AS INTEGER , nicht alle Variablen sondern nur r als integer deklariert, war mir entfallen, sorry. Danke für den Hinweis. Ich hoffe, es nervt dich nicht allzu sehr, wenn ich noch einige kleine Nachfragen habe.
Kann man "implizit" mit "automatisch also computergeneriert" und "explizit" wie "ausdrücklich menschengewünscht" übersetzen ?
grindstone verwendete den Syntax
Dim Shared As Integer a, b, e, f bzw. mit meinen Variablen : Dim Shared As Integer x, y, r
Macht das fachlich hinsichtlich '"implizit" und "explizit" einen Unterschied ?
In deiner Antwort vom 13.06. verwendest du den Syntax:
DIM SHARED AS INTEGER x = 1
Was hat es mit diesem "x = 1" auf sich?
Ist das eine Art Startwert, ab dem x in einer For-Next-Schleife gezählt wird?
Zum Unterschied locale und globale Variablen:
Wenn ich das richtig verstanden habe, gelten globale Variablen sowohl im Hauptprogramm als auch in allen SUB's, richtig?
Locale Variablen gelten hingegen ausschließlich in der jeweiligen SUB, in der sie benutzt werden, also nicht sub-übergreifend, richtig?
Besagte Fehlermeldung geschieht ja nur, weil irgend etwas zwischen den Variablen und Parametern nicht richtig zusammenpassen will.
In meinem kleinen Kreisprogramm gibt es nur 7 Variablen:
x, y, r, kmx, kmy, kr und f.
Wenn ich sie wie folgt definieren würde:
dim shared x as single
dim shared y as single
dim shared r as single
dim shared kmx as single
dim shared kmy as single
dim shared kr as single
dim shared f as single
(8 Stellen Genauigkeit dürften wohl mehr als ausreichen)
würden sie alle sowohl dem Hauptprogramm also auch allen SUB's zur Verfügung stehen, (egal, ob als Zähler in einer Schleife oder als Parameter in einer SUB).
Dann sind eben alle Variablen als global definiert.
Eine Unterscheidung zwischen localen und globalen Variablen wäre dann doch gar nicht nötig.
Oder liegt eben genau hier mein Denkfehler?
Passiert bei der Übergabe einer Variablen an einen Parmeter einer SUB intern irgend etwas, was man als Laie nicht weiß?
Gruß Revilo |
|
Nach oben |
|
|
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1261 Wohnort: Ruhrpott
|
Verfasst am: 15.06.2024, 18:32 Titel: |
|
|
Revilo hat Folgendes geschrieben: | Kann man "implizit" mit "automatisch also computergeneriert" und "explizit" wie "ausdrücklich menschengewünscht" übersetzen ? | Ja, so könnte man es ausdrücken.
Revilo hat Folgendes geschrieben: | grindstone verwendete den Syntax
Dim Shared As Integer a, b, e, f bzw. mit meinen Variablen : Dim Shared As Integer x, y, r
Macht das fachlich hinsichtlich '"implizit" und "explizit" einen Unterschied ? | Das funktioniert nur in FB (auch im QBasic Kompatibilitätsmodus). Beim originalen QBasic muß es heissen Code: | DIM x AS INTEGER
DIM y AS INTEGER
Dim r AS INTEGER |
Revilo hat Folgendes geschrieben: | In deiner Antwort vom 13.06. verwendest du den Syntax:
DIM SHARED AS INTEGER x = 1
Was hat es mit diesem "x = 1" auf sich?
Ist das eine Art Startwert, ab dem x in einer For-Next-Schleife gezählt wird? | Damit wird der Variable x gleich bei der Deklaration der Wert 1 zugewiesen. Auch das funktioniert nur bei FB. In QBasic muss es heissen: Code: | DIM SHARED x AS INTEGER
x = 1 |
Revilo hat Folgendes geschrieben: | Dann sind eben alle Variablen als global definiert.
Eine Unterscheidung zwischen localen und globalen Variablen wäre dann doch gar nicht nötig.
Oder liegt eben genau hier mein Denkfehler?
Passiert bei der Übergabe einer Variablen an einen Parmeter einer SUB intern irgend etwas, was man als Laie nicht weiß? | Das ist ein schlechter Programmierstil, den du dir gar nicht erst angewöhnen solltest (Ja, ja, ich weiß: "Hört, wer da anderen predigt" ). Bei einem einzelnen Miniprogramm macht das nicht viel Unterschied, aber wenn du einmal größere Programme schreibst und vor allem, wenn du Teile aus älteren Programmen wiederverwenden möchtest, ist es eine große Erleichterung, wenn du dir um doppelte Variablennamen keine Gedanken machen musst.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
|
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 79
|
Verfasst am: 15.06.2024, 19:18 Titel: |
|
|
Revilo hat Folgendes geschrieben: | ...war mir entfallen, sorry. |
Das ist absolut kein dummer Fehler, sondern was das sogar Experten übersehen. So ähnlich wie bei C ein "if (i=27) { ..." - wobei es dafür immerhin hilfreiche Compiler-Warnings gibt.
Revilo hat Folgendes geschrieben: |
Kann man "implizit" mit "automatisch also computergeneriert" und "explizit" wie "ausdrücklich menschengewünscht" übersetzen ? |
Eher nicht. Explizit ist halt ausdrücklich. Implizit "stillschweigend". Aber letztlich bestimmt/definiert der Programmierer immer. - Wenn man davon ausgeht, dass er sich bewusst ist, was er da codet.
Beim Original-BASIC ist's halt so dass wenn ein "i" auftaucht, dann ist das eine neue Variable vom Typ "Real"(float). Wenn du beispielsweise mal "adress" statt "address" tippst, hast allerdings dann mal zwei verschiedene Variablen und irgendwie macht das Programm nicht was man erwartet hat...
Revilo hat Folgendes geschrieben: | Dim Shared As Integer x, y, r
Macht das fachlich hinsichtlich '"implizit" und "explizit" einen Unterschied ? |
Nein. Explizit bedeutet schlicht, dass ein "Symbol" - Variable, SUB etc. VOR dem "Gebrauch" im Code "deklariert" wird. So musst du z.B. bei FreeBASIC auch eine SUB mit DECLARE "ankündigen", wenn die "Definition", also dessen Code erst hinter dem ersten Aufruf im Quelltext kommt, genauso wie bei den meisten anderen Hochsprachen. Also:
Code: |
DECLARE SUB mysubroutine
...
mysubroutine
...
SUB mysubroutine
...
END SUB |
=> ohne DECLARE Syntax Error. Bei Variablen übernimmt das DIM, und für "globale" Variablen musst du "DIM SHARED..." verwenden. Ansonsten kannst du innerhalb von SUBs nicht darauf zugreifen, sondern nur in dem Code, der nach dem DIM vor den SUBs folgt.
Revilo hat Folgendes geschrieben: |
Was hat es mit diesem "x = 1" auf sich?
Ist das eine Art Startwert, ab dem x in einer For-Next-Schleife gezählt wird? |
Das nennt sich "Initialisierung". Bei vielen Sprachen wird das nicht automatisch gemacht, weil's auch ein paar Taktzyklen kostet, die unnötig verschwendet sein könnten; BASIC setzt die meisten Werte auf 0, allerdings überschreibt es den Puffer von Strings auch nicht mit lauter Nullen. Prinzipiell kann der Speicher so noch alte Daten enthalten, dann ist x halt mal zufällig z.B. 177. Mit einem "FOR x=1 TO 10" wird x aber auch mit 1 initialisiert.
Revilo hat Folgendes geschrieben: | Zum Unterschied locale und globale Variablen:
Wenn ich das richtig verstanden habe, gelten globale Variablen sowohl im Hauptprogramm als auch in allen SUB's, richtig?
Locale Variablen gelten hingegen ausschließlich in der jeweiligen SUB, in der sie benutzt werden, also nicht sub-übergreifend, richtig? |
Bei globalen Variablen kann man das nicht so verallgemeinern; bei SHARED allein gelten die Variablen nur innerhalb des "Moduls", bei COMMON SHARED im ganzen Projekt. Man muss dabei vorallem bedenken, dass man im selben Projekt mehrere völlig identische Variablen haben könnte, aber wenn man in einem "Modul" darauf zugreift, tatsächlich auf einen Zwillig zugreift, der praktisch identisch ist, allerdings für den Computer eine ganz andere Variable.
Lokale Variablen sind ne kompliziertere Sache... Nicht nur, dass sie nur innerhalb einer SUB "existieren". Du kannst eine SUB sich selbst aufrufen lassen - das nennt sich Rekursion. Dabei bleiben die Variablen nicht erhalten, sondern es werden jedesmal neue Zwillinge aller lokalen Variablen erstellt - auf dem so genannten "Stack"/"Stapelspeicher". - Ein Prinzip direkt aus der Maschinensprache, das Hochsprachen auch nutzen, vielleicht kann's Wikipedia hinreichend erklären.
Revilo hat Folgendes geschrieben: | Wenn ich sie wie folgt definieren würde:
dim shared x as single
...
dim shared f as single
(8 Stellen Genauigkeit dürften wohl mehr als ausreichen)
würden sie alle sowohl dem Hauptprogramm also auch allen SUBs zur Verfügung stehen |
Ja: solange du sie nicht wieder mit gleichnamigen lokalen Variablen "überschreibst". BTW haben die Gleitkommazahltypen float("single") und double eine gravierende Schwäche die man kennen sollte: sie sind Binärbrüche. Statt 0.1, 0.01 und 0.001 stellen sie intern 0.5, 0.25, 0.125 usw. dar - jede "Stelle" nicht 1/10, sondern 1/2. Das macht oft nichts, allerdings ist 1+1.1 im Computer nicht gleich 2.1. Wenn man die Ausgabe rundet, ist der Fehler vernachlässigbar, aber direkte Vergleiche sind fehlerbehaftet wenn man nicht eine gewisse Toleranz einbaut.
Revilo hat Folgendes geschrieben: | Eine Unterscheidung zwischen localen und globalen Variablen wäre dann doch gar nicht nötig. |
Doch, weil's ein erheblicher Unterschied ist. Du sollst einfach nicht lokale Variablen so nennen wie deine globalen Variablen, und nur so einsetzen wie es Sinn macht.
Revilo hat Folgendes geschrieben: | Passiert bei der Übergabe einer Variablen an einen Parameter einer SUB intern irgend etwas, was man als Laie nicht weiß? |
Wie schon angekratzt: die Werte der Variablen(BYVAL) oder Zeiger auf ihre Speicheradresse (BYREF) werden auf dem Stack abgelegt, zusammen mit der Rücksprungadresse... - Ich würde das mal mit einem klaren JA beantworten... 🧐 |
|
Nach oben |
|
|
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 79
|
Verfasst am: 15.06.2024, 19:27 Titel: |
|
|
grindstone hat Folgendes geschrieben: | Das ist ein schlechter Programmierstil, den du dir gar nicht erst angewöhnen solltest... |
Es KANN schon "sauber" sein, so aus OOP-Perspektive. Wenn du ein "Modul" machst - also quasi ne Klasse - und nur die Variablen global definierst, die innerhalb deiner "Klasse" gebraucht werden, quasi als Membervariablen / "Eigenschaften"...
Wenn du allerdings deinen Allerwelts-i-Integer global definierst kann die Kacke schnell dampfen, wenn du den z.B. als Zähler in ner FOR-Schleife benutzt, und in der Unterprogramme aufgerufen werden, die ebenfalls dieses i benutzen...
Entsprechend sollten globale Variablen auch absolut eindeutige Namen haben wie "mylibrarydatabufferfortuesdays" und auch wirklich Sinn machen, dass man sich weder selber ein Bein stellt noch beim Coderecycling Probleme kriegt. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 16.06.2024, 00:15 Titel: |
|
|
Hallo Berkeley,
vielen Dank für deine Antwort, aber offenbar setzt du bei mir mehr Sachkenntnis voraus, als ich tatsächlich habe.
Ich bin zwar 60 Jahre alt aber dennoch Anfänger und schreibe meine Programme nur in QBasic weil ich gar keine andere Programmiersprache kenne. Ich mache es einfach als Hobby, um nicht geistig "einzurosten".
Ich bin hier quasi gerade dabei, das "Zählen" zu erlernen.
Daß du mir gleich mit den Feinheiten der "Integralrechnung" kommst, ist zwar nett gemeint, aber hoffnungslos.
Auf rein mathematischem Gebiet könnte ich dir bis zur Integralrechnung folgen. Aber hier geht es eben nicht um Mathematik sondern um das Programmieren. Das ist ein völlig anderes "Schlachtfeld" auf dem ich (noch) ein ganz kleines Licht bin.
Auf gut' Deutsch: Von deinem Beitrag habe ich nicht ein Wort verstanden.
Dennoch danke ich dir für deine Bemühungen.
Gruß Revilo |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 16.06.2024, 05:22 Titel: |
|
|
Berkeley hat Folgendes geschrieben: | BASIC setzt die meisten Werte auf 0, allerdings überschreibt es den Puffer von Strings auch nicht mit lauter Nullen. |
@Berkeley: Ein FreeBASIC-STRING (ich verwende diesen Begriff in Abgrenzung zum ZSTRING) besteht in erster Linie aus dem Header, der u. a. die Adresse des eigentlichen Stringinhalts enthält; bei Initialisierung eines Strings (oder auch bei Zuweisung meinString = "") ist das der Nullpointer. Von daher ist kein Überschreiben des Puffers nötig.
"Relevant" ist das Nicht-Überschreiben eigentlich nur bei einer Wertzuweisung <> "". _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Berkeley
Anmeldungsdatum: 13.05.2024 Beiträge: 79
|
Verfasst am: 16.06.2024, 15:44 Titel: |
|
|
Revilo hat Folgendes geschrieben: | Hallo Berkeley,
vielen Dank für deine Antwort, aber offenbar setzt du bei mir mehr Sachkenntnis voraus, als ich tatsächlich habe. |
Dann solltest du dir nicht den Kopf über "explizit", "implizit", "Deklarationen", "Definitionen" usw. zerbrechen.
Mach' einfach nicht so was:
Code: |
DIM SHARED AS INTEGER a
<fröhlicher Quelltext>
SUB mysub(a AS INTEGER)
DIM AS INTEGER a
a=27
END SUB
SUB mysub2
a=13
END SUB
|
Das erste 'a' wär eigentlich global, die beiden 'a's in der SUB - Parameter und per DIM - sind für den Computer aber ganz andere -lokale- Variablen. Beide lokalen 'a's sind auf einer "Ebene", daher kriegst du auch ne Fehlermeldung wenn du das zu kompilieren versuchst => es geht nur eine von beiden Varianten gleichzeitig. Nach END SUB ist mit beiden Methoden die lokale Variable a futsch, die existiert nur in 'mysub' und wird auch nur da auf 27 gesetzt.
In der SUB mysub2 wird das globale 'a' verändert, nach Verlassen ist 'a' immer noch 13 - aber eben nicht innerhalb 'mysub', weil das 'a' da eine andere Variable ist, die nur genauso heißt. Und ohne das "SHARED" würd's eine Fehlermeldung in mysub2 geben, da für den Computer das erste 'a' praktisch nur da existiert wo "<fröhlicher Quelltext>" steht. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 16.06.2024, 19:20 Titel: |
|
|
Hallo Berkeley,
vielen Dank für deine Rückantwort.
Wahrscheinlich frage ich nicht treffend genug oder einfach zu umständlich.
Mein kleines Kreisprogramm sollte eigentlich als Beispiel zur besseren Veranschaulichung dienen, war aber wohl doch keine so glückliche Wahl.
Deshalb versuche ich es mal mit anderen Worten.
Ich habe ein Hauptprogramm. Das ist also praktisch das Projekt, an dem ich gerade knobele.
Um hier nicht den Überblick zu verlieren, lasse ich verschiedene Teilaufgaben durch SUB's bearbeiten.
Ich habe eine ganze Reihe verschiedener SUB's -- Für jede Teilaufgabe eine.
Diese SUB's müssen alle sowohl mit dem Hauptprogramm
als auch untereinander kommunizieren können.
Im Hauptporgramm werden irgend welche Werte ermittlt.
Diese liegen in bestimmten Variablen vor z.B. a, b und c
a ,b und c sind die Ausgangsdaten zur Bearbeitung einer Teilaufgabe, müssen also der jeweiligen SUB irgendwie "übergeben, mitgeteilt" werden, damit sie die Teilaufgabe überhaupt bearbeiten kann.
Zu diesem Zweck habe ich jede SUB mit ihren ganz individuellen Parametern declariert. Es gibt also keine 2 SUB's mit gleichen Parametern, bzw. Parametern gleichen Namens.
Die 1. SUB habe z.B. die Parameter p1a, p1b, p1c
Ich rufe sie mit den Werten a,b,c aus dem Hauptprogramm auf.
Die Werte a,b, c liegen jetzt quasi als Kopie in den Parametern p1a,p1b und p1c vor, mit denen diese SUB arbeitet. Sie liefert als Ergebnis den Wert d.
d soll der Ausgangswert für die 2. SUB sein, die wiederum eine, diesmal andere, Teilaufgabe zu bearbeiten hat. Sie habe dazu den Parameter p2d
d liegt nach Aufruf der 2. SUB also als Kopie im Parameter p2d vor.
Sie liefert als Ergebnis die Werte e und f, die an eine 3. SUB
mit den Parametern p3e, p3f übergeben werden sollen.
Diese 3. SUB liefert den Wert g.
Dieser soll als Endergebnis im Hauptprogramm ausgegeben werden.
Z.B. mit dem Befehl:
print using "Ergebnis: a: ## b:## c:## ergeben: g:## ";a;b;c;g
Ergänzung:
Wenn ich z.B. i als Zähler in einer For-Next-Schleife benutze, dann grundsätzlich nur in dieser konkreten Schleife.
Andere Schleifen haben entsprechend andere Zähler z.B. u statt i.
Ich weiß, daß jede Variable Speicherplatz benötigt. Aber wie soll ich mir anders behelfen, um Verwechslungen zu vermeiden? Das ist nun mal das Schicksal eines Laien. Unkenntnis kostet Speicherplatz.
Zusammenfassung dessen, was ich bisher davon verstanden habe:
1) Ein Parameter einer SUB muß vom gleichen Datentyp sein, wie der Wert, der an ihn übergeben wird, also z.B. single.
2) a,b und c sind offenbar globale Variablen, weil sie im Hauptprogrammm verwendet werden.
3) p1a, p1b, p1c, d, p2d, e, f, p3e, p3f und g sind offenbar lokale Variablen, weil sie nur lokal in einer der 3 SUB 's verwendet werden.
4) d, e, f und g können nach meinem Verständnis aber nicht lokal sein,
denn:
4.1) d, e und f müssen schließlich an andere SUB's übergebbar sein,
damit diese ihren Job, ihre Teilaufgabe machen können.
4.2) g muß schließlich im Hauptprogramm ausgebbar sein,
damit im Hauptprogramm ein Ergebnis erscheinen kann.
Aus diesem Widerspruch ergeben sich wahrscheinlich auch meine Schwierigkeiten mit diesem Thema.
Daher meine Frage:
Wie müßte ich die Befehle DIM.....; bzw. DIM SHARED.....
fachlich korrekt auf diese einzelnen Variablen a, b, c, d, e, f, g, p1a, p1b, p1c, p2d, p3e und p3f anwenden ?
Das habe ich wahrscheinlich schon 100 mal falsch gemacht.
Gibt es dafür eine Art "Faustregel"?
(PS: hinsichtlich der Genauigkeit würde "integer" völlig ausreichen, weil ich nur mit natürlichen Werten zu tun habe.)
Das mit den Kreisen war nur ein schlecht gewähltes Beispiel.
Gruß Revilo |
|
Nach oben |
|
|
dreael Administrator
Anmeldungsdatum: 10.09.2004 Beiträge: 2524 Wohnort: Hofen SH (Schweiz)
|
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 16.06.2024, 23:56 Titel: |
|
|
Zitat: | 2) a,b und c sind offenbar globale Variablen, weil sie im Hauptprogrammm verwendet werden. |
Nein; wenn sie nur im Hauptprogramm definiert ist, ist sie ebenfalls lokal. Global ist sie nur, wenn sie sowohl im Hauptprogramm als auch in allen Unterprogrammen verfügbar ist.
Zitat: | 4) d, e, f und g können nach meinem Verständnis aber nicht lokal sein,
denn:
4.1) d, e und f müssen schließlich an andere SUB's übergebbar sein,
damit diese ihren Job, ihre Teilaufgabe machen können. |
Nein. Du kannst eine lokale Variable an eine SUB als Parameter übergeben. Mit welchen Wert die neue SUB arbeiten soll, erfährt sie ja über die Parameterübergabe.
Code: | DIM a AS INTEGER, b AS INTEGER, c AS INTEGER ' lokal nur im Hauptprogramm
DECLARE SUB p1(p1a AS INTEGER, p1b AS INTEGER, p1c AS INTEGER)
DECLARE SUB p2(p2d AS INTEGER)
DECLARE SUB p3(p3e AS INTEGER, p3f AS INTEGER)
a = 1
b = 2
c = 3
p1(a, b, c)
SUB p1(p1a AS INTEGER, p1b AS INTEGER, p1c AS INTEGER)
DIM d AS INTEGER ' lokal nur in p1. Auch p1a, p1b und p1c sind lokal.
d = p1a + p1b + p1c
p2(d)
END SUB
SUB p2(p2d AS INTEGER)
DIM e AS INTEGER, f AS INTEGER ' lokal nur in p2
e = 2*p2d
f = p2d - 1
p3(e, f)
END SUB
SUB p3(p3e AS INTEGER, p3f AS INTEGER)
PRINT "Mir wurden die Werte "; p3e; " und "; p3f; " uebergeben."
END SUB |
Ablauf:
Das Hauptprogramm liefert die Werte a, b und c an p1; diese werden dort als p1a, p1b und p1c gespeichert.
p1 berechnet den Wert d und übergibt ihn an p2; dieser Wert wird dort als p2d gespeichert.
p2 berechnet die Werte e und f und übergibt sie an p3, sie werden dort als p3e und p3f gespeichert.
p3 macht was mit den übergebenen Werten p3e und p3f. Wenn es fertig ist, gibt es die Kontrolle an p2 zurück.
p2 ist nach Aufruf von p3 fertig; wenn p3 die Kontrolle an p2 zurückgibt, gibt p2 die Kontrolle an p1 zurück. Da p1 auch nichts mehr zu tun hat, gibt es die Kontrolle an das Hauptprogramm zurück.
Zitat: | 4.2) g muß schließlich im Hauptprogramm ausgebbar sein,
damit im Hauptprogramm ein Ergebnis erscheinen kann. |
Möglich wäre es, nur die Variable g SHARED zu setzen, damit du sie in p3 beschreiben und im Hauptprogramm auslesen kannst. Um einen einzelnen Wert zurückzugeben, sind aber Funktionen da. Das Problem ist lediglich, dass du den Funktionswert von p3 über p2 und p1 an das Hauptprogramm durchreichen musst.
Code: | #lang "qb"
DIM a AS INTEGER, b AS INTEGER, c AS INTEGER, g AS INTEGER ' lokal nur im Hauptprogramm
DECLARE FUNCTION p1(p1a AS INTEGER, p1b AS INTEGER, p1c AS INTEGER) AS INTEGER
DECLARE FUNCTION p2(p2d AS INTEGER) AS INTEGER
DECLARE FUNCTION p3(p3e AS INTEGER, p3f AS INTEGER) AS INTEGER
a = 1
b = 2
c = 3
g = p1(a, b, c)
PRINT "Das Ergebnis lautet "; g; "."
FUNCTION p1(p1a AS INTEGER, p1b AS INTEGER, p1c AS INTEGER) AS INTEGER
DIM d AS INTEGER ' lokal nur in p1. Auch p1a, p1b und p1c sind lokal.
d = p1a + p1b + p1c
p1 = p2(d) ' Durchreichen der Rueckgabe von p2 an das Hauptprogramm
END FUNCTION
FUNCTION p2(p2d AS INTEGER) AS INTEGER
DIM e AS INTEGER, f AS INTEGER ' lokal nur in p2
e = 2*p2d
f = p2d - 1
p2 = p3(e, f) ' Durchreichen der Rückgabe von p3 an p1
END FUNCTION
FUNCTION p3(p3e AS INTEGER, p3f AS INTEGER) AS INTEGER
DIM p3g AS INTEGER ' lokal nur in p3
p3g = p3e - p3f
p3 = p3g ' Definition des Rueckgabewerts
END FUNCTION |
Der Ablauf ist fast derselbe wie oben, nur dass p3 die Variable p3g an p2 übergibt. p2 kann dann damit noch etwas machen, wenn es will; in meinem Beispiel gibt es den Wert aber einfach an p1 weiter. p1 macht auch nichts mehr und gibt den Wert an das Hauptprogramm weiter.
Da nun alle Variablen lokal sind, könnten die Variablen im Unterprogramm auch denselben Namen haben wie im Hauptprogramm oder einem anderen Unterprogramm - es sind trotzdem andere Variablen. Es spricht aber nichts dagegen, sie alle unterschiedlich zu benennen, und es kostet auch keinen zusätzlichen Speicherplatz. Wenn eine lokale Variable nicht mehr gebraucht wird, wird der von ihr belegte Speicherplatz wieder freigegeben. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 17.06.2024, 21:28 Titel: |
|
|
Hallo nemored,
deine letzten Ausführungen waren sehr aufschlussreich. Vielen Dank dafür.
Sie zeigen mir, daß ich bei der Deklarierung meiner Variablen eine ganze Menge fachliche "Böcke" geschossen habe.
Du legst mir die Nutzung von Functionen nahe.
Diesen Begriff verbinde ich eher mit der Mathematik, also mit dem berechnen einer Ergebniszahl aus vorgegebenen Zahlen.
Ich sah das immer als Möglichkeit, sich individuelle mathematische Formeln
"zusammenstricken" zu können.
Aber offenbar können Funktionen auch Befehle enthalten, die gar nichts mit mathemat. Symbolen wie sin, cos, log usw. zu tun haben.
Das legt die Vermutung nahe, daß eine Funktion genauso z.B. 100 Programmzeilen enthalten kann, wie eine SUB.
Was wäre denn dann der Unterschied zwischen SUB und Funktion?
Warum sind Funktionen empfehlenswerter, als SUB's?
Besagte Fehlermeldung "Falscher Parameter" hat also eher mit einer falschen Deklarierung meiner Variablen (lokal statt global oder umgekehrt) zu tun. Richtig?
Ich hatte immer vermutet, es wäre ein falscher Wert übergeben worden,
der noch irgend wo im Speicher "schlummerte" und von dort "ausgegraben" wurde.
Z.B. soll eine 177 an einen Parameter übergeben werden, der nur Werte
1 und 25 akzeptiert. Klar, daß mein "Robby" da meckert.
Um solche "versteckten" Fehler möglichst zu umgehen, gestalte ich z.B.
For - Next - Schleifen immer wie folgt:
i=0
for i=1 to 10
.
. Befehle, SUB's in dieser Schleife
.
next
if i>10 then i=10
So vermeide ich hoffentlich, daß i zufällich durch irgend welche "Schaltfehler" des Computers auf eine unerwartete, unmögliche
11 springen kann. Ist diese Vorsichtsmaßnahme sinnvoll oder unnötig?
Was bedeutet übrigens #lang "qb"? Ist mir in QBasic noch nie begegnet.
Nur um mich zur vergewissern, ob ich es richtig verstanden habe:
Dein:
DECLARE SUB p1(p1a AS INTEGER, p1b AS INTEGER, p1c AS INTEGER)
DECLARE SUB p2(p2d AS INTEGER)
DECLARE SUB p3(p3e AS INTEGER, p3f AS INTEGER)
müßte, wenn die SUB's Fritz, Franz und Sophie hießen, also wie folgt aussehen:
DECLARE SUB Fritz(Fritza AS INTEGER, Fritzb AS INTEGER, Fritzc AS INTEGER)
DECLARE SUB Franz(Franzd AS INTEGER)
DECLARE SUB Sophie(Sophiee AS INTEGER, Sophief AS INTEGER)
Richtig?
a = 1, b = 2, c = 3 sind die Werte aus dem Hauptprogramm
Mit diesen Werten würde ich also die SUB Fritz a,b,c aufrufen.
Wie wäre dieser Aufruf sytaktisch korrekt?
1) Fritz a, b, c oder
2) Fritz(a, b, c) oder
3) Fritz a as integer, b as integer, c as integer oder
4) Fritz (a as integer, b as integer, c as integer)
Analog würde es wohl auch für Franz und Sophie gelten.
Ich habe es nicht so mit Worten. Für mich ist mathematisches eher nachvollziehbar. Können wir daher bitte den ganzen Ablauf mal an den konkreten Zahlen a,b,c mit den jeweiligen Zwischen-Ergebnissen durchspielen? Das mag dir auf den ersten Blick nervig erscheinen,
ist letztlich aber zeitsparend bei der Beantwortung dann noch übrig gebliebener Nachfragen meinerseits. Einverstanden?
Oft ist eine bildliche Anschauung hilfreicher, als 1000 Worte es je sein können.
Deshalb nenne ich das Hauptprogramm einfach mal "Chef".
Die SUB's sind quasi die "Angestellten" Fritz, Franz und Spohie.
Der "Chef" gibt die Werte a=1, b=2, c=3 vor und sagt zu den Angestellten: Macht was draus!
Fritz bekommt diese Werte zuerst, wird also vom "Chef" zuerst
angesprochen / aufgerufen, mit der Auflage, sich darum zu kümmern.
Diese Werte liegen Fritz jetzt also als Kopie in den Parametern Fritza, Fritzb, Fritzc vor, richtig?
Fritz erschafft sich eine eigene Variable d mit DIM d as integer
Fritz bestimmt jetzt dieses d aus den ihm übergebenen Parametern:
d = Fritza(mit Wert von a) + Fritzb(mit Wert von b) + Fritzc (mit Wert von c) jetzt müßte also d = 1 + 2 + 3 = 6 gelten, richtig?
Fritz übergibt dieses d = 6 an Franz, der damit weiterrechnen soll.
Er spricht also Franz d an.
d liegt Franz jetzt also als Kopie im Parameter Franzd vor, richtig?
Franz erschafft sich ebenso seine eigenen Variablen e und f,
so wie Fritz es zuvor mit d tat.
DIM e AS INTEGER, f AS INTEGER ' lokal nur in p2
Franz berechnet e und f:
e = 2 * Franz d = 2*6 = 12
f = Franz d - 1 = 6 -1 = 5
Franz gibt e =12 und f =5 an Sophie weiter.
Der entsprechende Aufruf lautet also Sophie e, f
e und f liegen jetzt also als Kopie in Sophie's Parametern mit
Sophie e = 12 und Sophie f = 5 vor.
Sophie erschafft, wie ihre "Kollegen" zuvor, wiederum ihre eigene,
private Variable g mit DIM g as integer
Sophie bestimmt das Endergebnis g:
g = Sophie e - Sophie f in Zahlen also g = 12 - 5 = 7
Jetzt ist es Sophie's Aufgabe, dem "Chef" das Ergebnis g dieser Teamarbeit so zu präsentieren, daß er es bei seiner Steuererklärung verwenden/angeben kann.
Dabei gibt es aber das Problem, daß g per Definition immer noch
Sophie's "Privatsache" ist. So kann der "Chef" nie etwas davon erfahren.
Sophie muß g also quasi "öffentlich " also auch für den "Chef" zugänglich machen, damit ihn ihr Ergebnis g überhaupt erreicht.
Es macht keinen Sinn, etwas für sich behalten zu wollen, wenn man es letztlich doch preisgeben muß, weil der "Chef" nun mal ein Ergebnis erwartet.
Da Sophie das Ergebnis g letztlich sowieso an den "Chef" übergeben muß,
ist ihr privater (locater) Anspruch auf g von Anfang an hinfällig.
Bedeutet:
Statt: DIM g as integer könnte Sophie auch gleich
DIM shared g as integer festlegen.
Soweit erst mal zu meinem Verständnis der Sache.
Ist es so ok.? Oder habe ich dabei trotzdem noch etwas übersehen?
Mal ganz nebenbei:
Deine Geduld mit mir ist bewundernswert.
Du schreibst mir z.B. daß DIM x,y,z as integer nicht korrekt ist, es statt dessen DIM x as integer, y as integer , z as integer heißen müßte. Und ich Dussel habe nichts anderes zu tun, als es im nächsten Moment schon wieder zu vergessen.
Deine Ausführungen und Beiträge sind für mich sehr wertvoll. Sie haben es nicht verdient, derart ignorant behandelt (vergessen) zu werdern, wie ich es tat. Sorry. Ich kann dafür nur Abbitte leisten.
Ich empfinde es als sehr angenehm, von dir zu lernen.
Gruß Revilo |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 17.06.2024, 22:45 Titel: |
|
|
Revilo hat Folgendes geschrieben: | Was wäre denn dann der Unterschied zwischen SUB und Funktion?
Warum sind Funktionen empfehlenswerter, als SUB's? |
Eine SUB und eine FUNCTION unterscheiden sich lediglich darin, dass die FUNCTION einen Rückgabewert liefert und die SUB nicht. Eine FUNCTION ist nicht per se empfehlenswerter als eine SUB, sondern nur, wenn ein sinnvoller Rückgabewert möglich ist (was wiederum recht häufig der Fall ist, da dieser Rückgabewert z. B. auch eine Fehler- bzw. Erfolgsmeldung sein kann).
Zitat: | Besagte Fehlermeldung "Falscher Parameter" hat also eher mit einer falschen Deklarierung meiner Variablen (lokal statt global oder umgekehrt) zu tun. Richtig? |
Die Fehlermeldung kommt vom falschen Datentyp - z. B. du übergibst ein INTEGER, erwartet wird aber ein DOUBLE, oder anders herum.
Zitat: | Um solche "versteckten" Fehler möglichst zu umgehen, gestalte ich z.B.
For - Next - Schleifen immer wie folgt:
i=0
for i=1 to 10
.
. Befehle, SUB's in dieser Schleife
.
next
if i>10 then i=10
So vermeide ich hoffentlich, daß i zufällich durch irgend welche "Schaltfehler" des Computers auf eine unerwartete, unmögliche
11 springen kann. Ist diese Vorsichtsmaßnahme sinnvoll oder unnötig? |
Das Null-Setzen zu Beginn ist überflüssig, weil die Variable i zu Beginn des Schleifendurchlaufs auf den angegebenen Wert 1 gesetzt wird. Wenn die Schleife komplett durchlaufen wird, hat i nach Verlassen der Schleife tatsächlich den Wert 11 - das ist nicht unmöglich, sondern sogar sicher.
https://users.freebasic-portal.de/nemored/buchBeginner/11_schleifen.htm#kap11_4_1
Zitat: | Was bedeutet übrigens #lang "qb"? Ist mir in QBasic noch nie begegnet. |
Entschuldige, das ist eine Unachtsamkeit von mir. Ich habe kein QBasic und nutze FreeBASIC im QBasic-"Kompatibilitätsmodus". Mit dieser Zeile zwinge ich FreeBASIC, den Code so zu behandeln, wie QBasic es tun würde (zumindest weitestgehend). Wenn ich den Code dann hier ins Forum schreibe, lösche ich diese Zeile wieder - aber offenbar nicht immer. Ignoriere die Zeile einfach.
Zitat: | Nur um mich zur vergewissern, ob ich es richtig verstanden habe:
Dein:
DECLARE SUB p1(p1a AS INTEGER, p1b AS INTEGER, p1c AS INTEGER)
DECLARE SUB p2(p2d AS INTEGER)
DECLARE SUB p3(p3e AS INTEGER, p3f AS INTEGER)
müßte, wenn die SUB's Fritz, Franz und Sophie hießen, also wie folgt aussehen:
DECLARE SUB Fritz(Fritza AS INTEGER, Fritzb AS INTEGER, Fritzc AS INTEGER)
DECLARE SUB Franz(Franzd AS INTEGER)
DECLARE SUB Sophie(Sophiee AS INTEGER, Sophief AS INTEGER)
Richtig? |
Soweit richtig.
Zitat: |
a = 1, b = 2, c = 3 sind die Werte aus dem Hauptprogramm
Mit diesen Werten würde ich also die SUB Fritz a,b,c aufrufen.
Wie wäre dieser Aufruf sytaktisch korrekt?
1) Fritz a, b, c oder
2) Fritz(a, b, c) oder
3) Fritz a as integer, b as integer, c as integer oder
4) Fritz (a as integer, b as integer, c as integer)
Analog würde es wohl auch für Franz und Sophie gelten. |
Bei einer SUB ist der Aufruf 1 und 2 möglich. Bei einer FUNCTION sind die Klammern erforderlich, es funktioniert also nur Aufruf 2.
Aufruf 3 und 4 funktionieren nicht. Das "AS INTEGER" steht nur in der DECLARE-Zeile und im Kopf des Unterprogramms, nicht aber beim Aufruf.
Zitat: | Oft ist eine bildliche Anschauung hilfreicher, als 1000 Worte es je sein können.
Deshalb nenne ich das Hauptprogramm einfach mal "Chef".
Die SUB's sind quasi die "Angestellten" Fritz, Franz und Spohie.
[...]
Diese Werte liegen Fritz jetzt also als Kopie in den Parametern Fritza, Fritzb, Fritzc vor, richtig? |
Jein. Es gibt zwei Arten von Übergabemöglichkeit:
BYVAL (by value) erstellt eine Kopie der Variablen, d. h. Fritz kennt z. B. die (nur ihm bekannte) Variable Fritza mit dem Wert 1, kann aber nicht auf a zugreifen. Fritza kann geändert werden, ohne dass es a beeinflusst.
BYREF (by reference) übergibt eine Referenz auf die Variable. Fritz kann zwar auch hier nicht direkt die Variable a aufrufen, wenn er aber Fritza ändert, ändert sich auch der Wert von a. Diese Übergabemethode ist die Standardmethode in QBasic.
Zitat: | Fritz erschafft sich eine eigene Variable d [...]
jetzt müßte also d = 1 + 2 + 3 = 6 gelten, richtig? |
Richtig.
Zitat: | Fritz übergibt dieses d = 6 an Franz, der damit weiterrechnen soll.
Er spricht also Franz d an.
d liegt Franz jetzt also als Kopie im Parameter Franzd vor, richtig? |
Analog zu oben keine echte Kopie, aber ansonsten richtig.
Zitat: | Statt: DIM g as integer könnte Sophie auch gleich
DIM shared g as integer festlegen. |
Das kann Sophie tatsächlich nicht. Globale Variablen anlegen darf nur der Chef (also das Hauptprogramm). Wenn der Chef das aber macht, kann Sophie in diese Variable das Ergebnis hineinschreiben.
Zitat: | Mal ganz nebenbei:
Deine Geduld mit mir ist bewundernswert.
Du schreibst mir z.B. daß DIM x,y,z as integer nicht korrekt ist, es statt dessen DIM x as integer, y as integer , z as integer heißen müßte. Und ich Dussel habe nichts anderes zu tun, als es im nächsten Moment schon wieder zu vergessen.
Deine Ausführungen und Beiträge sind für mich sehr wertvoll. Sie haben es nicht verdient, derart ignorant behandelt (vergessen) zu werdern, wie ich es tat. Sorry. Ich kann dafür nur Abbitte leisten.
Ich empfinde es als sehr angenehm, von dir zu lernen. |
Ach was, Vergesslichkeit ist keine Ignoranz. Beim Programmieren gibt es so viele Dinge zu beachten, da muss man vieles mehrmals machen, bis es sich festigt. _________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
Revilo
Anmeldungsdatum: 26.12.2022 Beiträge: 149
|
Verfasst am: 19.06.2024, 20:00 Titel: |
|
|
Hallo nemored,
wie immer vielen Dank.
Bitte laß mich deine letzte Antwort mal auf den Kern zusammenfassen,
soweit ich ihn jetzt verstanden habe :
1) Schleifen:
i=0 ist zu Beginn einer Schleife unnötig
if i>10 then i=10 nach einer Schleife aber sinnvoll, um zu vermeiden, daß mit einer ungewollten 11 weiterechnet wird. Der Rechner kann nun mal kein Feld(11) bearbeiten, wenn es nur
von 1 bis 10 dimensioniert ist. Richtig?
2) Fehlermeldung "Falscher Parameter"
Originalwert und Parameter einer SUB, an den der Originalwert
übergeben wird, müssen denselben Datentyp haben.
Eine SUB die in ihrem Parameter eine kg - Angabe erwartet, kann
natürlich mit einer °C - Angabe nichts anfangen. 100 °C und 100 kg
haben zwar denselben Zahlenwert (hier eben 100), sind aber trotzdem
zwei ganz verschiedene Dinge.
So ist also eine (integer) - 7 etwas anderes, als eine (single) -7.
Integer = ganze Zahl ohne Kommastelle
Single, Double, Long = reelle Zahl mit Kommastelle, je nach
gewünschter Genauigkeit/Stellenanzahl.
Richtig?
3) DIM shared... ist grundsätzlich "Chef-Sache". Richtig?
4) BYVAL (by value) und BYREF (by reference):
Ist das auch wieder ein FreeBasic-Syntax? In QBasic kenne ich es nicht.
Bitte laß mich mal vermuten:
Es ist, bildlich gesprochen, wie beim Duden. Man sucht die Schreibweise eines einzigen Wortes, bzw. dien Inhalt eioner bestimmten Variable a.
Möglichkeit 1) also BYVAL (by value):
Ich kaufe mir einen kompletten Duden (also quasi eine Kopie des "Original-Dudens" bzw. der Variablen a), blätterte darin, bis ich weiß, wie besagtes Wort zu schreiben ist.
Das kostet aber Geld, respektive Speicherplatz und Zeit.
Möglichkeit 2) also BYREF (by reference):
Hier gibt es offenbar einen Tipp, einen "Zeiger":
Nach dem Motto:
In der örtlichen Bibliothek steht ein Duden.
Das gesuchte Wort steht z.B. auf Seite 162.
Dann lese ich eben dort nach und weiß auch, wie das jeweilige Wort zu schreiben ist, bzw. welchen Inhalt die Variable a hat.
Ich brauche also keine "Duden-Kopie" zu kaufen.
Daß diese Methode QBasic-Standard ist, ist daher nur zu begrüßen.
5) Aufruf einer SUB:
Offenbar ist also Syntax 2)
- Fritz(a, b, c) - korrekt
Mit Klammern kann ich beim Aufruf also sowohl bei SUB' s als auch bei Funktionen nichts verkehrt machen. Richtig?
Bei deinem Zitat:
Das "AS INTEGER" steht nur in der DECLARE-Zeile und im Kopf des Unterprogramms, nicht aber beim Aufruf.
bin ich mir vom Verständnis her noch nicht ganz sicher.
Könntest du mir das am Beispiel der SUB Fritz nochmal kurz
darlegen?
Vielen Dank, Revilo |
|
Nach oben |
|
|
nemored
Anmeldungsdatum: 22.02.2007 Beiträge: 4679 Wohnort: ~/
|
Verfasst am: 19.06.2024, 20:58 Titel: |
|
|
Zu 1)
Es hängt davon ab, was du mit i nach der Schleife noch anfangen willst. Da es sich um die Laufvariable der FOR-Schleife handelt, will man mit ihr außerhalb der Schleife meist nichts mehr anstellen. Dann ist ein Heruntersetzen auf i=10 nicht mehr nötig. Umgekehrt kann man die Eigenart nutzen, um zu prüfen, ob die Schleife komplett durchlaufen wurde oder zuvor abgebrochen wurde.
Zitat: | DIM i AS INTEGER
DIM werte(10)
' [...]
FOR i = 1 TO 10
IF werte(i) >= 100 THEN EXIT FOR
NEXT
IF i = 11 THEN PRINT "Alle Werte sind kleiner als 100." |
Zu 2)
Im Großen und Ganzen richtig. SINGLE und DOUBLE sind Zahlen mit Nachkommastellen (einfache und doppelte Genauigkeit). INTEGER und LONG sind ganze Zahlen, wobei ich nicht weiß, welchen Zahlenbereich sie in QBasic einnehmen.
Zu 3)
Richtig.
Zu 4)
Um im Bild zu bleiben: Eine eigene Kopie des Dudens hat den Vorteil, dass ich Textstellen markieren und Anmerkungen hineinschreiben kann. Das kann ich beim Leihduden natürlich auch, aber die anderen Nutzer werden davon ganz und gar nicht begeistert sein. Auf das Programm übertragen: Auf eine als Referenz übergebene Variable musst du besser aufpassen.
Zu 5)
Mit den Klammern machst du auf jeden Fall nichts verkehrt.
Code: | DECLARE SUB fritz(fritzA AS INTEGER, fritzB AS INTEGER, fritzC AS INTEGER)
' Hier ist die Angabe der Datentypen sehr zu empfehlen. Es geht in QBasic auch ohne, aber dann sollte man genau wissen, was intern passiert.
DIM a AS INTEGER, b AS INTEGER, c AS INTEGER
fritz(a, b, c)
' hier keine Angabe der Datentypen. Die Datentypen von a, b und c liegen ja durch die DIM-Zeile fest.
SUB fritz(fritzA AS INTEGER, fritzB AS INTEGER, fritzC AS INTEGER)
' hier wieder: Angabe der Datentypen sehr empfehlenswert
' [...]
END SUB |
_________________ Deine Chance beträgt 1:1000. Also musst du folgendes tun: Vergiss die 1000 und konzentriere dich auf die 1. |
|
Nach oben |
|
|
|
|
Du kannst keine Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum nicht antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen.
|
|