for statements converted to while statements, learning Obj C

Discussion in 'Mac Programming' started by Ja Di ksw, Jan 10, 2011.

  1. Ja Di ksw macrumors 65816

    Ja Di ksw

    Joined:
    Apr 9, 2003
    #1
    Hi everyone. I'm just learning how to do Obj C (only programming experience I have is with NetLogo), and an exercise wants me to convert a for statement into a while statement. However, the "while" examples they give don't have a lot of info and I'm not quite sure what to do. Here is the for statement:

    Code:
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    
    	int n, number, triangularNumber, counter;
    
    	
    	for (counter = 1; counter <= 5; ++counter )
    	{
    		NSLog (@"What Triangular number do you want?");
    		scanf("%i", &number);
    		triangularNumber = 0;
    		
    		for (n = 1; n <= number; ++n )
    			triangularNumber += n;
    		
    		NSLog (@"Triangular number %i is %i", number, triangularNumber);
    	}
        
    
        [pool drain];
        return 0;
    }
    
    
    And here is what I came up with (yes, I know it's bad):

    Code:
    
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    	
    	int n, number, triangularNumber, counter;
    		
    	while (counter <= 5) {
    		NSLog (@"What Triangular number do you want?");
    		scanf("%i", &number);
    		triangularNumber = 0;
    		while (n <= number) {
    			triangularNumber += n;
    			NSLog (@"Triangular number %i is %i", number, triangularNumber);
    		++n,
    		++counter;
    	}}
        
    	
        [pool drain];
        return 0;
    }
    
    It doesn't have any errors, but it also doesn't ask for any input. Just runs and then exits. Can anyone tell me what I'm doing wrong?
     
  2. ChOas macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #2
    You don't know what value n, number, triangularNumber, counter have because you never initialised them with a number, just declared them.

    Try and set them all to 0 after declaring them.
     
  3. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #3
    Or, for counter and n at least, set them to 1 as the for loops do.



    B
     
  4. ChOas macrumors regular

    Joined:
    Nov 24, 2006
    Location:
    The Netherlands
    #4

    Uuuuuh yeah, that :D
     
  5. Ja Di ksw thread starter macrumors 65816

    Ja Di ksw

    Joined:
    Apr 9, 2003
    #5
    Thanks for the help :). Setting them up beforehand did the trick, though I also had to delete the innermost "while" statement (and the calculations for a triangular number somehow didn't work anymore, but I'm not too concerned about that). Anyways, thanks for the help! It's fun getting back into programming (though I was never really 'deep' to begin with).
     
  6. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #6
    The red-hilited code does not belong to the inner loop. That's why it stopped working.

    The rule for decomposing for loops is this:
    Code:
    for ( a; b; c )
    {  body;  }
    
    is approximately** equivalent to this:
    Code:
    a;
    while ( b )
    {  body;  c; }
    
    Go look at where you've placed your }'s and move them to separate lines instead of putting them together like }}.

    ** This isn't 100% true, because the continue statement in a for loop actually jumps to the c statement.
     
  7. lee1210 macrumors 68040

    lee1210

    Joined:
    Jan 10, 2005
    Location:
    Dallas, TX
    #7
    I think they key to moving between these control structures is knowing what they actually do. For the three expressions in a for, knowing which happens when is crucial.
    for( expressionA;expressionB;expressionC ) expressionD

    expressionA is the initializer. This will happen one time before the body of the loop executes. It is generally used to set a counter, but you can do whatever you want with this expression.

    expressionB is the test for continuation. It is executed before each iteration of expressionD, and the first time it is executed is after expressionA. The first time this expression evaluates to 0 (false, even though there's no proper false in C) the loop terminates. If this evaluates to a non-0 value, one iteration of expressionD will be executed.

    expressionC is generally used to increment a counter or modify some other piece of state that moves the iteration of the loop "forward". This is executed immediately after every iteration of expressionD, before the execution of expressionB to test if the loop should continue.

    expressionD is the "body" of the loop. It executes each time expressionB evaluates to a non-0 value. It is generally a "block" of expressions contained in {} but this isn't a strict requirement.

    while ( expressionE ) expressionF

    expressionE is run before each iteration of expressionF. If expressionE evaluates to 0 the loop exits, if it evaluates to non-zero expressionF executes once and expressionE is tested again. expressionE in a while is like expressionB in a for loop.

    expressionF is the "body" of the loop, just like expressionD in a for loop.

    Knowing this, it is very easy to move a while to a for, and pretty easy to go the other direction:

    Code:
    #include <stdio.h>
    int main(int argc, char *argv) {
      int x = 0;
      while (x < 7) {
        printf("x is now: %d\n",x);
        x++;
      }
    }
    
    This can be rewritten easily as:
    Code:
    #include <stdio.h>
    int main(int argc, char *argv) {
      int x = 0;
      for (;x < 7;) {
        printf("x is now: %d\n",x);
        x++;
      }
    }
    
    It might not be the neatest, but it works fine to have empty statements in your for loop. It might be nicer to write this as:
    Code:
    #include <stdio.h>
    int main(int argc, char *argv) {
      int x;
      for (x=0;x < 7;x++) {
        printf("x is now: %d\n",x);
      }
    }
    
    but the result is the same.

    Conversely, it should be easy to rearrange a for loop very slightly to get a while loop.
    Code:
    #include <stdio.h>
    int main(int argc, char *argv) {
      int z;
      for (z=7;z>0;z--) {
        printf("z is now: %d\n",z);
      }
    }
    
    So using the labels from above:
    expressionA is z=7
    expressionB is z>0
    expressionC is z--
    expressionD is { printf("z is now: %d\n",z); }

    So turning this into a while:
    Code:
    #include <stdio.h>
    int main(int argc, char *argv) {
      int z;
      z=7;
      while (z>0) {
        printf("z is now: %d\n",z);
        z--;
      }
    }
    
    expressionA is moved immediately before the loop.
    expressionB is used as expressionE in the while loop.
    expressionC is moved to the end of the block that was used as expressionD, and this new block is used as expressionF in our while example.

    While you can always achieve the same thing with either of these control structures, there are situations that lend themselves more readily to one rather than the other. I would say a while gets a nod if your are waiting for some state elsewhere to change that you are checking with, say, a function call inside the body of the loop. A for loop is easier to deal with if you are iterating through the elements of an array whose size you know.

    -Lee

    Edit: chown33 posted a terser version of this above, with an important note re: the continue statement. In general this is all sort of moot as it's rare (though it does occur) that one needs to "translate" a loop like this.
     
  8. balamw Moderator

    balamw

    Staff Member

    Joined:
    Aug 16, 2005
    Location:
    New England
    #8
    Just to point out a tip that might help you avoid this in the future.

    Avoid putting the closing brackets for nested loops on a single line and comment them so you know what they are closing.

    Code:
    #import <Foundation/Foundation.h>
    
    int main (int argc, const char * argv[]) {
        NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    	
    	int n, number, triangularNumber, counter;
    	
    	while (counter <= 5) {
    		NSLog (@"What Triangular number do you want?");
    		scanf("%i", &number);
    		triangularNumber = 0;
    		while (n <= number) {
    			triangularNumber += n;
    			NSLog (@"Triangular number %i is %i", number, triangularNumber);
    			++n,
    			[COLOR="Red"]++counter[/COLOR];
    		} //inner-loop (n)
    	} //outer-loop (counter)    
    	
        [pool drain];
        return 0;
    }
    I left the red code where it was so you can see that it seems out of place now.

    B
     

Share This Page