We’ve learned that the instructions are executed one after the other from the beginning to the end within a function. Quite often though, we actually need more than that. For example, we might need to do certain things only under certain conditions, or we need to do certain things more than one time before continuing with something else. We basically need to control the flow of our program, or in other words, making decisions based on conditions.
C language provides a few different flow control or decision making methods. Before explaining them, let’s first introduce the ‘block’ and ‘condition’.
block: a group of instructions that are enclosed in a pair of curly braces. Instructions in a block are executed together, variable definition within a block is also allowed, which we’ll learn later.
Any number of instructions can be grouped together by having ‘{‘ and ‘}’ around them, anywhere. But normally it only makes sense to group instructions together for given conditions. For example, if this condition is true, then do these block of instructions.
A block looks like the following,
|
{ instruction_1; instruction_2; ... instruction_N; } |
condition: a test expression that is evaluated to either true or false. For example, ‘3 > 1′ is a true condition, and ‘2 == 3′ is false one (note the double ‘=’ sign, since a single ‘=’ is used for value assignment). It is not very useful to have constant condition like that though, usually the test expression has variable in it, so we test whether the variable value meets the condition or not at our program run time. For example, ‘x > 2′ will be true only if the value of variable x is greater than 2.
With that, here comes the flow control methods …
1. if … else
if ( conditions ) blockA else blockB
if ‘conditions’ are true, then blockA will be executed, otherwise instructions in blockB will be executed, for example,
|
if ( x > 1 ) { printf ("hey, x is greater than 1\n"); } else { printf ("aha, x is less than or equal to 1\n"); } |
The else part is optional, for example,
|
if ( x == 100 ) { printf (" this is good\n"); } |
if … else can be concatenated and cascaded, to however many levels needed, for example,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
|
if (x > 100) { printf ("x is greater than 100\n"); } else if (x > 90) { printf ("x is greater than 90\n"); } else { printf ("x is smaller than or equal to 90\n"); if (x == 50) { printf("hey, I'm half of 100\n"); } else { if (x > 50) { printf("x is bigger than 50\n"); } else { printf("x is less than 50\n"); /* QUESTION: can x be equal to 50 here? */ } } } |
As shown above, the position of the ‘{‘ or ‘}’ does not really matter, but it is important to make sure they always come as a pair.
2. switch … case
switch ( variable or expression ) {case ( constant_1 ) : instructions; break; case ( constant_2 ) : instructions; break; … default : instructions; break; }
Depending on the value of ‘variable or expression’, only the instructions under the matching ‘case’ are executed.
The ‘break‘ instruction ends the entire switch block. Without that, instructions from the following ‘case’ will be executed, till it hits a ‘break‘ statement.
For example,
|
switch (x) { case 100 : printf ("x = 100\n"); break; case 50 : printf ("x = 50\n"); break; default : printf ("x is neither 100 nor 50\n"); break; } |
3. goto
goto label;
Any time when there is a ‘goto label’ statement, program will unconditionally go to the instruction pointed to by ‘label’. For example,
|
printf ("I am here\n"); goto next_st; printf ("never come here\n"); next_st: /* the label name must be followed by a : */ printf ("next statement\n"); |
Note that in above code, the instruction between the ‘goto’ statement and label ‘next_st’ will never get executed. Thus ‘goto’ is usually paired with ‘if‘ or other conditional statement.
Please keep in mind that we should always try to minimize of the use of ‘goto’ statement, as it breaks the normal flow of the program and makes it hard to follow and understand the program.
4. while … do
This comes in two forms,
while ( conditions ) block
do block while ( conditions );
The first form executes the block while conditions are true, the next block first executes the block once, then continue to execute block while conditions are true. For example,
|
x = 1; while (x < 3) { printf ("x = %d\n", x); x = x + 1; } |
or,
|
x = 1; do { printf ("x = %d\n", x); x = x + 1; } while (x < 3); |
Exercise: are the output from above two different from each other? what if we change line #1 to ‘x = 5’?
5. for loop
for ( initial instructions; conditions; update instructions ) block
The initial instructions (separated by ,) are executed once and once only at the beginning of loop.
Then the conditions are tested, if false, the loop is terminated, otherwise the the block of instructions are executed.
Then the update instructions are executed.
The above repeats until the loop terminates, for example,
|
for (ii = 1; ii < 3; ii++) { printf ("ii = %d\n", ii); } |
Note that ‘ii++’ is the same as ‘ii = ii + 1′.
It is ok to have all fields of for loop empty, in which case it becomes an infinite loop. In real programming though, you probably want some condition to terminate the loop. For example,
|
for ( ; ; ) { printf ("danger, infinite loop\n"); } |
6. break … continue
Within while or for loop, ‘break‘ statement will immediately terminate the loop, ‘continue‘ statement will immediately skip the rest of the instructions in the loop and jumps to the beginning of the loop. For example,
|
int ii = 0; /* this is another form of infinite loop */ while ( 1 ) { ii++; printf ("ii = %d\n", ii); /* the {} are ignored since there's only one instruction in the block. */ if (ii == 10) break; if (ii >= 5 ) continue; printf ("I am here, ii = %d\n", ii); } |
Exercise: how many times the “I am here” is printed above?
We learned all the basic flow controls above, there’s one last statement, ‘return‘.
return: immediately returns from and terminates function.
The return statement can be anywhere in the function, after that instruction, the entire function terminates and the program flow goes back to the caller of the function. If we return from the ‘main’ function, the entire program terminates.
So we ‘return’ here …