Learn Objective-C Lesson 5: Loops

A computer is really good at executing the same thing over and over again. A lot of programming involves doing the same thing over and over again (and no, that’s not meant to be a programming joke, although it could certainly be taken as one). Objective-C allows for two main ways of looping. We’ll start with a rather general problem.

The for() Loop

The Problem

Create a program that displays the sum of all the numbers from 1 to a user-specified value. Note that to get a user-specified value, we are going to be using a function call to scanf(), which is similar to NSLog, except that it reads input, rather than exporting it. A brief explanation will follow, but scanf() is not a function that you will regularly use on the iPhone. It is just a “place-holder” way to get input until we can use better options.

As for the problem itself, we are adding all the numbers between 1 and the input. So if the input was 5, we would output the sum as 1 + 2 + 3 + 4 + 5, or 15.

The (Inefficient) Solution

We could just take all the values and simply add them up:

int sum = 1 + 2 + 3 + 4 + 5;

sum would equal 15, just as expected. But although this method is rather simple and the most logical at this point, it is not very efficient, or scalable. If the user had entered a large value, such as 1000, writing the code for that would be torturous. But there will be a user who will enter 1000. You will almost never be able to anticipate every single type of input your user might give or do to your program, and you should probably have a solution to handle every case. So how are we going to handle the case of the user inputting 1000—or indeed, any value other than 5 (in this case)?

The Best Solution

We would use a loop. Here is the code to accomplish the problem above, using a for() loop:

  1. #import <Foundation/Foundation.h>int main (int argc, const char * argv[]) {
  2.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  3.  
  4.     int sum = 0;    // Make sure we start at zero, to avoid issues later
  5.  
  6.     // Allow user input
  7.     NSLog(@"Please enter a value.");
  8.     int times;
  9.     scanf("%d", ×);
  10.  
  11.     // for() loop construct:
  12.     for(int n = 1; n <= times; n = n + 1)
  13.         sum = sum + n;
  14.  
  15.     NSLog(@"Sum of all values from 1 to %d is %d", times, sum);
  16.  
  17.     [pool drain];
  18.     return 0;
  19. }

The output shows that for an initial value of 1000, the sum is 500500.

Code Demystified

The for() loop is basically three statements in one line. Within the parentheses following the “for”, you have the initial expression, condition, and the loop expression. These are separated by semicolons.

Initial Expression

This statement is usually used to initialize variables used in the loop and assign them values. Usually this will be a counter of some sort which will not be used elsewhere in the program. In this case, I like to declare the variable and assign it a value at the same time, as I did above, rather than having int n; and then n = 1; in the loop. It just makes the code more concise.

You can initialize and declare more than one variable at a time: int a = 0, b = 3, c = 5;. For the most part though, you will only need some form of a (integer) counter variable, and you won’t need multiple variables. You could still use that to your advantage, though.

It is important to note that any variables you initialize here (initialize means that you have not made any mention of this variable before, and you are creating a new variable here) are only valid within the loop—as soon as you exit the loop (described below) the variable is no longer accessible.

Condition

This is a boolean condition that determines if the loop is still valid. If this expression becomes untrue (usually due to the loop expression), then the program exits out of the loop without running through the loop again. The program then moves on to the next line after the loop.

Remember that when comparing integers, as you usually will when using a loop, the following two expressions are equivalent: n <= 1000; and n < 1001;. But in this case, because you are only checking up to 1000 (and because the user entered 1000, and you should avoid modifying the input if possible; in addition, having to add one to the input just to use a less-than construct is not a good choice), the first expression makes more logical sense.

Loop Expression

This is an expression that is executed after the main body of the loop; it is usually a way to increment the initialized variable(s). In this case, the counter variable n is incremented by 1, so that eventually the loop condition will become false.

General Operational Procedure

