For loop doesn't terminate as expected

I'm trying to show the execution sequence in a for loop, where the syntax is explained as:

for (expression1; expression2; expression3) {
// statement(s) of for loop body
}

To demonstrate the sequence, I use the following code:

void setup() {
  int k;
  
  Serial.begin(115200);
  
  for (k = 0,      Serial.print("Expression1 k = "), Serial.println(k);     // Expression 1
       k < 10,     Serial.print("Expression2 k = "), Serial.println(k);     // Expression 2
       k++,        Serial.print("Expression3 k = "),  Serial.println(k)) {  // Expression 3

    Serial.print("In for loop body, k squared = ");   // for Loop statement body
    Serial.println(k * k);   
    delay(1000);
  }
}

void loop() {}

I'm running the code on a true UNO, but the loop does not terminate after 10 iterations. Ideas?

k < 10,     Serial.print("Expression2 k = "), Serial.println(k);

This is three expressions separated by commas. Each of the three is evaluated left to right. The value of the rightmost one is the value of the whole expression and so the above partial statement is equal to:

Serial.println(k);

Serial.println returns the number of characters printed which in this case will always be a non-zero value and therefore the for loop will never exit.

Why would you write a for loop like that anyway?

Pete

Agh, comma separated...

just DON'T

My eyes, my eyes. Please, Someone, just take it away!

Thanks Pete. I don't advocate a comma-separated list of expression either. However, I had a student ask me about the sequence of expression evaluation in a for loop. I pointed out that expression1 was only evaluated once, and then expression2 determined if another pass would be made through the loop body while expression3 is used to change the state of the loop. The code clearly demonstrates the sequence; it just didn't terminate as expected.

Pete: I know you're answer is correct, because if I change the second expression to:

       Serial.print("Expression2 k = "), Serial.println(k), k < 10; // Expression 2

the code works as I expected.

KenF. Sometimes you have to prostitute your code to show a less experienced person what's going on.

econjack:
KenF. Sometimes you have to prostitute your code to show a less experienced person what's going on.

I know, I've been there, my heart goes out to you!

I feel so dirty...

Sometimes you have to prostitute your code to show a less experienced person what's going on.

Sometimes, you just have to tell them NO!. DO NOT TO THAT SHIT! This was one of those times.

  for (k = 0,      Serial.print("Expression1 k = "), Serial.println(k);     // Expression 1

k < 10,     Serial.print("Expression2 k = "), Serial.println(k);     // Expression 2
      k++,        Serial.print("Expression3 k = "),  Serial.println(k)) {  // Expression 3

Serial.print("In for loop body, k squared = ");   // for Loop statement body
   Serial.println(k * k);  
   delay(1000);
 }

boggle

This might be of interest: The International Obfuscated C Code Contest

How amusingly and utterly bizarre!

My favourite is jason.c (it's one of the winners). The code looks like this (in part):

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#define __ "Y\n : ! ,.?>"
#define D(f) ; } int f(int i) { return
#define E(a,b,c,d,e) b##d,c,e,a
#define e(a,b,c,d) a##b##c##d
#define B *p++ - ' ' || !p++
#define _(k) o(*#k - 64)
#define G(g,l,k,o,e,d,n,c,i,b,a,f,j,m,p) \
a#b#c#d#e#f#g#a#i#j#k#l#m#n#o e,i l##c,m##b; d g j n h(k 30:1); o p f}

 G(E(f ( 9) -s
 ? -s + 'q'
 ? f( 5 ) -s &&'d' -
       s?U(  3 ) ||_(J)
 :A ( s- f( 5 ))
 :(c= 4 *
      4):

 g(0)D(

 V)c <= 3 *4 + 3&&c && V(X ( i) ) ;
 }

 int , time ( 0)& , c - 15 || P

 (1

):0,
 & ( !!d    ( 0 )
  ||(a=! _(S)) ,b= 0 )||
 a
 ?d(a  = 0)
 ? _
(I): w ( j =!W(j=_ (V ))) ,

 l(_
    (Y+ s ) )
  )e

 (
 main(){;
    ;;;s , ra,
 n, d), && C ( j +R( s-j+t( i- 1) )
   )D( W)m[ c* 4| z( j ) ]
    &&_( X )E (d   ( 0
       )&&  R( 6)/ 6
   ? c= 17|_ ( T )
   :01,||+
       , v =i & 3 ^ 2
       ,+j & 3&&W ( j)||y ( 10 )D (k) --
   j ? k ( O[j]=R(15 ))
: 1 D
 ( H )o ( 7+! !  i+3 )+

  i?

    c=i /4 & 63,
    a= 1

I didn't put the lot there because I'm not sure about the copyright. Anyway, compiling and running under Linux, OS/X, etc. gives this:

you are in a maze of twisty little passages
caves lead:  left right
you see
   a lamp
> take lamp
eh?
> get lamp
done
> left
you climb...
you are in a maze of twisty little passages
caves lead:  left forward right back
you see
   a scepter
> get scepter
done
> back
you climb...
you are in a maze of twisty little passages
caves lead:  forward back
>

However you don't see those words in the code at all. Indeed the "logic" is hard to follow:

  D(J) !j                                --E( 0 D  ( K )!-!N, || i &,
                                                _( R ) :i* c== (O
   [ j ] ) &&n==f (j+   6  +    5   * 4)?O
    [j]=   !i *    c-_   (    L)    :J(i )
    D ( N ) j=9, & d(0 )? j= 6 | ! i , J(i )D 
 ( o)(*S = p , ++ S,p = M , r (q (i) ),-- S,  p = *S))
    ( (l (_ (Q )),n =s,i ^5 ) ) ;, E(j ,
 sign ,  v ,ed ( b ) ;;
      int   c =1 ,O[9])
            ;int(  s
)=

If you want to try this at home, here is the source:

http://ioccc.org/2001/jason.c

Just compile and run like this:

cc jason.c -o jason
./jason

Oops, forgot I had logged into my test account.

  • Nick Gammon

(edit) This was for reasons related to my (failed) attempts to play Warlords of Draenor.

@econjack: You could explain to the student that the syntax of a statement is not the same as the semantics of that statement. Although expression2 suggests an arbitrary expression, the semantics require that it be a logical expression evaluating to true or false which determines when the loop will exit.

Pete

... the semantics require that it be a logical expression evaluating to true or false ...

Just to nit-pick, as long as you define "true" as non-zero then that is true.

However whilst (in C++)

5 != true

however

if (5) ...

would evaluate to the "if" being true.

Peidiwch â phoeni Nick . Nid wyf yn credu neb sylwi .:slight_smile:

True, it might be an entry into an obfuscated code contest, but it does do what I wanted and I may actually put it in the book. I find that most students are very visual and learn better if they can "see" the concept.

@el_supremo: I do try to explain the difference between syntax and semantic errors. My starting point is that a syntax error is a violation of the rules of the language. For example, English wants a sentence to have a noun and a verb. If I say: "The dog meowed.", the sentence obeys the syntax rules, but doesn't have the proper context, so it's a semantic error. Again, simple is better...at least at the outset.

I also point out the potential abuse one can get into using the comma operator!

Like this, which we see here quite often:

digitalWrite ((10, 11, 12), HIGH);   // turn on pins 10, 11 and 12

And another one from recently:

if (a < 5, b > 10, c == 42) 
  ...