Manueller Zähler

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Vermilion
Beiträge: 1846
Registriert: 08.04.2006 16:00
Computerausstattung: Apple iMac (2010) & HP Notebook
Wohnort: Heidekreis

Manueller Zähler

Beitrag 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...
Bild

Immer die neueste PureBasic Version. Auf allem Betriebssystemen. Ich bin ein OS-Nomad!
Christian+
Beiträge: 213
Registriert: 13.07.2008 10:05
Computerausstattung: Windows 8.1 Pro
AMD Phenom II X4 955 @ 3.2 GHz
4GB RAM
NVIDIA GeForce GTX 660

Re: Manueller Zähler

Beitrag 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
Windows 8.1 Pro 64Bit | AMD Phenom II X4 955 @ 3.2 GHz | 4GB RAM | NVIDIA GeForce GTX 660
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Manueller Zähler

Beitrag 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 
Christian+
Beiträge: 213
Registriert: 13.07.2008 10:05
Computerausstattung: Windows 8.1 Pro
AMD Phenom II X4 955 @ 3.2 GHz
4GB RAM
NVIDIA GeForce GTX 660

Re: Manueller Zähler

Beitrag 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.
Windows 8.1 Pro 64Bit | AMD Phenom II X4 955 @ 3.2 GHz | 4GB RAM | NVIDIA GeForce GTX 660
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Manueller Zähler

Beitrag 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.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Manueller Zähler

Beitrag 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 
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Manueller Zähler

Beitrag 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.
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8809
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Manueller Zähler

Beitrag von NicTheQuick »

Hab grad wenig Zeit, aber ein Hinweis dazu. Character ist eine Struktur und kein nativer Datentyp. Siehe Werkzeuge -> Strukturverzeichnis.
ullmann
Beiträge: 205
Registriert: 28.10.2005 07:21

Re: Manueller Zähler

Beitrag 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.
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7031
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Manueller Zähler

Beitrag 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)
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
Antworten