![Das deutsche QBasic- und FreeBASIC-Forum Foren-Übersicht](misc/logos/logo.png) |
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 |
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 16.10.2013, 15:37 Titel: |
|
|
Mein Beispiel sollte zeigen dass -1 eigentlich nicht richtig ist, weil man sich normalerweise nicht darauf verlassen sollte das der String eine bestimmte länge hat. Wenn man mit -4 arbeitet besteht dieses ganze Problem nicht! |
|
Nach oben |
|
![](templates/subSilver/images/spacer.gif) |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1211 Wohnort: Ruhrpott
|
Verfasst am: 17.10.2013, 07:09 Titel: |
|
|
@RockTheSchock: Auf die Gefahr hin, mich zu wiederholen: Wenn du auf diese Weise mit Pointern arbeitest, mußt du sicherstellen, daß der String die richtige Länge hat, und zwar, bevor du anfängst, ihn zu bearbeiten!
Vielleicht kann ich dir das veranschaulichen:
Angenommen, du hast einen String "g" von 8 Byte Länge, der bei Adresse 1000 beginnt1000 |
1001 | 1. Wert
1002 |
1003 |__
1004 |
1005 | 2. Wert
1006 |
1007 |__
1008 | undefinierter Inhalt
1009 | undefinierter Inhalt
1010 | undefinierter Inhalt
1011 | undefinierter Inhalt
1012 | undefinierter Inhalt
... Dann hat StrPtr(g) einen Wert von 1000 und Len(g) einen Wert von 8. Und nun halte dir vor Augen, wie eine For/Next-Schleife funktioniert:Zuerst wird die Laufvariable auf den Anfangswert gesetzt und die Schleife einmal durchlaufen.
Dann wird zur Laufvariable die Schrittweite addiert und geprüft, ob dieser Wert größer ist als der Endwert.
Wenn nicht, wird die Schleife noch einmal durchlaufen, wenn ja, wird das Programm fortgesetzt. Für unser Beispiel heißt das:
Anfangswert: StrPtr(g) = 1000
Schrittweite: SizeOf(Single) = 4
Endwert: StrPtr(g) + Len(g) - 1 = 1007
Wert der Laufvariable vor dem 1. Schleifendurchlauf: 1000
Wert der Laufvariable nach dem 1. Schleifendurchlauf: 1000 + 4 = 1004 ---> 1004 < 1007 ---> Schleife wiederholen
Wert der Laufvariable nach dem 2. Schleifendurchlauf: 1004 + 4 = 1008 ---> 1008 > 1007 ---> Schleife beenden und Programm fortsetzen Das wäre der korrekte Ablauf. Bei einer Pointerlänge von 4 Bytes funktioniert das Ganze auch noch bisEndwert: StrPtr(g) + Len(g) - 4 = 1004
...
Wert der Laufvariable nach dem 1. Schleifendurchlauf: 1000 + 4 = 1004 ---> 1004 = 1004 ---> Schleife wiederholen
... Aber stell dir vor, du hättest jetzt statt einem SinglePtr einen BytePtr mit einer Länge von 1. Dann würden die letzten 3 Werte des Strings überhaupt nicht gelesen. Wenn andererseits der String eine Länge von 9 Bytes hätte, bekämst du einen weiteren SchleifendurchlaufEndwert: StrPtr(g) + Len(g) - 1 = 1008
...
Wert der Laufvariable nach dem 2. Schleifendurchlauf: 1004 + 4 = 1008 ---> 1008 = 1008 ---> Schleife wiederholen
Wert der Laufvariable nach dem 3. Schleifendurchlauf: 1008 + 4 = 1012 ---> 1012 > 1008 ---> Schleife beenden und Programm fortsetzen
... Wenn du nur lesend auf den Speicher zugreifst, passiert nicht viel, außer, daß du beim letzten Wert Datenmüll bekommst. Solltest du jedoch in die 3 Speicherstellen hinter dem String schreiben, kannst du Glück haben, daß diese gerade nicht benutzt werden, es kann aber auch sein, daß dort eine andere Variable abgelegt ist, beispielsweise ein Integer-Wert, der irgendwo anders im Programm gebraucht wird. Dann veränderst du dessen Inhalt und produzierst damit einen der fiesesten Fehler, die es gibt: Es gibt keine Fehlermeldung und mit hoher Wahrscheinlichkeit auch keinen Programmabsturz, du hast nur plötzlich irgendwo anders einen falschen Wert. Und da beim nächsten Programmstart die Variablen höchstwahrscheinlich an einer anderen Position stehen, ist der Fehler auch nicht reproduzierbar und tritt selten und in unregelmäßigen Abständen auf. Nach sowas kannst du dich monatelang totsuchen.
Wenn du mit den Stringfunktionen arbeitest, sorgt der Compiler dafür, daß es keine verbotenen Speicherzugriffe gibt, das macht die Sache aber auch sehr langsam. Zugriffe über Pointer sind sehr viel schneller, dafür mußt du dich aber selber um die Integrität der Daten kümmern und solltest genau wissen, was du tust. Das hat schon einen Hauch von Assemblerprogrammierung.
Also noch einmal: Du bist für die korrekte Länge des Strings verantwortlich, und der korrekte Endwert für alle Pointerarten ist StrPtr(g) + Len(g) - 1
Gruß
grindstone |
|
Nach oben |
|
![](templates/subSilver/images/spacer.gif) |
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 17.10.2013, 08:55 Titel: |
|
|
Zitat: | Aber stell dir vor, du hättest jetzt statt einem SinglePtr einen BytePtr mit einer Länge von 1 |
Ich habe ja extra geschrieben dass es korrekterweise heißen muss:
-SizeOf(DATENTYP) was bei Single -4 ist bei byte aber -1 und bei Double halt -8
Dadurch ist sichergestellt das egal was an die Funktion übergeben wird kein falscher Speicherbereich überschrieben wird.
Und die beiden For schleifen vor und nach dem Funktionsaufruf dienen lediglich zur Anschaung, zum Gucken was im Speicher passiert. |
|
Nach oben |
|
![](templates/subSilver/images/spacer.gif) |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1211 Wohnort: Ruhrpott
|
Verfasst am: 18.10.2013, 11:07 Titel: |
|
|
@RockTheSchock: Ich habe mir eben alle posts noch einmal durchgelesen und fürchte, daß ich dich die ganze Zeit falsch verstanden habe.
Wenn du ein Programm zu Testzwecken gezielt mit falschen Daten fütterst, um einen Fehler zu provozieren, solltest du das deutlich dazuschreiben. So wie du das formuliert hast, wirkt es so, als ob du nicht wirklich weißt, was du tust und ratlos bist, warum das Programm immer wieder falsche Ergebnisse liefert.
Im übrigen muß ich dir recht geben: -SizeOf(DATENTYP) ist bei fehlerhafter Stringlänge sicher gegen unerwünschte Seiteneffekte durch falsches Schreiben in den Speicher.
Gruß
grindstone |
|
Nach oben |
|
![](templates/subSilver/images/spacer.gif) |
RockTheSchock
Anmeldungsdatum: 04.04.2007 Beiträge: 138
|
Verfasst am: 18.10.2013, 12:29 Titel: |
|
|
Zitat: | Ich habe mir eben alle posts noch einmal durchgelesen und fürchte, daß ich dich die ganze Zeit falsch verstanden habe. |
Tut mir leid, dass ich mich nicht genau genug ausgedrückt habe. Das war ein gutes Beispiel wie man Konfusion erzeugt, indem man keine vernünftigen Kommentare schreibt. Ich hätte einfach nur einen kleinen Kommentar zu meinem Testcode einfügen müssen und einen Kommentar inderhalb der Funktion ampfloat zur Schleifenabbruchbedingung.
Schon hätten wir uns die halbe Diskussion sparen können. |
|
Nach oben |
|
![](templates/subSilver/images/spacer.gif) |
grindstone
Anmeldungsdatum: 03.10.2010 Beiträge: 1211 Wohnort: Ruhrpott
|
Verfasst am: 19.10.2013, 08:47 Titel: |
|
|
Zitat: | Schon hätten wir uns die halbe Diskussion sparen können. |
Sieh es mal positiv: Für den einen oder anderen derjenigen, die diesen Thread still im Hintergrund verfolgen, hat das Ganze sicher einen Erkenntnisgewinn gebracht.
Gruß
grindstone _________________ For ein halbes Jahr wuste ich nich mahl wie man Proggramira schreibt. Jetzt bin ich einen! |
|
Nach oben |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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.
|
|