Basic flow control is fairly simple and usually involves a condition in parentheses and
a block of conditionally executed code in curly braces. These curly braces constitute a
new scope, into which new variables can be introduced. So, for example:
After the closing curly brace in the fourth line, the i introduced in the second line has ceased to exist, because its scope is the inside of the curly braces. If the contents of the curly braces consist of a single statement, the curly braces can be omitted, but I would advise beginners against this shorthand, as you can confuse yourself. A common be‐ ginner mistake (which will be caught by the compiler) is forgetting the parentheses around the condition. The full set of flow control statements is given, and I’ll just summarize them schematically here (Example 1-1).
Example 1-1. The C flow control constructs
if (condition) { statements;
}
if (condition) { statements;
} else { statements;
}
if (condition) { statements;
} else if (condition) { statements;
} else { statements;
}
if (x == 7) {
int i = 0;
i += 1;
}
After the closing curly brace in the fourth line, the i introduced in the second line has ceased to exist, because its scope is the inside of the curly braces. If the contents of the curly braces consist of a single statement, the curly braces can be omitted, but I would advise beginners against this shorthand, as you can confuse yourself. A common be‐ ginner mistake (which will be caught by the compiler) is forgetting the parentheses around the condition. The full set of flow control statements is given, and I’ll just summarize them schematically here (Example 1-1).
Example 1-1. The C flow control constructs
if (condition) { statements;
}
if (condition) { statements;
} else { statements;
}
if (condition) { statements;
} else if (condition) { statements;
} else { statements;
}
while (condition) {
statements;
}
do { statements;
} while (condition);
for (before-all; condition; after-each) { statements;
}
}
C also has a goto statement that allows you to jump to a named (labeled) line in your
code; even though goto is notoriously “considered harmful,” there are situations in which it is pretty much necessary, especially because C’s flow control is
otherwise so primitive.
Note : It is permissible for a C statement to be compounded of multiple state‐ ments, separated by commas, to be executed sequentially. The last of the multiple statements is the value of the compound statement as a whole. This construct, for instance, lets you perform some secondary action before each test of a condition or perform more than one after-each action.
}
do { statements;
} while (condition);
for (before-all; condition; after-each) { statements;
}
The if...else if...else structure can have as many else if blocks as needed, and
the else block is optional. Instead of an extended if...else if...else if...else
structure, when the conditions would consist of comparing various values against a
single value, you can use the switch statement; be careful, though, as it is rather con‐
fusing and can easily go wrong. The main trick is to re‐
member to end every case with a break statement, unless you want it to “fall through”
to the next case (Example 1-2).
Example 1-2. A switch statement
The C for loop needs some elaboration for beginners (Example 1-1). The before-all statement is executed once as the for loop is first encountered and is usually used for initialization of the counter. The condition is then tested, and if true, the block is exe‐ cuted; the condition is usually used to test whether the counter has reached its limit. The after-each statement is then executed, and is usually used to increment or dec‐ rement the counter; the condition is then immediately tested again. Thus, to execute a block using integer values 1, 2, 3, 4, and 5 for i, the notation is:
Example 1-2. A switch statement
NSString* key;
switch (tag) {
case 1: { // i.e., if tag is 1
key = @"lesson";
break;
}
case 2: { // i.e., if tag is 2
key = @"lessonSection";
break;
}
case 3: { // i.e., if tag is 3
key = @"lessonSectionPartFirstWord";
break;
}
}
The C for loop needs some elaboration for beginners (Example 1-1). The before-all statement is executed once as the for loop is first encountered and is usually used for initialization of the counter. The condition is then tested, and if true, the block is exe‐ cuted; the condition is usually used to test whether the counter has reached its limit. The after-each statement is then executed, and is usually used to increment or dec‐ rement the counter; the condition is then immediately tested again. Thus, to execute a block using integer values 1, 2, 3, 4, and 5 for i, the notation is:
int i;
for (i = 1; i < 6; i++) {
// ... statements ...
The need for a counter intended to exist solely within the for loop is so common that
C99 permits the declaration of the counter as part of the before-all statement; the
declared variable’s scope is then inside the curly braces:
The for loop is one of the few areas in which Objective-C extends C’s flow-control syntax. Certain Objective-C objects, such as NSArray, represent enumerable collections of other objects; “enumerable” basically means that you can cycle through the collection, and cycling through a collection is called enumerating the collection. (I’ll discuss the main enumerable collection types in Chapter 10.) To make enumerating easy, Objective-C provides a for...in operator, which works like a for loop:
To abort a loop from inside the curly braces, use the break statement. To abort the current iteration from within the curly braces and proceed to the next iteration, use the continue statement. In the case of while and do, continue means to perform imme‐ diately the conditional test; in the case of a for loop, continue means to perform im‐ mediately the after-each statement and then the conditional test.
for (int i = 1; i < 6; i++) {
// ... statements ...
}
The for loop is one of the few areas in which Objective-C extends C’s flow-control syntax. Certain Objective-C objects, such as NSArray, represent enumerable collections of other objects; “enumerable” basically means that you can cycle through the collection, and cycling through a collection is called enumerating the collection. (I’ll discuss the main enumerable collection types in Chapter 10.) To make enumerating easy, Objective-C provides a for...in operator, which works like a for loop:
SomeType* oneItem;
for (oneItem in myCollection) {
// ... statements ....
}
On each pass through the loop, the variable oneItem (or whatever you call it) takes on
the next value from within the collection. As with the C99 for loop, oneItem can be
declared in the for statement, limiting its scope to the curly braces:
for (SomeType* oneItem in myCollection) {
// ... statements ....
}
To abort a loop from inside the curly braces, use the break statement. To abort the current iteration from within the curly braces and proceed to the next iteration, use the continue statement. In the case of while and do, continue means to perform imme‐ diately the conditional test; in the case of a for loop, continue means to perform im‐ mediately the after-each statement and then the conditional test.
Note : It is permissible for a C statement to be compounded of multiple state‐ ments, separated by commas, to be executed sequentially. The last of the multiple statements is the value of the compound statement as a whole. This construct, for instance, lets you perform some secondary action before each test of a condition or perform more than one after-each action.
We can now turn to the question of what a condition consists of. C has no separate
boolean type; a condition either evaluates to 0, in which case it is considered false, or it
doesn’t, in which case it is true. Comparisons are performed using the equality and
relational operators (K&R 2.6); for example, == compares for equality, and < compares
for whether the first operand is less than the second. Logical expressions can be com‐
bined using the logical-and operator (&&) and the logical-or operator (||); using these
along with parentheses and the not operator (!) you can form complex conditions.
Evaluation of logical-and and logical-or expressions is short-circuited, meaning that if
the left condition settles the question, the right condition is never even evaluated.
Warning : Don’t confuse the logical-and operator (&&) and the logical-or opera‐ tor (||) with the bitwise-and operator (&) and the bitwise-or opera‐ tor (|) discussed earlier. Writing & when you mean && (or vice versa) can result in surprising behavior.
Warning : Don’t confuse the logical-and operator (&&) and the logical-or opera‐ tor (||) with the bitwise-and operator (&) and the bitwise-or opera‐ tor (|) discussed earlier. Writing & when you mean && (or vice versa) can result in surprising behavior.
The operator for testing basic equality, ==, is not a simple equal sign; forgetting the
difference is a common novice mistake. The problem is that such code is legal: simple
assignment, which is what the equal sign means, has a value, and any value is legal in a
condition. So consider this piece of (nonsense) code:
You might think that the while condition tests whether i is 1. You might then think: i is 0, so the while body will never be performed. Right? Wrong. The while condition does not test whether i is 1; it assigns 1 to i. The value of that assignment is also 1, so the condition evaluates to 1, which means true. So the while body is performed. Moreover, even though the while body assigns 0 to i, the condition is then evaluated again and assigns 1 to i a second time, which means true yet again. And so on, forever; we’ve written an endless loop, and the program will hang.
C programmers revel in the fact that testing for zero and testing for false are the same thing and use it to create compact conditional expressions, which are considered elegant and idiomatic. Such idioms can be confusing, but one of them is commonly used in Objective-C, namely, in order to test an object reference to see whether it is nil. Since nil is a form of zero, one can ask whether an object s is nil like this:
// ...
}
int i = 0;
while (i = 1) {
i = 0;
}
You might think that the while condition tests whether i is 1. You might then think: i is 0, so the while body will never be performed. Right? Wrong. The while condition does not test whether i is 1; it assigns 1 to i. The value of that assignment is also 1, so the condition evaluates to 1, which means true. So the while body is performed. Moreover, even though the while body assigns 0 to i, the condition is then evaluated again and assigns 1 to i a second time, which means true yet again. And so on, forever; we’ve written an endless loop, and the program will hang.
C programmers revel in the fact that testing for zero and testing for false are the same thing and use it to create compact conditional expressions, which are considered elegant and idiomatic. Such idioms can be confusing, but one of them is commonly used in Objective-C, namely, in order to test an object reference to see whether it is nil. Since nil is a form of zero, one can ask whether an object s is nil like this:
if (!s) {
// ...
}
Objective-C introduces a BOOL type, which you should use if you need to capture or
maintain a condition’s value as a variable, along with constants YES and NO (repre‐
senting 1 and 0), which you should use when setting a boolean value. Don’t compare
anything against a BOOL, not even YES or NO, because a value like 2 is true in a con‐
dition but is not equal to YES or NO. (Getting this wrong is a common beginner mistake,
and can lead to unintended results.) Just use the BOOL directly as a condition, or as
part of a complex condition, and all will be well. For example:
BOOL isnil = (nil == s);
if (isnil) { // not: if (isnil == YES)
No comments:
Post a Comment