What is the difference between the following programs? They both interpret some imaginary exam result in the same way. They both look identical when compiled and run. Why then are they different? /**************************************************//* Program 1 *//**************************************************/ #include
The answer is that the second of these programs can be more efficient. This because it uses the else form of the if statement which in turn means that few things have to be calculated. Program one makes every single test, because the program meets every if statement, one after the other. The second program does not necessarily do this however. The nested if statements make sure that the second two tests are only made if the first one failed. Similarly the third test is only performed if the first two failed. So the second program could end up doing a third of the work of the first program, in the best possible case. Nesting decisions like this can be an efficient way of controlling long lists of decisions like those above. Nested loops make a program branch into lots of possible paths, but choosing one path would preclude others.
Node:switch, Next:Example 15, Previous:Stringing together if..else, Up:Decisions
switch: integers and characters
The switch construction is another way of making a program path branch into lots of different limbs. It can be used as a different way of writing a string of if .. else statements, but it is more versatile than that and it only works for integers and character type values. It works like a kind of multi-way switch. (See the diagram.) The switch statement has the following form: switch (int or char expression) { case constant : statement; break; /* optional */ ... }
It has an expression which is evaluated and a number of constant `cases' which are to be chosen from, each of which is followed by a statement or compound statement. An extra statement called break can also be incorporated into the block at any point. break is a reserved word.
The switch statement can be written more specifically for integers: switch (integer value) { case 1: statement1; break; /* optional line */ case 2: statement2; break; /* optional line */ .... default: default statement break; /* optional line */ }
When a switch statement is encountered, the expression in the parentheses is evaluated and the program checks to see whether the result of that expression matches any of the constants labelled with case. If a match is made (for instance, if the expression is evaluated to 23 and there is a statement beginning "case 23 : ...") execution will start just after that case statement and will carry on until either the closing brace } is encountered or a break statement is found. break is a handy way of jumping straight out of the switch block. One of the cases is called default. Statements which follow the default case are executed for all cases which are not specifically listed. switch is a way of choosing some action from a number of known instances. Look at the following example.
Node:Example 15, Next:To try, Previous:switch, Up:Decisions
Example Listing/************************************************//* *//* switch .. case *//* *//************************************************/ /* Morse code program. Enter a number and */ /* find out what it is in Morse code */ #include
The program selects one of the printf statements using a switch construction. At every case in the switch, a break statement is used. This causes control to jump straight out of the switch statement to its closing brace }. If break were not included it would go right on executing the statements to the end, testing the cases in turn. break this gives a way of jumping out of a switch quickly.
There might be cases where it is not necessary or not desirable to jump out of the switch immediately. Think of a function yes() which gets a character from the user and tests whether it was 'y' or 'Y'. yes () /* A sloppy but simple function */ {switch (getchar()) { case 'y' : case 'Y' : return TRUE default : return FALSE }}
If the character is either 'y' or 'Y' then the function meets the statement return TRUE. If there had been a break statement after case 'y' then control would not have been able to reach case 'Y' as well. The return statement does more than break out of switch, it breaks out of the whole function, so in this case break was not required. The default option ensures that whatever else the character is, the function returns false.
Node:To try, Previous:Example 15, Up:Decisions
Things to try
Write a program to get a lot of numbers from the user and print out the maximum and minimum of those.
Try to make a counter which is reset to zero when it reaches 9999.
Try to write a program incorporating the statement if (yes()) {...}.
Node:Loops, Next:Arrays, Previous:Decisions, Up:Top
Loops
Controlling repetitive processes. Nesting loops
Decisions can also be used to make up loops. Loops free a program from the straitjacket of doing things only once. They allow the programmer to build a sequence of instructions which can be executed again and again, with some condition deciding when they will stop. There are three kinds of loop in C. They are called:
while
do ... while
for
These three loops offer a great amount of flexibility to programmers and can be used in some surprising ways!
while:
Example 16:
Example 17:
do while:
Example 18:
for:
The flexible for loop:
Quitting Loops and Hurrying Them Up!:
Nested Loops:
Questions 18:
Node:while, Next:Example 16, Previous:Loops, Up:Loops
while
The simplest of the three loops is the while loop. In common language while has a fairly obvious meaning: the while-loop has a condition: while (condition) { statements; }
and the statements in the curly braces are executed while the condition has the value "true" ( 1 ). There are dialects of English, however, in which "while" does not have its commonplace meaning, so it is worthwhile explaining the steps which take place in a while loop.
The first important thing about this loop is that has a conditional expression (something like (a > b) etc...) which is evaluated every time the loop is executed by the computer. If the value of the expression is true, then it will carry on with the instructions in the curly braces. If the expression evaluates to false (or 0) then the instructions in the braces are ignored and the entire while loop ends. The computer then moves onto the next statement in the program.
The second thing to notice about this loop is that the conditional expression comes at the start of the loop: this means that the condition is tested at the start of every `pass', not at the end. The reason that this is important is this: if the condition has the value false before the loop has been executed even once, the statements inside the braces will not get executed at all - not even once.
The best way to illustrate a loop is to give an example of its use. One example was sneaked into an earlier chapter before its time, in order to write the skipgarb() function which complemented scanf(). That was: skipgarb () /* skip garbage corrupting scanf */ {while (getchar() != '\n') { }}
This is a slightly odd use of the while loop which is pure C, through and through. It is one instance in which the programmer has to start thinking C and not any other language. Something which is immediately obvious from listing is that the while loop in skipgarb() is empty: it contains no statements. This is quite valid: the loop will merely do nothing a certain number of times... at least it would do nothing if it were not for the assignment in the conditional expression! It could also be written: skipgarb () /* skip garbage corrupting scanf */ {while (getchar() != '\n') { }}
The assignment inside the conditional expression makes this loop special. What happens is the following. When the loop is encountered, the computer attempts to evaluate the expression inside the parentheses. There, inside the parentheses, it finds a function call to getchar(), so it calls getchar() which fetches the next character from the input. getchar() then takes on the value of the character which it fetched from the input file. Next the computer finds the != "is not equal to" symbol and the newline character \n. This means that there is a comparison to be made. The computer compares the character fetched by getchar() with the newline character and if they are `not equal' the expression is true. If they are equal the expression is false. Now, if the expression is true, the while statement will loop and start again - and it will evaluate the expression on every pass of the loop to check whether or not it is true. When the expression eventually becomes false the loop will quit. The net result of this subtlety is that skipgarb() skips all the input characters up to and including the next newline \n character and that usually means the rest of the input.
Node:Example 16, Next:Example 17, Previous:while, Up:Loops
Example Listing
Another use of while is to write a better function called yes(). The idea of this function was introduced in the previous section. It uses a while loop which is always true to repeat the process of getting a response from the user. When the response is either yes or no it quits using the return function to jump right out of the loop. /***********************************************//* *//* Give me your answer! *//* *//***********************************************/ #include
Node:Example 17, Next:do while, Previous:Example 16, Up:Loops
Example Listing
This example listing prompts the user to type in a line of text and it counts all the spaces in that line. It quits when there is no more input left and printf out the number of spaces. /***********************************************//* *//* while loop *//* *//***********************************************/ /* count all the spaces in an line of input */ #include
Node:do while, Next:Example 18, Previous:Example 17, Up:Loops
do..while
The do..while loop resembles most closely the repeat..until loops of Pascal and BASIC except that it is the `logical opposite'. The do loop has the form: do { statements; } while (condition)
Notice that the condition is at the end of this loop. This means that a do..while loop will always be executed at least once, before the test is made to determine whether it should continue. This is the only difference between while and do..while.
A do..while loop is like the "repeat .. until" of other languages in the following sense: if the condition is NOTed using the ! operator, then the two are identical. repeat do == until(condition) while (!condition)
This fact might be useful for programmers who have not yet learned to think in C!
Node:Example 18, Next:for, Previous:do while, Up:Loops
Example Listing
Here is an example of the use of a do..while loop. This program gets a line of input from the user and checks whether it contains a string marked out with "" quote marks. If a string is found, the program prints out the contents of the string only. A typical input line might be: Onceupon a time "Here we go round the..."what a terrible..
The output would then be: Here we go round the...
If the string has only one quote mark then the error message `string was not closed before end of line' will be printed. /**********************************************//* *//* do .. while demo *//* *//**********************************************/ /* print a string enclosed by quotes " " */ /* gets input from stdin i.e. keyboard */ /* skips anything outside the quotes */ #include
Node:for, Next:The flexible for loop, Previous:Example 18, Up:Loops
for
The most interesting and also the most difficult of all the loops is the for loop. The name for is a hangover from earlier days and other languages. It is not altogether appropriate for C's version of for. The name comes from the typical description of a classic for loop:
For all values of variable from value1 to value2 in steps of value3, repeat the following sequence of commands....
In BASIC this looks like: FOR variable = value1 TO value2 STEP value3 NEXT variable
The C for loop is much more versatile than its BASIC counterpart; it is actually based upon the while construction. A for loop normally has the characteristic feature of controlling one particular variable, called the control variable. That variable is somehow associated with the loop. For example it might be a variable which is used to count "for values from 0 to 10" or whatever. The form of the for loop is: for (statement1; condition; statement2) { }
For normal usage, these expressions have the following significance.
statement1
This is some kind of expression which initializes the control variable. This statement is only carried out once before the start of the loop. e.g. i = 0;
condition
This is a condition which behaves like the while loop. The condition is evaluated at the beginning of every loop and the loop is only carried out while this expression is true. e.g. i < 20;
statement2
This is some kind of expression for altering the value of the control variable. In languages such as Pascal this always means adding or subtracting 1 from the variable. In C it can be absolutely anything. e.g. i++ or i *= 20 or i /= 2.3 ...
Compare a C for loop to the BASIC for loop. Here is an example in which the loop counts from 0 to 10 in steps of 0.5: FOR X = 0 TO 10 STEP 0.5 NEXT X for (x = 0; x <= 10; x += 0.5) { }
The C translation looks peculiar in comparison because it works on a subtly different principle. It does not contain information about when it will stop, as the BASIC one does, instead it contains information about when it should be looping. The result is that a C for loop often has the <= symbol in it. The for loop has plenty of uses. It could be used to find the sum of the first n natural numbers very simply: sum = 0; for (i = 0; i <= n; i++) { sum += i; }
It generally finds itself useful in applications where a single variable has to be controlled in a well determined way.
g4
Example Listing
This example program prints out all the primes numbers between 1 and the macro value maxint. Prime numbers are numbers which cannot be divided by any number except 1 without leaving a remainder. /************************************************//* *//* Prime Number Generator #1 *//* *//************************************************/ /* Check for prime number by raw number */ /* crunching. Try dividing all numbers */ /* up to half the size of a given i, if */ /* remainder == 0 then not prime! */ #include
Node:The flexible for loop, Next:Quitting Loops and Hurrying Them Up!, Previous:for, Up:Loops
The flexible for loop
The word `statement' was chosen carefully, above, to describe what goes into a for loop. Look at the loop again: for (statement1; condition; statement2) { }
Statement really means what it says. C will accept any statement in the place of those above, including the empty statement. The while loop could be written as a for loop! for (; condition; ) /* while ?? */ { }
Here there are two empty statements, which are just wasted. This flexibility can be put to better uses though. Consider the following loop: for (x = 2; x <= 1000; x = x * x) { .... }
This loop begins from 2 and each time the statements in the braces are executed x squares itself! Another odd looking loop is the following one: for (ch = '*'; ch != '\n'; ch = getchar()) { }
This could be used to make yet another different kind of skipgarb() function. The loop starts off by initializing ch with a star character. It checks that ch != '\n' (which it isn't, first time around) and proceeds with the loop. On each new pass, ch is reassigned by calling the function getchar(). It is also possible to combine several incremental commands in a loop: for (i = 0, j=10; i < j; i++, j--) { printf("i = %d, j= %d\n",i,j); }
Statement2 can be any statement at all which the programmer would like to be executed on every pass of the loop. Why not put that statement in the curly braces? In most cases that would be the best thing to do, but in special instances it might keep a program tidier or more readable to put it in a for loop instead. There is no good rule for when to do this, except to say: make you code as clear as possible.
It is not only the statements which are flexible. An unnerving feature of the for construction (according to some programmers) is that even the conditional expression in the for loop can be altered by the program from within the loop itself if is written as a variable. int i, number = 20; for (i = 0; i <= number; i++) { if (i == 9) { number = 30; } }
This is so nerve shattering that many languages forbid it outright. To be sure, is not often a very good idea to use this facility, but in the right hands, it is a powerful one to have around.
Node:Quitting Loops and Hurrying Them Up!, Next:Nested Loops, Previous:The flexible for loop, Up:Loops
Quitting Loops and Hurrying Them Up!
C provides a simple way of jumping out of any of the three loops above at any stage, whether it has finished or not. The statement which performs this action is the same statement which was used to jump out of switch statements in last section. break;
If this statement is encountered a loop will quit where it stands. For instance, an expensive way of assigning i to be 12 would be: for (i = 1; i <= 20; i++) { if (i == 12) { break; } }
Still another way of making skipgarb() would be to perform the following loop: while (TRUE) { ch = getchar(); if (ch == '\n') { break; } }
Of course, another way to do this would be to use the return() statement, which jumps right out of a whole function. break only jumps out of the loop, so it is less drastic.
As well as wanting to quit a loop, a programmer might want to hurry a loop on to the next pass: perhaps to avoid executing a lot of irrelevant statements, for instance. C gives a statement for this too, called: continue;
When a continue statement is encountered, a loop will stop whatever it is doing and will go straight to the start of the next loop pass. This might be useful to avoid dividing by zero in a program: for (i = -10; i <= 10; i++) { if (i == 0) { continue; } printf ("%d", 20/i); }
Node:Nested Loops, Next:Questions 18, Previous:Quitting Loops and Hurrying Them Up!, Up:Loops
Nested Loops
Like decisions, loops will also nest: that is, loops can be placed inside other loops. Although this feature will work with any loop at all, it is most commonly used with the for loop, because this is easiest to control. The idea of nested loops is important for multi-dimensional arrays which are examined in the next section. A for loop controls the number of times that a particular set of statements will be carried out. Another outer loop could be used to control the number of times that a whole loop is carried out. To see the benefit of nesting loops, the example below shows how a square could be printed out using two printf statements and two loops. /*****************************************//* *//* A "Square" *//* *//*****************************************/ #include
The output of this program is a "kind of" square: ****************************************************************************************************
Node:Questions 18, Previous:Nested Loops, Up:Loops
Questions
How many kinds of loop does C offer, and what are they?
When is the condition tested in each of the loops?
Which of the loops is always executed once?
Write a program which copies all input to output line by line.
Write a program to get 10 numbers from the user and add them together.
0 comments: on " "
Post a Comment