Go with the Flow
Pages: 1, 2
Now We're Writing in Code
Some people are all about shortening the code they write. This can be
an admirable goal: less code can mean a faster operation and a simpler
more maintainable codebase. Sometimes brevity can make your code much
cleaner. Toward these goals C includes an operator that performs one
of the tasks that an if/else block is often
called in to perform: setting a variable to two different values based
on some boolean logic. This operator, called the ternary
operator, turns this code:
int integerForSeedValue(int seedNumber) {
int retval = 0;
if (seedNumber == 8) {
retval = seedNumber - 3;
} else {
retval = seedNumber * 3;
}
return retval;
}
Into this code:
int integerForSeedValue(int seedNumber) {
return (seedNumber == 8) ? (seedNumber - 3) : (seedNumber * 3);
}
That's quite a savings of space, but the second snippet looks like quantum physics. Let's take this line apart token by token.
We start with return, which we know and love from our last
lesson. Then we've got a bit in parentheses that is boolean
logic. This is the condition we're used to in a normal
if/else block, expressed in exactly the same
way. If we put a semicolon here, the result of the condition would be
returned. Instead we have a question mark, which tells the computer
that it just read a condition for a ternary operator, and the other
parts are next. The next bit in parentheses is what we want the
ternary operator to evaluate to if the condition is true. This is
first, just like the true condition is first in a normal
if/else block. Then we have a colon, which
tells the computer that we're done with the true case and moving on to
the false case. Here we put what we want the ternary operator to
evaluate to if the condition is false.
So you can read the question mark as "if the following is true, evaluate this" and the colon as "but if the condition was false, evaluate this instead." But note that you can only evaluate the cases, meaning multiple lines isn't an option, and each case must evaluate to be the proper type or you'll get a warning.
Another thing to note is that we've introduced a new operator,
"==",
the
equality conditional. This checks to see if the thing on the left
is equal to the thing on the right, and if they are it evaluates to
TRUE, otherwise to FALSE. Why isn't it a single equals sign? Because
we already use that token to set the value of variables and that means
we can't use it here.
Flip the Switch
When you're dealing with code that must decide between a few options,
if is the way to go. But if you need to use one input to
decide amongst a lot of things, Then it's much simpler to just use a
switch:
int integerForSeedValue(int seedNumber) {
int retval = 0;
switch (seedNumber) {
case 1:
printf("The Seed was one, not many.\n");
retval = seedNumber;
break;
case 8:
printf("We have an eightfold seed.\n");
retval = seedNumber * 2;
break;
}
return retval;
}
In this section, too, we will examine many different incarnations of
the integerForSeedValue function, and you should run your
program with each of them.
Let's pull the code apart. We start with the token switch,
then something in parentheses. After that is a block. But the stuff in
parentheses isn't a condition, it's the switch variable. This is the
variable whose value determines what gets done inside the switch
block.
Once we know this variable, we move through the switch block looking
for case lines with the same value, and ignoring all the
other code until we find one. When we do find one, we execute the code
after it until we hit a break statement, which pops us
out of the block. Note that hitting another case
statement will not end the block: a break is the only
thing that will stop it. That seems odd until you consider the
following:
int integerForSeedValue(int seedNumber) {
int retval = 0;
switch (seedNumber) {
case 1:
printf("Surreptitiously, a singular seed..\n");
retval = seedNumber;
break;
case 6:
case 7:
case 8:
printf("Our seed is 6, 7, or maybe even 8!\n");
retval = seedNumber * 2;
break;
}
return retval;
}
Which means that if seedNumber is 6, 7, or 8, retval
will be set to seedNumber * 2. In other words, you can
group cases together if you want them all to do the same
code.
But note that each case here is a constant integer. This is a very important
limitation in the way switch works: its cases can only be
constants and can't be boolean expressions, like
if/else blocks' conditions.
The switch syntax also provides a way to catch anything
you didn't account for. The following snippet is an example:
int integerForSeedValue(int seedNumber) {
int retval = 0;
switch (seedNumber) {
case 1:
printf("He is The One.\n");
retval = seedNumber;
break;
case 8:
printf("And the number of the seed shall be eight.\n");
retval = seedNumber * 2;
default:
printf("What a seed it is!\n");
retval++;
}
return retval;
}
We added a default case. The code here will be executed
if no matching case is found, or if no break
is found beforehand. Note that we took away the break in
case 8. This allows the default to be
executed when seedNumber is 8, which it is in our program
as written in Lesson 2.
But you might have noticed that the code in our default case is something
we haven't seen before. The "++" is yet another operator,
the
increment operator. It takes whatever is in retval and adds
one. It's sister the decrement
operator, "--", subtracts one.
Run all the different switch examples and see the results. Try to trace where the control flows.
A Conditional Ending
We've learned three ways of changing how our program control flows, each of which is useful for different situations. We can now change code execution based on boolean logic, we can set variables based on the same logic, and our code can change how it works based on the value of variables.
But there's more. As useful as these structures are, they don't let you do the same thing over and over, which is the exclusive domain of loops, which we will cover in our next lesson.
Seth Roby graduated in May of 2003 with a double major in English and Computer Science, the Macintosh part of a three-person Macintosh, Linux, and Windows graduating triumvirate.
Return to MacDevCenter.com
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 12 of 12.
-
Error in example on first page
2004-08-02 12:31:45 DrewE [Reply | View]
I believe that in the example on the first page, the first time "return" is listed in the program, it is supposed to be "retvar."
-
It is easy!
2003-09-01 18:58:41 anonymous2 [Reply | View]
This is old news, but I'm going to say it again. I've been so confused reading Obj-C tutorials (no prior C experience). The whole message this and message that thing was causing uncontrollable stupors. In three short lessons, it's all starting to make sense and I'm able to reread Mike Beam's articles and understand them with confidence.
Thanks!
Keep up the C training. Maybe you can shed some light on standard C library headers like stdio.h and math.h.
Here's something that's bothering me, though.
If header files are for functions, where do I find information for operators and whatnot?
For example:
I can go to the Help menu in Project Builder and open the Man page for "stdio" and it will give me a list of all the functions included with stdio.h. But I haven't found the info for operators like +, -, *, /, &&, ==, etc. or syntax for commands (functions?) like "if" and "switch".
-
Great Help
2003-08-24 03:06:15 anonymous2 [Reply | View]
Hi!
As you pointed out in your first article, if you don't know C and you buy a book like "Cocoa with Objective-C" it is easy to get lost. I did, and being very frustrated, I quit moving through the book. (Couldn't even make it past the first example.) Thanks to your article I have now moved on to page 193 and am going strong.
Thank you so much!
Keep up the good work, and keep those articles coming.
T.J. Hart
-
seedNumber and default statement
2003-08-23 22:16:53 anonymous2 [Reply | View]
Hi Seth,
At the end of your article you say:
"This allows the default to be executed when seedNumber is 8, which it is in our program as written in Lesson 2."
It seems to me that seedNumber is 6 in Lesson 2.
I look forward to your next article.
-
retval?
2003-08-22 02:56:22 anonymous2 [Reply | View]
Just wondering: is there any logic to how the return value is set in the various examples?
I've encountered:
retval = seedNumber * 2,
retval = seedNumber * 3,
retval = seedNumber - 3... -
retval?
2003-08-22 11:04:14 tallama [Reply | View]
Hi this is the author.
No, there's no logic as to what the return values are, really, we're just trying to examine how the various conditionals work out. To do that, we're using a variety of similar code in different situations, which is really what you usually do in a conditional anyway.
-
Great series!
2003-08-22 02:48:13 anonymous2 [Reply | View]
So far I've been able to follow the series easily. Can't wait for the next episode. BTW, what is the publishing schedule?
-
How to read the question mark ("?")
2003-08-20 12:23:02 halliday [Reply | View]
Seth, you said:
<blockquote>So you can read the question mark as "if the following is true, evaluate this"</blockquote>
Unfortunately, this should read either as:
<blockquote>So you can read the question mark as "if the preceding is true, evaluate this"</blockquote>
or as:
<blockquote>So you can read the question mark as "if the condition is (was) true, evaluate this"</blockquote>
(Just trying to help clarity [and I wish the blockquotes were not mangled in my post].)
-
Woo Hoo!
2003-08-20 06:20:18 anonymous2 [Reply | View]
I've been waiting for another installment in this series, and finally it's here. Seth, you have an uncanny ability to be able to explain the subject matter and make it stick.
Thanks for your work and dedication to this series! I was beginning to get worried that there wasn't going to be another installment (what *IS* the publishing schedule for this series anyhow). Glad to see there indeed was more.