Excerpted from Stephen Kochan’s Programming in Objective-C 2.0, 2nd Edition published by Addison-Wesley, ©2009:

  1. The initial expression is evaluated first. This expression usually sets a variable that is used inside the loop, generally referred to as an index or counter variable, to some initial value (often 0 or 1).
  2. The looping condition is evaluated. If the condition is not satisfied (the expression is FALSE or NO), the loop immediately terminates. Execution continues with the program statement that immediately follows the loop.
  3. The program statement(s) that constitutes the body of the loop is executed.
  4. The looping expression is evaluated. This expression is generally used to change the value of the index variable, frequently by adding or subtracting 1.
  5. Return to step 2.

The while() Loop

This is another type of loop that Objective-C supports. Although most tutorials and textbooks would consider them (roughly) equivalent, I use for() loops whenever I know how many times I want to go through, whether it is by a hard-coded value or by a the value in a variable. The while() loop is better suited for cases where the program does not know how many times it is to be run, and instead checks for a different condition. This can be better illustrated with an example.

The Problem (Revised)

Calculate the sum of all the integers that the user enters; the user input is terminated by any negative value.

The Solution

This would be very difficult to do with a for() loop, as you do not know how many times to execute. You would have to do an ugly check in the loop condition. A while() loop makes this more elegant.

  1. #import <Foundation/Foundation.h>
  2.  
  3. int main (int argc, const char * argv[]) {
  4.     NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
  5.  
  6.     NSLog(@"Input a list of integers. Hit Return after each one. End the list with a negative value.");
  7.     int sum = 0;
  8.     int input = 0;
  9.     scanf("%d", &input);
  10.  
  11.     while (input >= 0) { // "Greater-than or equal to zero" is the same as "not negative"
  12.         sum = sum + input;
  13.         scanf("%d", &input);
  14.     }
  15.  
  16.     NSLog(@"The sum of all those values is %d", sum);    [pool drain];
  17.     return 0;
  18. }

Here is a sample run:

  1. Input a list of integers. Hit Return after each one. End the list with a negative value.
  2. 5
  3. 2
  4. 18
  5. 30
  6. 37
  7. 69
  8. -29
  9. The sum of all those values is 161

Code Demystified

The expression for the while() loop is a simple boolean condition (the middle part of the for() loop). This gets evaluated, and if it is true, the body is executed. If not, the program moves on. This means that in the loop, you have to make the value untrue somehow; otherwise you will get an infinite loop.

The do-while Loop

In a regular for() or while() loop, the condition is checked first, then the loop is executed. This means that if the initial condition was false to begin with, the body of the loop would never ever get executed; the code would skip directly over the loop. The do-while loop is guaranteed to perform one iteration of the loop first, before checking the condition. From that point on, as long as the condition remains true, the loop will continue to execute. The syntax is as follows:

  1. int n = 1;
  2. do {
  3.     sum = sum + n;
  4.     n = n + 1;
  5. } while (n <= 5);

The above example is a re-writing of the previous loop examples, using the do-while construct. A more compelling example might look like this:

  1. int sum = 0;
  2. int input = 0;
  3. do {
  4.     sum = sum + input;
  5.     NSLog(@"Sum is %d", sum);
  6.     scanf("%d", &input);
  7. } while (input != -1);

In the above example, the program will continue to display the sum of all the values the user enters until negative 1 is entered. The loop in this case ensures that the NSLog is printed at least once, and the user input is gathered; in this case, the input is placed in the loop, rather than having to have an additional scanf() outside of the loop. This makes the code a little easier to read and understand.

Pitfalls

A few things that people get tripped up on:

  • Forgetting braces: If you have more than one statement that you want to execute given a certain condition, you must enclose them within curly braces. Otherwise, they can stand alone as one line, without braces.
  • The Infinite Loop: The loop condition must be made false, somehow. (It’s also a really good idea to actually have a loop condition). Otherwise, your loop will never end, and it keep running until your computer crashes, or until the power goes out.

Conclusion

Loops are relatively easy to implement, yet they can save you a lot of coding. For a big loop, like in the first example, you truly begin to leverage your computer’s processing power, and save yourself a lot of work. When combined with if() statements, they can become quite powerful.

This post is part of the Learn Objective-C in 24 Days course.

Author: Feifan Zhou