Seite 1 von 2

Manueller Zähler

Verfasst: 09.08.2011 16:05
von Vermilion
Ich werde bekloppt. Ich versuche das nun schon seit 3 Stunden. Frustrierend ist, das ich das damals in der Berufsschule im Fach Digitaltechnik sogar hatte, einen Binärzähler bauen, also das so in etwa.

Ich habe eine (möglicherweise sehr, sehr, sehr große) Ganzzahl in Form eines Strings. Nun will ich immer um 1 inkrementieren. Wenn das "Ende" des Zahlensystems erreicht ist (in diesem Falle 9), wir beim nächsten Durchlauf die Ziffer auf 0 zurückgesetzt und die nächste Stelle um 1 erhöht.

Der einzige Ansatz, der bisher erfolgreich war, waren verschachtelte For-To Schleifen, die allerdings eine feste Ziffernanzahl voraussetzen. :(

Ich weiß nicht, ob es etwas bringt, Code zu posten. Habe gut ein Dutzend Ansätze (die Hälfte verworfen) gemacht, die alle nicht das gewünschte Ergebnis brachten. /:->

Sowas bzw. Mathe war nie mein Ding...

Re: Manueller Zähler

Verfasst: 09.08.2011 17:42
von Christian+
Meinst du in etwas in die Richtung ?

Code: Alles auswählen

Structure char
  c.c[0]
EndStructure

Procedure.s Inkrementieren(Zahl.s)
  Protected *char.char = @Zahl
  Protected Pos.i
  For Pos = Len(Zahl) - 1 To 0 Step -1
    If Chr(*char\c[Pos]) = "9"
      *char\c[Pos] = Asc("0")
    Else
      *char\c[Pos] = *char\c[Pos] + 1
      ProcedureReturn Zahl
    EndIf
  Next
  ProcedureReturn "1" + Zahl
EndProcedure

Define Zahl.s
Define i.i

For i = 1 To 20
  
  Zahl = Inkrementieren(Zahl)
  Debug Zahl
  
Next

Re: Manueller Zähler

Verfasst: 09.08.2011 17:45
von NicTheQuick
Etwas hübscher bzw. ohne Verwendung von Chr() und Asc(). :wink:

Aber das mit den beiden Endbedingungen gefällt mir sehr gut! :)

Code: Alles auswählen

Structure char
	c.c[0]
EndStructure

Procedure.s Inkrementieren(Zahl.s)
	Protected *char.char = @Zahl
	Protected Pos.i = Len(Zahl) - 1
	While Pos >= 0
		If *char\c[Pos] = '9'
			*char\c[Pos] = '0'
		Else
			*char\c[Pos] + 1
			ProcedureReturn Zahl
		EndIf
		Pos - 1
	Wend
	ProcedureReturn "1" + Zahl
EndProcedure

Define Zahl.s
Define i.i

For i = 1 To 20
	
	Zahl = Inkrementieren(Zahl)
	Debug Zahl
	
Next 

Re: Manueller Zähler

Verfasst: 09.08.2011 17:54
von Christian+
@NicTheQuick
Super so ist es natürlich viel besser. Ich hatte gar nicht dran gedacht dass ich auf Chr() und Asc() verzichten kann.

Re: Manueller Zähler

Verfasst: 09.08.2011 22:20
von ullmann
Hier habe ich aber ein Verständnisproblem:

Laut Hilfe muss der Maximalindex für ein statisches Array in einer Struktur um eins größer sein als der tatsächlich nutzbare Maximalindex:
Bitte beachten Sie, dass sich in Strukturen ein statisches Array[] nicht so verhält wie das normale BASIC Array (definiert mittels Dim), um konform zum C/C++ Strukturen Format zu bleiben (was direkte API Strukturen Portierung ermöglicht). Dies bedeutet, dass a[2] ein Array von 0 bis 1 definiert, wogegen Dim a(2) ein Array von 0 bis 2 anlegt.
Das Beispiel aus der Hilfe:

Code: Alles auswählen

Structure Window
    *NextWindow.Window  ; verweist auf ein anderes Window Objekt
    x.w 
    y.w
    Name.s[10]  ; 10 Namen verfügbar (von 0 bis 9)
  EndStructure
Also: [10] bedeutet verfügbare Indizes von 0 bis 9, [2] bedeutet verfügbare Indizes von 0 bis 1, spinne ich diesen Gedanken weiter: [1] bedeutet verfügbarer Index 0, aber [0] ????? Verfügbarer Index von 0 bis -1 ???? Was bedeutet also [0] ?

Ich vermute mal, dass [0] ebenfalls den Index 0 ermöglicht. Dem widerspricht aber der folgende Code:

Code: Alles auswählen

*char\c[Pos] = Asc("0")
Bei einer 19-stelligen Zahl wäre Pos anfangs gleich 18. Ich greife über den Zeiger *char auf die mit dem Zeiger verbundene Struktur char zu, und zwar auf deren Element c, welches ein statisches Array ist, und bei diesem Array auf den Index 18, der wegen der Dimensionierung mit [0] gar nicht gültig sein dürfte - warum kommt hier kein Index-Überlauf-Fehler und warum funktioniert das Ganze trotzdem?

