Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Why do FOR/NEXT variables end up +1 more?
#1
I vaguely remember something about this at the old .com forum, but I forget the reason, so I thought I'd just ask about it here.

Why are variable used with FOR/NEXT +1 more at the end?  I was doing a count using a FOR/NEXT variable and couldn't figure out why afterwards the variable end up +1 number higher when over. 

In this example, the FOR/NEXT prints all 10 t's, but when printing the last t value over, it's at 11, and the FOR/NEXT never went to 11.  Why is that?

- Dav

Code: (Select All)

'print 10 t's

For t = 1 To 10 'stop t at 10
    Print t
Next

'so t is 10...but...

Print
Print
Print t 'this show 11 now?

Find my programs here in Dav's QB64 Corner
Reply
#2
It's because `FOR` works by first incrementing the loop variable and then checking if it is greater than the end value you gave. For your loop, the first time `t` is greater is when it is incremented to 11.

The reason it works this way is because depending on your `STEP` and what end number you use, you might not hit the last number at all and instead skip right over it. Imagine you did this:

Code: (Select All)

For t = 1 To 10.5 Step 1
Next
Print t ' What should t be?

Obviously `t` cannot be 10.5 at the end because 10.5 will never be hit by the loop. Instead it works identical to your loop,`t` gets incremented to 11 and since that's greater than 10.5 the loop stops there.
Reply
#3
Oh I see. Thank you for the explanation.  

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#4
BASIC always behaved this way about FOR... NEXT. Since Dartmouth. Many programs depend on this "quirk".

This could cause problems with an _UNSIGNED variable used like this:
Code: (Select All)
DIM u AS _UNSIGNED INTEGER
FOR u = 10 TO 0 STEP -1
PRINT u
NEXT

Expect "u" to be -1? Read the code again. Or if it were possible in QuickBASIC to compile in debug mode it would return a runtime error. This is something that never occurred to me while using QuickBASIC or QBasic. (scratch head)
Reply
#5
(08-24-2023, 01:02 PM)mnrvovrfc Wrote: BASIC always behaved this way about FOR... NEXT. Since Dartmouth. Many programs depend on this "quirk".

This could cause problems with an _UNSIGNED variable used like this:
Code: (Select All)
DIM u AS _UNSIGNED INTEGER
FOR u = 10 TO 0 STEP -1
PRINT u
NEXT

Expect "u" to be -1? Read the code again. Or if it were possible in QuickBASIC to compile in debug mode it would return a runtime error. This is something that never occurred to me while using QuickBASIC or QBasic. (scratch head)

Now I wasn't expecting that ... u ends up with a value of 65535, the max value.  Interesting.

EDIT: u ends up as -1 in QBJS however.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#6
@Dav I ran across something that might be useful aside from @mnrvovrfc comments above.

From the Wiki in turn...

https://qb64phoenix.com/qb64wiki/index.php/DO...LOOP
Quote:
  • DO UNTIL or DO WHILE used with LOOP: The condition is evaluated before running the loop code.
    UNTIL checks if the condition is false each time before running code.
    WHILE checks if the condition is true each time before running code.
  • DO used with LOOP UNTIL or LOOP WHILE: The code block will run at least once:
    UNTIL checks if the condition is false before running loop code again.
    WHILE checks if the condition is true before running loop code again.

https://qb64phoenix.com/qb64wiki/index.php/FOR...NEXT
Quote:
  • NEXT ends the FOR loop code block and increments the counter to the next value even when it exceeds the stop limit.

https://qb64phoenix.com/qb64wiki/index.php/WHILE...WEND
Quote:
  • statements will execute repeatedly while condition is a non-zero value.
  • EXIT WHILE can be used for emergency exits from the loop in QB64 only.
  • A DO...LOOP can use the same DO WHILE condition to get the same results.
  • WHILE loops only run if the WHILE condition is True.

https://qb64phoenix.com/qb64wiki/index.php/UNTIL
Quote:
  • Only one conditional evaluation can be made at the start or the end of a DO...LOOP.
  • DO UNTIL evaluates a condition before and inside of the loop. The loop may not run at all.
  • LOOP UNTIL evaluates a condition inside of the loop. It has to loop once.
  • Skips the loop or loops until an evaluation becomes True.

I ran into a unique situation where I needed to switch from a `FOR..NEXT` to a `DO: LOOP UNTIL` last night.

It was regarding this `str_shuffle$` function I wrote for my library:



I was using a `FOR..NEXT` but the issue was after exiting, I was doing something in an older version of this which was attempting to use the FINAL value of `i%` (my goto var name for iterator) using `ASC(s$, i%)` which exceeded the length of the string by 1.

