Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (24.65 MB, 900 trang )
Discussion
Loops are useful in programming because you will often need to start a loop from one
place to another, from one index to another, or from start to stop. For instance, you
might want to loop through all characters inside a string and count how many "A"
characters you can find in it. Another example is a loop that finds all files in a directory.
This is a loop that finds the number of files and then starts from the first one until it
gets to the last one.
Usually, programmers require a counter in their loops. For instance, you might want
to read all the characters inside a C-String. For this, you will need the index of each
character. If your string is 10 characters long, you will need to go from index 0 to 9. If
your string is 20 characters long, you have to read from index 0 to 19. Since the length
of your string is a variable, you can put it as the exit-conditional of your loop. Here is
an example:
char *myString = "This is my string";
NSUInteger counter = 0;
for (counter = 0;
/* Start from index 0 */
counter < strlen(myString); /* Exit loop when we reach last character */
counter++){ /* Increment the index in every iteration */
char character = myString[counter];
NSLog(@"%c", character);
}
The code that gets executed before the loop (as noted in the Solution section of this
recipe) is obviously optional. In fact, all three main parts of a for loop are optional, but
it is recommended that you think about how you intend to use your loops and use the
three main parts of the for statement accordingly.
Let's have a look at where you would want to skip the first statement of your for loop.
As you could see in the previous section, our counter variable was set to 0 before we
even started our loop. However, we are setting it to 0 again once our loop is about to
start. This is unnecessary in this example, but there is nothing wrong with that approach. If you feel you don't need the redundant code, simply remove it:
char *myString = "This is my string";
NSUInteger counter = 0;
for (; /* empty section */
counter < strlen(myString); /* Exit loop when we reach last character */
counter++){ /* Increment the index in every iteration */
char character = myString[counter];
NSLog(@"%c", character);
}
1.9 Implementing Loops with For Statements | 33
www.it-ebooks.info
The second clause of any for loop is very important because this is the conditional that
allows your loop to exit. Having no condition in the second clause is similar to having
a never-ending loop, or an infinite loop as it is known. Therefore, it is best to think
about the condition that allows your program to end the loop and continue on its path
of execution.
Any variable defined in the first clause of a for loop is accessible inside the loop but not
outside it. For instance:
for (NSUInteger counter = 0;
counter < 10;
counter++){
NSLog(@"%lu", (unsigned long)counter);
}
/* "counter" is NOT accessible here. This line will throw compile time error */
NSLog(@"%lu", (unsigned long)counter);
The third clause inside a for loop is very interesting indeed. This is the statement that
gets executed after every iteration of your loop. This includes the last iteration. For
instance:
NSUInteger counter = 0;
for (counter = 0;
counter < 4;
counter++){
NSLog(@"%lu", (unsigned long)counter);
}
NSLog(@"%lu", (unsigned long)counter);
This will print the following values to the console:
0
1
2
3
4
So our counter did get to number 4 although in our loop we asked that the counter
should be less than 4. This proves the point that when our loop finishes, in the last
iteration, the third clause of our for loop gets executed. But the code inside our loop
won't be called since the end-condition (second clause) will not be met and our loop
will finish.
See Also
XXX
34 | Chapter 1: The Basics
www.it-ebooks.info
1.10 Implementing While Loops
Problem
You want to let a piece of code run over and over again until a certain condition is met.
Solution
Use while loops and specify your exit condition. Here is the format for the while loop:
while (
CODE
}
As long as the condition is a value other than zero/nil/NULL, the while
loop will run.
Discussion
The while loop is the "arrogant" brother of the for loop (see Recipe 1.9) because while
loops only take a condition that should be met for the loop to run. If the condition is
positive, the loop will always run until the condition becomes negative. For instance,
a while loop could be implemented to make an icon in the Dock in Mac OS X jump up
and down until the user taps on that icon (this is actually a very bad user experience;
icons in the Dock shouldn't jump up and down continuously, but for a short interval,
or even a fixed number of times, usually 3). The exit condition for the while loop is the
user's tapping on that icon. As long as the user hasn't tapped on the icon, the icon will
jump up and down.
A while loop is awkward to use with a counter because of its syntax. If you require a
counter to control your loop, it is better to use a for loop. If you do require a while loop
but still want to have access to a counter, you will need to manage the counter manually,
like so:
NSUInteger counter = 0;
while (counter < 10){
NSLog(@"Counter = %lu", (unsigned long)counter);
counter++;
}
Just as you can have positive conditions for your while loops, you can have negative
conditions as well:
BOOL shouldExitLoop = NO;
NSUInteger counter = 0;
while (shouldExitLoop == NO){
counter++;
1.10 Implementing While Loops | 35
www.it-ebooks.info
if (counter >= 10){
shouldExitLoop = YES;
}
}
NSLog(@"Counter = %lu", (unsigned long)counter);
The output of this program is:
Counter = 10
So what we are doing is simply running a loop for as long as our counter is less than
10. If the value of the counter (adjusted inside the loop itelf) goes over or becomes equal
to 10, then we exit our loop. Just like a for loop, you can create an infinite loop using
a while loop, although this is a terrible programming practice and you should avoid it
by all means:
while (YES){
/* Infinite loop */
}
You must make sure that you have an exit strategy in your while and for loops. For
this, you need to keep an eye on the condition for your loops and make sure that the
condition will be met at some point, without making your loops hogging all the memory
and/or system resources while they run.
Here is another usage of a while loop:
char *myString = "Some Random String";
NSUInteger counter = 0;
char character;
while ((character = myString[counter++]) != 'R' &&
counter < strlen(myString)){
/* Empty */
}
NSLog(@"Found the letter R at character #%lu", (unsigned long)counter+1);
Here we are searching inside a string to find the first occurrence of the letter 'R'. As
soon as we find it, we exit our while loop. We have been careful to include another
condition: if we reach the end of the string (strlen(myString)), we end the loop, so that
we don't wander off into undefined memory and cause a crash or a security flaw. (Doing
so is called a buffer overflow.
This algorithm has a bug, however: it returns a wrong results when the letter 'R' isn't
in the string at all. Because the while loop finishes when we get to the end of the string,
we always print a message to the console saying that the letter 'R' was found at some
index. I will leave it up to you to fix this algorithm. As a hint, you might want to use a
Boolean value when you do find the letter 'R' and then later use that flag to determine
whether the letter was found. To use that boolean technique, you might need to change
the way the while loop is set up, but I think you get the idea.
A while loop is useful for traversing an array. For instance, a C String is an array of
characters ending with a zero byte. If you are searching for a specific character in this
36 | Chapter 1: The Basics
www.it-ebooks.info