Nächster Punkt: Eigentlich wollte ich schreiben, dass nirgendwo in der Hilfe steht, dass man Apostrophe verwenden kann. Ich habe nun extra mehrfach in der Hilfe gesucht (bei Variablen, Typen und Operatoren sowie bei Allgemeine Syntaxregeln) und bin bei Strings - Asc fündig geworden:
Hinweis: Es ist ebenfalls möglich, den ASCII-Wert eines Zeichens (aber nicht von einer Zeichenkette) zu erhalten, indem man dieses zwischen Apostrophe setzt.
Beispiel:

ASCII = '!' ; 'ASCII' erhält den Wert '33'
Da die Apostrophe die eingeschlossene Zeichen-Konstante in einen Wert umwandeln, wäre ein zusätzlicher Eintrag bei Operatoren sinnvoll. Und da Apostrophe auch eine zulässige Schreibweise sind, sollten sie auch bei Allgemeine Syntaxregeln erwähnt werden.

Zurück zum erstgenannten Punkt.

Manchmal liest man hier im Forum: "Dies und das wird nicht unterstützt. Funktioniert es trotzdem, so kann dies in späteren Versionen nicht mehr der Fall sein". Rein von der Argumentation trifft dieses hier auch zu, wobei mir das Ganze hier jedoch durchdacht und sinnvoll vorkommt, so dass ich vermute, dass es auch in zukünftigen PB-Versionen noch funktionieren wird. Aber es wäre schön, wenn PB-Hilfe aktualisiert werden würde und wenn mir bitte mal jemand die Bedeutung von [0] erklären könnte.

Re: Manueller Zähler

Verfasst: 09.08.2011 22:32
von NicTheQuick
[0] bedeutet einfach, dass das Strukturmember die Größe Null hat, aber im späteren Verlauf Indexüberläufe ignoriert werden.
Ich glaube mich daran zu erinnern, dass das auch mal von offizieller Seite gesagt wurde oder sogar irgendwo versteckt in der Hilfe steht. Jedenfalls hat sich es noch nie geändert. Würde das geschehen, würden aber sicherlich genug anfangen zu meckern, da das so für Zeigerarithemtik recht praktisch ist.

Im Zweifelsfall hier noch eine weitere Version:

Code: Alles auswählen

Procedure.s Inkrementieren(Zahl.s)
   Protected *char.Character = @Zahl + (Len(Zahl) - 1) * SizeOf(Character)
   While *char >= @Zahl
      If *char\c = '9'
         *char\c = '0'
      Else
         *char\c + 1
         ProcedureReturn Zahl
      EndIf
      *char - SizeOf(Character)
   Wend
   ProcedureReturn "1" + Zahl
EndProcedure

Define Zahl.s
Define i.i

For i = 1 To 20
   
   Zahl = Inkrementieren(Zahl)
   Debug Zahl
   
Next 

Re: Manueller Zähler

Verfasst: 09.08.2011 22:55
von ullmann
Danke.

Das ist eine sehr gute Erklärung.

Aber nun noch eine Frage. Warum gibst du hier:

Code: Alles auswählen

Protected *char.Character = @Zahl + MemoryStringLength(@Zahl) - SizeOf(Character)
bei dem Zeiger *char den Typ .Character an? Wenn ich es richtig verstehe, ist Character keine Struktur, sondern ein Basistyp. Und in der Hilfe steht, dass Zeigervariablen immer 32 oder 64 Bit groß sind, so dass die Angabe eines Types (ausgenommen Strukturen) nicht sinnvoll ist.
Als eine Konsequenz daraus hängt der Typ des Zeigers vom CPU-Adressmodus ab ('Long' auf 32 Bit CPU und 'Quad' auf 64 Bit zum Beispiel), so ist ein Zeiger eine Variable vom Typ Zeiger.
Daraus resultiert, dass das Zuweisen eines Typs zu einem Zeiger (*Pointer.l , *Pointer.b …) keinen Sinn macht.
Würde es also auch so funktionieren?

Code: Alles auswählen

Protected *char = @Zahl + MemoryStringLength(@Zahl) - SizeOf(Character)
Obwohl du den Zeiger *char nicht mit der Struktur char verknüpfst, kannst du dennoch auf das Strukturmember c zugreifen?

Code: Alles auswählen

If *char\c = '9'
Zählt i von 1 bis 20 inkrementiert deine Funktion aber die Zahlen von 1 bis 40 laut Debug-Ausgabe.

Re: Manueller Zähler

Verfasst: 09.08.2011 23:55
von NicTheQuick
Hab grad wenig Zeit, aber ein Hinweis dazu. Character ist eine Struktur und kein nativer Datentyp. Siehe Werkzeuge -> Strukturverzeichnis.

Re: Manueller Zähler

Verfasst: 10.08.2011 00:11
von ullmann
Hm, ich weiß nicht.

Character steht in der Hilfe unter Basic Typen. Und im Strukturverzeichnis steht auch Word, aber das ist ja sicher keine Struktur.

Re: Manueller Zähler

Verfasst: 10.08.2011 00:17
von STARGÅTE
Character hat die Struktur:

Code: Alles auswählen

Structure Character
  c.c
EndStructure
Was du meinst wäre nur .c, das ist der Basistyp Character.
Aber .Character ist die Struktur da oben.

Mit ihrer Hilfe kann man schneller im Speicher zB hier ein Character lesen.
*Buffer.Character\c = 3
ist Äquivalent mit
PokeC(*Buffer, 3)