I dogmatically reach for `FOR..NEXT` but will no longer. I wanted to share the findings with you Smile

Also what do you think this word is using code from above? Big Grin (@a740g can't play he cheats! (I shared this with him already on discord Big Grin))

Code: (Select All)
EMUCPSTOR
TSPURMCEO
MRCSTPOUE
TCUSEPRMO
MOTEUPRSC
CPSMEOTRU
OPECSUTRM
MEROUSCPT
TPROECSMU
RSETPOUMC
USECOMTPR
OCTMRPSEU
UCEORMTPS
SUPORCTME
RMPUCSTOE
MTERCSOPU
UPSMCOETR
CRPMTOUES
PEMRCOSTU
EOPCRUMST
CPSRMTOEU
UMRSOTEPC
POCSUTMER
URTMOESPC
UPCRTOSME
PREUOSTCM
TROEUSCPM
MOUPRSTEC
PCOETURMS
PUOSTERCM


I'm happy to be wrong and corrected and scolded about my code, BTW!

If you guys know of a better way to shuffle a string than this! @a740g already told me I shouldn't modify the control variable.

But @a740g I found this:
Quote:Avoid changing the FOR counterVariable's value inside of the loop. This obfuscates code and is a poor programming practice.
Once the loop has been started, changing the variables holding the startValue, stopValue or increment value will not affect loop execution.

And actually I'm not even using a `FOR..NEXT` any more.

...

But not to hijack the thread. It's relevant share in context, and wanted to make sure to share with others.

@Dav it's a serendipitous coincidence so sorry for the intrusion if you feel slighted by this slightly off-topic but-similar share.
grymmjack (gj!)
GitHubYouTube | Soundcloud | 16colo.rs
Reply
#7
If it is important that no last value is assigned, one can cancel it with "If ... Exit ... End If".

Code: (Select All)

'For - Next, letzten zugewiesenen Wert verhindern - 24. Aug. 2023

$Console:Only
Option _Explicit

Dim As Integer i, j

For i = 1 To 5
  Print i
Next

Print

'Wert ist jetzt 6, da die letzte Pruefung
'der Abbruchbedingung noch an i uebergeben wird.
Print i * 5

Print: Print
Print "Letzte Zuweisung verhindern"

Print
For j = 1 To 5 Step 1
  Print j
  If j = 5 Then
    'Keine Zuweisung mehr
    Exit For
  End If
Next

Print
Print j * 5

End
Reply
#8
Addition with While ... Wend.

Code: (Select All)

'For - Next, letzten zugewiesenen Wert verhindern - 24. Aug. 2023

$Console:Only
Option _Explicit

Dim As Integer i, j, k

For i = 1 To 5
  Print i
Next

Print

'Wert ist jetzt 6, da die letzte Pruefung
'der Abbruchbedingung noch an i uebergeben wird.
Print i * 5

Print: Print
Print "Letzte Zuweisung verhindern"

Print
For j = 1 To 5 Step 1
  Print j
  If j = 5 Then
    'Keine Zuweisung mehr
    Exit For
  End If
Next

Print
Print j * 5

Print: Print
Print "Im Gegensatz zu QuickBasic und QBasic funktioniert ein"
Print "Abbruch mit >Exit While< auch in QB64; aber nur dort."

While k < 10
  k = k + 1
  Print k
  If k = 5 Then
    Exit While
  End If
Wend

Print
Print k
Print
Print k * 5

End
Reply
#9
Thanks for the info, @grymmjack & @kernelpanic.

About the word scramble puzzle thing grymmjack, hmm... I can't see it yet but will take a closer look...  I like puzzles.

- Dav

Find my programs here in Dav's QB64 Corner
Reply
#10
(08-24-2023, 12:51 PM)DSMan195276 Wrote: It's because `FOR` works by first incrementing the loop variable and then checking if it is greater than the end value you gave. For your loop, the first time `t` is greater is when it is incremented to 11.

The reason it works this way is because depending on your `STEP` and what end number you use, you might not hit the last number at all and instead skip right over it. Imagine you did this:

Code: (Select All)

For t = 1 To 10.5 Step 1
Next
Print t ' What should t be?

Obviously `t` cannot be 10.5 at the end because 10.5 will never be hit by the loop. Instead it works identical to your loop,`t` gets incremented to 11 and since that's greater than 10.5 the loop stops there.
Hey @DSMan195276 Since you used backticks, they work everywhere now to show as code inline like in discord. Also you can use 3 backticks for a regular qb codeblock.

Trying the reply to you since it's quoting the backticks to see what will happen Smile

Thanks
grymmjack (gj!)
GitHubYouTube | Soundcloud | 16colo.rs
Reply




Users browsing this thread: 1 Guest(s)