for (;;) { }

edited June 2010 in Chit chat
What does that piece of code do in C?
Well I am familiar with something like for (i=0; i<100; i++) { }
but I haven't understood what happens if you leave the parts between the semi-colons blank. I would have thought if just ran the code between the braces once, but then why bother with the for ( ; ; )?

Incidentally, is it considered bad practice to modify the index variable inside the loop?
Post edited by wilsonsamm on

Comments

  • edited June 2010
    for ( ; ; ) describes an infinite loop because there's no exit condition. If you notice the structure of the for loop, the middle statement (one between the semi-colons) is an expression that checks for a condition to exit the loop. Eg, for (int f=0; f < 10; f++) will loop repeatedly as long as f is less than 10. Once it hits 10, it exits the loop.

    If you leave out the condition check (as above), the loop will never exit unless the code executing within the loop somehow forces a break from the loop.
  • edited June 2010
    so in other words, for ( ; ; ) is conceptionally synonymous with while(1) since it will go round and round until a break; occurs...

    And you are right. I examined the code and there was a break; there.

    ah, in the past I have written while (1), and some compilers have generated code to check if 1 is non-zero. a handy optimisation for people with such compilers!
  • edited June 2010
    wilsonsamm wrote: »
    so in other words, for ( ; ; ) is conceptionally synonymous with while(1) since it will go round and round until a break; occurs...

    Yes.
    ah, in the past I have written while (1), and some compilers have generated code to check if 1 is non-zero. a handy optimisation for people with such compilers!

    Yeah, the for infinite loop is generally considered a better alternative to the while infinite loop because some compilers generate a conditional check for the latter. I'm not sure if this is a hangover from the previous c coding days though because you would expect compilers to have become smarter now.. ;)
  • edited June 2010
    This is a For loop systax, in C and in Java which is a derivative language, it means the following.


    for (Initialise ; Condition ; Update Value)

    Initialise
    This statement is used to initialise a variable for example: x = 1. It can also be used to declare and initialise a variable as in: int x = 1;

    Declare means: Reserve a named space in memory for data of the specified type, i.e. create a variable.
    Initialise means: Give the variable its first value.

    Condition
    This consists of a boolean expression such as: x <= 10. The loop will continue whilst the condition evaluates to true. The condition is evaluated once per loop, not contunually within the loops structure.

    Update Value
    This updates a variable for example : x = x + 1 (x++ for short). Typically you are going to want to uptate the a control variable which was Initialised in the For loops paramiter list.
    //Loop from 10 down to 1 (does somthing 10 times)
    for (x = 10; x > 0 ; x= x - 1)
    {
      ///Do somthing
    }
    

    However, each of the Initialise, Condition, Update Value expressions are optional, so you can have only some or none if you want. For example
    int x;
    int amt
    [B]for (;;;)[/B]
    {
      cout << "How quonkers are you filling the dispenser with?";
      cin >> x;
    
      [B]for ( ; x < 10;  x = x -1) [/B]
     {
        cout << "How many quonkers would you like";
        cin >> amt;
        if (x - amt >= 0)  x = x - amt;
        else cout << "Sorry not enough quonkers left";
      }//end for
    
      cout << " Sorry no more quonkers left please refill machine";
    }//end for
    
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    That means I could do
    for (x=10 ; ; ) {
        if (doyourthing()) then break;
    }
    

    and it would doyourthing until that returned true, and x would remain at ten (unless doyourthing changed it) but what's the scope of that variable? Is this following code possible?
    int x
    for ( ; (x>7 && x<16) ; ) {
        printf("give me a value between 7 and 16 exclusive");
        scanf("%d", x);
    }
    
  • edited June 2010
    wilsonsamm wrote: »
    That means I could do
    for (x=10 ; ; ) {
        if (doyourthing()) then break;
    }
    

    and it would doyourthing until that returned true, and x would remain at ten (unless doyourthing changed it) but what's the scope of that variable? Is this following code possible?
    int x
    for ( ; (x>7 && x<16) ; ) {
        printf("give me a value between 7 and 16 exclusive");
        scanf("%d", x);
    }
    

    Yes you could do your first example.

    In your first example x was declaired in the for loop; therefore, its scope is within the brackets of the for loop.

    However, in your second example the scope of x is not limited to the loop, but the whole method the code woud reside in, following its declaration.
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    Scottie_uk wrote: »
    Yes you could do your first example.

    In your first example x was declaired in the for loop; therefore, its scope is within the brackets of the for loop.

    Not to be too pedantic but in fact he has not declared x in the for loop. To declare: for (int x = 10; ; ). This would cause x to be local to the scope of the loop.
  • edited June 2010
    Arjun wrote: »
    Not to be too pedantic but in fact he has not declared x in the for loop. To declare: for (int x = 10; ; ). This would cause x to be local to the scope of the loop.

    Which is pretty what I was saying. The only correction need is that x is not declaired in the loop but the for loops paramiter list.
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    Arjun wrote: »
    Not to be too pedantic but in fact he has not declared x in the for loop. To declare: for (int x = 10; ; ). This would cause x to be local to the scope of the loop.

    And what if there was already an x in the function where the loop was? then that x would not be accessible inside the for loop.
  • edited June 2010
    wilsonsamm wrote: »
    And what if there was already an x in the function where the loop was? then that x would not be accessible inside the for loop.

    No, the local variable will hide the global one.

    Don't mean to put you off but wouldn't it be faster and easier for you to refer to a book or online tutorial than posting on the forum back and forth?
  • edited June 2010
    Arjun wrote: »
    No, the local variable will hide the global one.

    Don't mean to put you off but wouldn't it be faster and easier for you to refer to a book or online tutorial than posting on the forum back and forth?

    True.
    I have a small 1992 book called "C simply". It explains some of the stuff but I'm learning new things by asking here...
  • edited June 2010
    Arjun wrote: »
    No, the local variable will hide the global one.

    Don't mean to put you off but wouldn't it be faster and easier for you to refer to a book or online tutorial than posting on the forum back and forth?

    Global being the variable which was declared ouside of a method. However, I'm not sure thats what he was asking, I could be wrong though.

    However inside a method if you had
    main ()
    {
       int x = 0;
    
       for (int x = 0; x < 10; x ++)
      {
         cout << x;
       }
    }
    

    Then you would get a variable already defined error just as you would in this situation
    main ()
    {
     
    
       for (int x = 0; x < 10; x ++)
      {
         cout << x;
    
          int x = 5;
       }
    }
    
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    ^^

    The use of cout implies C++. In which case neither variant will give a compile error. The first one will output the value of x declared in the for statement within the loop, hiding the x declared at the top of main, ie output the numbers 0 to 9. The second will output the value of x declared in the for statement too, as the cout line precedes the second declaration of x, so 0 to 9 again. If the second x was declared before the cout line, then it would output 5 ten times.

    If we are talking about C, then declaring x in the for statement is illegal, unless you are using C99. C99 will behave as C++. Ye olde C won't compile.
  • edited June 2010
    JamesW wrote: »
    ^^

    The use of cout implies C++. In which case neither variant will give a compile error. The first one will output the value of x declared in the for statement within the loop, hiding the x declared at the top of main, ie output the numbers 0 to 9. The second will output the value of x declared in the for statement too, as the cout line precedes the second declaration of x, so 0 to 9 again. If the second x was declared before the cout line, then it would output 5 ten times.

    If we are talking about C, then declaring x in the for statement is illegal, unless you are using C99. C99 will behave as C++. Ye olde C won't compile.

    Good shout, I've had all the C Javaised out of me. However, will not my second example result in 0 followed by an infinite number of 6s?
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    Scottie_uk wrote: »
    Good shout, I've had all the C Javaised out of me. However, will not my second example result in 0 followed by an infinite number of 6s?

    No it won't. At the cout line the only x in scope is the one declared in the for statement. The next line introduces a new x, which hides, but doesn't over-write the previous x. The new x then immediately drops out of scope when the loop loops. The original x in the for statement is still in scope, is incremented, tested against the exit condition, and cout prints the new value. That's what happens with gcc at any rate.
  • edited June 2010
    JamesW wrote: »
    No it won't. At the cout line the only x in scope is the one declared in the for statement. The next line introduces a new x, which hides, but doesn't over-write the previous x. The new x then immediately drops out of scope when the loop loops. The original x in the for statement is still in scope, is incremented, tested against the exit condition, and cout prints the new value. That's what happens with gcc at any rate.

    You know I'm going to test this later in Visual Studio. I'll also try some older stand alone C++ compiler.
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    JamesW wrote: »
    That's what happens with gcc at any rate.

    It shouldn't. It shouldn't even compile because if it did there would be two versions of x declared in the same scope. VS doesn't compile it, which I believe is the correct behaviour.

    You can get it to compile by modifying it to be:
    for (int x = 0; x < 10; x ++)
    {
       {
          cout << x;
          int x = 5;
       }
    }
    
    Since the additional braces will create a new scope. Then it'll behave as you suggested.
  • edited June 2010
    AndyC wrote: »
    It shouldn't. It shouldn't even compile because if it did there would be two versions of x declared in the same scope. VS doesn't compile it, which I believe is the correct behaviour.
    It does though! On OS X both gcc and clang compile it.

    Here's the code tarted up a bit, and made unC++ified:
    //wos.c
    #include <stdio.h>
    
    int main()
    {
      for (int x = 0; x < 10; x ++)
        {
          printf("%d\n", x);
          int x = 5;
        }
      return 0;
    }
    

    Both the following build without warnings or errors:
    gcc -o wos -std=c99 wos.c
    clang -o wos wos.c
    

    And both produce the same output:
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    I don't know the standard well enough to know if the behaviour is correct, wrong, or undefined behaviour.

    Edit
    But a few minutes on Google finds the relevant part of the c99 standard:
    C99 wrote:
    Except for the behavior of a continue statement in the
    loop body, the statement
                   for ( clause-1 ; expr-2 ; expr-3 ) statement 
    
    and the sequence of statements
                   { 
                           clause-1 ; 
                           while ( expr-2 ) { 
                                   statement 
                                   expr-3 ; 
                           } 
                   } 
    
    are equivalent ....

    So, the for loop above should transform to:
      int x = 0; // expr-1
      while(x < 10) // expr-2
        {
          printf("%d\n", x);
          int x = 5;
          x++;  // expr-3
        }
    
    So VC is wrong, and gcc and clang are correct.
  • edited June 2010
    wilsonsamm wrote: »
    so in other words, for ( ; ; ) is conceptionally synonymous with while(1) since it will go round and round until a break; occurs...

    As a random note, I always use the 'for ( ;; )' construct instead of the 'while(1)' one.
    For some reason, it reads easier for me, as I immediately see "forever" in it. :-)
  • edited June 2010
    JamesW wrote: »
    So VC is wrong, and gcc and clang are correct.

    Nope. According to the C++ standard, section 6.4:
    3 A  name  introduced by a declaration in a condition (either introduced
      by the type-specifier-seq or the declarator of the  condition)  is  in
      scope from its point of declaration until the end of the substatements
      controlled by the condition.  If the name is re-declared in the outer-
      most block of a substatement controlled by the condition, the declara-
      tion that re-declares the name is ill-formed.  [Example:
              if (int x = f()) {
                      int x; // ill-formed, redeclaration of 'x'
              }
              else {
                      int x; // ill-formed, redeclaration of 'x'
              }
    
       --end example]
    
    

    And section 6.5 clarifies that this same ruling applies to iteration statements as well.

    Can't say I'm overly surprised. GCC is (somewhat ironically) not nearly as standards compliant as VC++.
  • fogfog
    edited June 2010
    the first book I had on C was ?4.95 from PC world... decent book / good primer

    yellow cover with C in 3d with bricks as the filling

    we had an excellent C teacher at uni (Tony Bermudez) he was supposed to have written a book..he gave us hand out notes of basically the book in a rough form..

    it covered everything , headers etc . I should see if I have it someone, it was very well written
    he's one of the few teachers I remember who were decent , and could actually teach... instead of teaching as a sideline to fund their phd etc
  • edited June 2010
    AndyC wrote: »
    Nope.
    And section 6.5 clarifies that this same ruling applies to iteration statements as well.

    Yep. And as section 6.5.3 clarifies:
      6.5.3  The for statement                                    [stmt.for]
    
    1 The for statement
              for ( for-init-statement; conditionopt ; expressionopt ) statement
      is equivalent to
    
              {
                      for-init-statement
                      while ( condition ) {
                              statement
                              expression ;
                      }
              }
    
    Look at the code which the standard says is equivalent to the for statement. A variable declared in for-init-statement is not in the same scope as a variable declared in statement.
  • edited June 2010
    That scoping in 6.5.3 is as I would expect. Any variables declared in statement or expression are limited to the bounds of the while loop. Whilst any variable declared in the for-init-statement(2nd one) is limited to the bounds of the for loop and any line that follows it.
    Calling all ASCII Art Architects Visit the WOS Wall of Text and contribute: https://www.yourworldoftext.com/wos
  • edited June 2010
    Real men #define ever ( ; ; )

    So you can do

    for ever

    Serious note: Use ++x rather than x++ in a for loop (compiler will optimise it as same thing for built in types but when you go onto using c++ iterators you don't want to make a copy (which is what x++ has to do). Get into good habits early.
  • edited June 2010
    Serious note: Use ++x rather than x++ in a for loop (compiler will optimise it as same thing for built in types but when you go onto using c++ iterators you don't want to make a copy (which is what x++ has to do). Get into good habits early.

    Do you mean that ++x; uses fewer instructions so that the resulting loop is tighter than had I chosen x++;?
    That makes no sense... I don't know about x86, but the PDP-11 assembly has both INC Rn and DEC Rn (increment and decrement). The end of the loop could like like this:
    loop: CLR R5      # set the index variable to zero. (we'll keep it in register 5)
          /* loop here... */
          CMP R5++,R4 # increment R5 and test it against R4
          BNE loop    # branch if not equal (to zero, that is) to the beginning of the loop
    
    which means x++; the only difference as far as I can tell is that ++x; has to compile to
            MOV -01, R5 # we set it to -1
    loop:   INC R5      # increment
            /* the loop goes here */
            CMP R5,R4    # when R5 becomes equal to R4 the loop will exit.
            BNE loop
    
    which is longer.

    The while (1) would compile to
    while:  TST 01      # test if 1
            BEQ out    # is equal to zero and if so, branch out.
            /* while loop */
            JMP while
    out:    /* rest of program goes here */
    
    which is shorter.

    That is, of course, unless I've missed something basic. It's quite early.

    EDIT: of course I've missed something basic. It would be better to compare the index variable to an absolute value rather than keeping this value in the processor register just for comparison.
  • edited June 2010
    wilsonsamm wrote: »
    Do you mean that ++x; uses fewer instructions so that the resulting loop is tighter than had I chosen x++;?

    You're forgetting that in C++ x might not be as simple as an integer, it might be some massive multi-megabyte structure and that is when the difference hurts performance. Writing ++x rather than x++ even when it's not strictly important tries to teach you to avoid the possibility creeping in by accident.
  • edited June 2010
    How can an index variable be a massive multi-megabyte structure? that's interesting.

    Anyway, what copy is being made when you post-increment?
  • edited June 2010
    Well it's unlikely to be a huge structure.

    It's more likely to be an iterator and those are fairly lightweight.

    What x++ does is

    Copy x
    Increment x
    Return the copy made earlier

    ++x does this

    Increment x
    Return x

    The compiler should optimise [the copy] out if the return value is not stored.

    In C++ you can overload pre and post increment operators and if the return value is discarded ++x should be preferred to x++ because it is never less efficient and may be more efficient.

    It's just a good habit to get into.

    EDIT: Of course, for this reason C++ should be called ++C (since evaluating C++ returns C).
Sign In or Register to comment.