Adding else to the if Statement

I l @ ve RuBoard

Adding else to the if Statement

The simple form of an if statement gives you the choice of executing a statement (possibly compound) or skipping it. C also enables you to choose between two statements by using the if else form. Let's use the if else form to fix an awkward segment from Listing 7.1.

 if (all_days != 0)       printf("%d days total: %.1f%% were below freezing.\n",          all_days, 100.0 * (float) cold_days / all_days); if (all_days == 0) printf("No data entered!\n"); 

If the program finds that days is not equal to , it should know that days must be without retesting, and it does. With if else you can take advantage of that knowledge by rewriting the fragment this way:

 if (all_days!= 0) printf("%d days total: %.1f%% were below freezing.\n",          all_days, 100.0 * (float) cold_days / all_days); else  printf("No data entered!\n"); 

Only one test is made. If the if test expression is true, the temperature data is printed. If it's false, the warning message is printed.

Note the general form of the if else statement:

 if (  expression  )  statement1  else statement2 

If expression is true (nonzero), statement1 is executed. If expression is false or zero, the single statement following the else is executed. The statements can be simple or compound. The indentation is not required by C, but it is the standard style. It shows at a glance the statements that depend on a test for execution.

If you want more than one statement between the if and the else , you must use braces to create a single block. The following construction violates C syntax, for the compiler expects just one statement (single or compound) between the if and the else :

 if (x > 0)   printf("Incrementing x:\n");   x++; else  printf("x <= 0 \n"); 

Instead, use this:

 if (x > 0) {   printf("Incrementing x:\n");   x++; } else printf ("x <= 0 \n"); 

The if statement enables you to choose whether to do one action. The if else statement enables you to choose between two actions. Figure 7.1 compares the two statements.

Figure 7.1. if versus if else .
graphics/07fig01.jpg

Another Example: Introducing getchar () and putchar ()

Most of the examples have used numeric input. To give you practice with other types, let's look at a character-oriented example. You already know how use scanf() and printf() with the %c specifier to read and write characters ; but now you'll meet a pair of C functions specifically designed for character-oriented I/O: getchar() and putchar() .

The getchar() function takes no arguments, and it returns the next character from input. For instance, the following statement reads the next input character and assigns its value to the variable ch :

 ch getchar(); 

This statement has the same effect as the following statement:

 scanf("%;c", &ch); 

The putchar() function prints its argument. For example, the next statement prints as a character the value previously assigned to ch :

 putchar(ch); 

This statement has the same effect as the following:

 printf("%c", ch); 

Because these functions deal only with characters, they are faster and more compact than the more general scanf() and printf() functions. Also, note that they don't need format specifiers; that's because they work with characters only. Both functions are typically defined in the stdio.h file. (Also, typically, they are preprocessor macros rather than true functions; we'll talk about function-like macros in Chapter 16, "The C Preprocessor and the C Library.")

Let's see how these functions work by writing a program that repeats an input line but replaces each nonspace character with the character that follows it in the ASCII code sequence. Spaces will be reproduced as spaces. You can state the desired response this way: If the character is a space, print it; otherwise , print the next character in the ASCII sequence. The C code looks much like this statement, as you can see in Listing 7.2.

Listing 7.2 The cypher1.c program.
 /* cypher1.c -- alters input, preserving spaces */ #include <stdio.h> #define SPACE ` '             /* that's quote-space-quote */ int main(void) {    char ch;    ch = getchar();            /* read a character         */    while (ch != `\n')         /* while not end of line    */    {        if (ch == SPACE)       /* leave the space          */            putchar(ch);       /* character unchanged      */        else            putchar(ch + 1);   /* change other characters  */        ch = getchar();        /* get next character       */    }    putchar(ch);               /* print the newline        */    return 0; } 

Here's a sample run:

  CALL ME HAL.  DBMM NF IBM/ 

Compare this loop to the one from Listing 7.1, which uses the status returned by scanf() instead of the value of the input item to determine when to terminate the loop. Listing 7.2, however, uses the value of the input item itself to decide when to terminate the loop. This difference results in a slightly different loop structure, with one read statement before the loop and one read statement at the end of each loop. C's flexible syntax, however, enables you to emulate Listing 7.1 by combining reading and testing into a single expression. That is, you can replace a loop of the form

 getchar();          /* read a character      */ `\n')               /* while not end of line */ {   ...                /* process character    */   ch = getchar();    /* get next character   */ } 

with one that looks like this:

 while ((ch = getchar()) != `\n') {     ...                      /* process character        */ } 

The critical line is this:

 while ((ch = getchar()) != `\n') 

It demonstrates a characteristic C programming style: combining two actions in one expression. The actions are assigning a value to ch and comparing this value to the newline character. The parentheses around ch = getchar() make it the left operand of the != operator. To evaluate this expression, the computer must first call the getchar() function and then assign its return value to ch . Because the value of an assignment expression is the value of the left member, the value of ch = getchar() is just the new value of ch . Therefore, after ch is read, the test condition boils down to ch != `\n' , that is, to ch not being the newline character.

This particular idiom is very common in C programming. All the parentheses are necessary. Suppose you mistakenly used this:

 while getchar() != `\n') 

The != operator has higher precedence than = , so the first expression to be evaluated is getchar() != `\n' . Because this is a relational expression, its value is 1 or (true or false). Then this value is assigned to ch . Omitting the parentheses means that ch is assigned or 1 rather than the return value of getchar() ; this is not desirable.

The ctype .h Family of Character Functions

Notice that the output for Listing 7.2 shows a period being converted to a slash; that's because the ASCII code for the slash character is one greater than the code for the period character. But if the point of the program is to convert only letters, it would be nice to leave all non- letters , not just spaces, unaltered. The logical operators, discussed later in this chapter, provide a way to test whether a character is not a space and not a comma, and so on, but it would be rather cumbersome to list all the possibilities. Fortunately, ANSI C has a standard set of functions for analyzing characters; the ctype.h header file contains the prototypes . These functions take a character as an argument and return nonzero (true) if the character belongs to a particular category and false otherwise. For example, the isalpha () function returns true if its argument is a letter. Listing 7.3 generalizes Listing 7.2 by using this function; it also incorporates the shortened loop structure we just discussed.

Listing 7.3 The cypher2.c program.
 /* cypher2.c -- alters input, preserving non-letters   */ #include <stdio.h> #include <ctype.h>       /* for isalpha()         */ int main(void) {    char ch;    while ((ch = getchar()) != `\n')    {        if (isalpha(ch))       /* if a letter,          */            putchar(ch + 1);   /* change it             */        else            putchar(ch);       /* otherwise print as is */    }    putchar(ch);               /* print the newline     */    return 0; } 

Here is a sample run; note how both lowercase and uppercase letters are encyphered, but spaces and punctuation aren't:

  See, it's a programmer!  Tff, ju't b qsphsbnnfs! 

Tables 7.1 and 7.2 list several functions provided when you include the ctype.h header file. Note that the mapping functions don't modify the original argument; instead, they return the modified value. That is,

 tolower(ch);    // no effect on ch 

doesn't change ch . To change ch do this:

 tolower(ch); // convert ch to lowercase 
Table  7.1. ctype.h character-testing functions.
Name True If Argument Is
isalnum () Alphanumeric (alphabetic or numeric)
isalpha() Alphabetic
iscntrl () A control character, such as Ctrl+B
isdigit () A digit
isgraph () Any printing character other than a space
islower () A lowercase character
isprint () A printing character
ispunct () A punctuation character (any printing character other than a space or an alphanumeric character)
isspace () A whitespace character: space, newline, formfeed, carriage return, vertical tab, horizontal tab, or, possibly, other implementation-defined characters
isupper () An uppercase character
isxdigit () A hexadecimal-digit character
Table  7.2. ctype.h character-mapping functions.
Name Action
tolower() If the argument is an uppercase character, returns the lowercase version; otherwise, just returns the original argument
toupper() If the argument is a lowercase character, returns the uppercase version; otherwise, just returns the original argument

Multiple Choice else if

Life often offers us more than two choices. You can extend the if else structure with else if to accommodate this fact. Let's look at a particular example. Utility companies often have charges that depend on the amount of energy the customer uses. Here are the rates one company charges for electricity, based on kilowatt-hours (kWh):

first 240 kWh: $0.11439 per kWh
next 300 kWh: $0.13290 per kWh
over 540 kWh: $0.14022 per kWh

If you worry about your energy management, you might want to prepare a program to calculate your energy costs. The program in Listing 7.4 is a first step in that direction.

Listing 7.4 The electric.c program.
 /* electric.c -- calculates electric bill */ #include <stdio.h> #define RATE1 0.11439       /* rate for first 240 kwh      */ #define RATE2 0.12032       /* rate for next 300 kwh       */ #define RATE3 0.14022       /* rate for over 540 kwh       */ #define BREAK1 240.0        /* first breakpoint for rates  */ #define BREAK2 540.0        /* second breakpoint for rates */ #define BASE1 (RATE1 * BREAK1)                             /* cost for 240 kwh            */ #define BASE2 (BASE1 + (RATE2 * (BREAK2 - BREAK1)))                             /* cost for 540 kwh            */ int main(void) {   double kwh;               /* kilowatt-hours used         */   double bill;              /* charges                     */   printf("Please enter the kwh used.\n");   scanf("%lf", &kwh);       /* %lf for type double        */   if (kwh <= BREAK1)       bill = RATE1 * kwh;   else if (kwh <= BREAK2)   /* kwh between 240 and 540     */       bill = BASE1 + (RATE2 * (kwh - BREAK1));   else                      /* kwh above 540               */       bill = BASE2 + (RATE3 * (kwh - BREAK2));   printf("The charge for %.1f kwh is $%1.2f.\n", kwh, bill);   return 0; } 

Here's sample output:

 Please enter the kwh used.  438  The charge for 438.0 kwh is .28. 

Listing 7.4 uses symbolic constants for the rates so that the constants are conveniently gathered in one place. If the power company changes its rates (it's possible), having the rates in one place makes it easy to update them. The listing also expresses the rate breakpoints symbolically. They, too, are subject to change. BASE1 and BASE2 are expressed in terms of the rates and breakpoints. Then, if the rates or breakpoints change, the bases are updated automatically. You may recall that the preprocessor does not do calculations. Where BASE1 appears in the program, it will be replaced by 0.11439 * 240.0 . Don't worry; the compiler does evaluate this expression to its numerical value ( 27.4536 ) so that the final program code uses 27.4536 rather than a calculation.

The flow of the program is straightforward. The program selects one of three formulas, depending on the value of kwh . Figure 7.2 illustrates this flow. We should point out that the only way the program can reach the first else is if kwh is equal to or greater than 240 . Therefore, the else if (kwh <= BREAK2) line really is equivalent to demanding that kwh be between 240 and 540 , as we noted in the program comment. Similarly, the final else can be reached only if kwh exceeds 540 . Finally, note that BASE1 and BASE2 represent the total charges for the first 240 and 540 kilowatt-hours, respectively. Therefore, you need add on only the additional charges for electricity in excess of those amounts.

Figure 07.2. Program flow for Listing 7.4, electric.c .
graphics/07fig02.jpg

Actually, the else if is a variation on what you already knew. For example, the core of the program is just another way of writing

 if (kwh <=BREAK1)      bill = RATE1 * kwh; else     if (kwh <=BREAK2)         bill = BASE1 + RATE2 * (kwh - BREAK1);     else         bill = BASE2 + RATE3 * (kwh - BREAK2); 

That is, the program consists of an if else statement for which the statement part of the else is another if else statement. The second if else statement is said to be nested inside the first. Recall that the entire if else structure counts as a single statement, which is why we didn't have to enclose the nested if else in braces. However, using braces would clarify the intent of this particular format.

These two forms are perfectly equivalent. The only differences are in where you put spaces and newlines, and these differences are ignored by the compiler. Nonetheless, the first form is better because it shows more clearly that you are making a three-way choice. This form makes it easier to skim the program and see what the choices are. Save the nested forms of indentation for when they are needed, for instance, when you must test two separate quantities . An example of such a situation is having a 10% surcharge for kilowatt-hours in excess of 540 during the summer only.

You can string together as many else if statements as you need (within compiler limits, of course), as illustrated by this fragment:

 if (score < 1000)      bonus = 0; else if (score < 1500)      bonus = 1; else if (score < 2000)      bonus = 2; else if (score < 2500)      bonus = 4; else      bonus = 6; 

(This might be part of a game program, in which bonus represents how many additional photon bombs or food pellets you get for the next round.)

Speaking of compiler limits, the ANSI C standard requires that a compiler support a minimum of 15 levels of nesting, and the C9X draft extends the minimum requirement to 127 levels.

Pairing else with if

When you have a lot of ifs and elses, how does the computer decide which if goes with which else ? For example, consider the following program fragment:

 if (number > 6)     if (number < 12)        printf("You're close!\n"); else printf("Sorry, you lose a turn!\n"); 

When is Sorry, you lose a turn! printed? When number is less than or equal to 6 , or when number is greater than 12 ? In other words, does the else go with the first if or the second? The answer is, the else goes with the second if . That is, you would get these responses:

Number Response
5 none
10 You're close!
15 Sorry, you lose a turn!

The rule is that an else goes with the most recent if unless braces indicate otherwise (see Figure 7.3).

Figure 7.3. The rule for if else pairings.
graphics/07fig03.jpg

We indented the example to make it look as though the else goes with the first if , but remember that the compiler ignores indentation. If you really want the else to go with the first if , you could write the fragment this way:

 if (number > 6) {      if (number < 12)          printf("You're close!\n"); } else printf("Sorry, you lose a turn!\n"); 

Now you would get these responses:

Number Response
5 Sorry, you lose a turn!
10 You're close!
15 none

More Nested ifs

You've already seen that the if else if else sequence is a form of nested if , one that selects from a series of alternatives. Another kind of nested if is used when choosing a particular selection leads to an additional choice. For example, a program could use an if else to select between males and females. Each branch within the if else then could contain another if else to distinguish between different income groups.

Let's apply this form of nested if to the following problem. Given an integer, print all the integers that divide into it evenly; if there are no divisors, report that the number is prime.

This problem requires some forethought before you whip out the code. First, you need an overall design for the program. For convenience, the program should use a loop to enable you to input numbers to be tested . That way, you don't have to run the program again each time you want to examine a new number. We've already developed a model for this kind of loop:

 prompt user while the scanf() return value is 1    analyze the number and report results    prompt user 

Recall that by using scanf() in the loop test condition, the program attempts both to read a number and to check to see whether the loop should be terminated .

Next, you need a plan for finding divisors. Perhaps the most obvious approach is something like this:

 for (div = 2; div < num; div++)   if (num % div == 0)        printf("%d is divisible by %d\n", num, div); 

The loop checks all the numbers between 2 and num to see whether they divide evenly into num . Unfortunately, this approach wastes computer time. You can do much better. Consider, for example, finding the divisors of 144. You find that 144 % 2 is 0, meaning 2 goes into 144 evenly. If you then actually divide 2 into 144, you get 72, which also is a divisor, so you can get two divisors instead of one divisor out of a successful num % div test. The real payoff, however, comes in changing the limits of the loop test. To see how this works, look at the pairs of divisors you get as the loop continues: 2,72; 3,48; 4,36; 6,24; 8,18; 9,16; 12,12; 16,9; 18,8;. . . . Ah! After you get past the 12,12 pair, you start getting the same divisors (in reverse order) you already found. Instead of running the loop to 143, you can stop after reaching 12. That saves a lot of cycles!

Generalizing this discovery, you see that you have to test only up to the square root of num instead of to num . For numbers like 9, this is not a big savings, but the difference is enormous for a number like 10,000. Instead of messing with square roots, however, you can express the test condition as follows:

 for (div = 2; (div * div) <= num; div++)   if (num % div == 0)          rintf("%d is divisible by %d and %d.\n",                    num, div, num / div); 

If num is 144, the loop runs through div = 12 . If num is 145, the loop runs through div = 13 .

There are two reasons for using this test rather than a square root test. First, integer multiplication is much faster than extracting a square root. Second, the square root function hasn't been formally introduced yet.

We need to address just two more problems, and then you'll be ready to program. First, what if the test number is a perfect square? Reporting that 144 is divisible by 12 and 12 is a little clumsy, but you can use a nested if statement to test whether div equals num / div . If so, the program will print just one divisor instead of two.

 for (div = 2; (div * div) <= num; div++) {    if (num % div == 0)    {       if (div * div != num)          printf("%d is divisible by %d and %d.\n",              num, div, num / div);       else          printf("%d is divisible by %d.\n", num, div);    } } 

Note

Technically, the if else statement counts as a single statement, so the braces around it are not needed. The outer if is a single statement also, so the braces around it are not needed. However, when statements get long, the braces make it easier to see what is happening, and they offer protection if later you add another statement to an if or to the loop.


Second, how do you know if a number is prime? If num is prime, then program flow never gets inside the if statement. To solve this problem, you can set a variable to some value, say 1 , outside the loop and reset the variable to inside the if statement. Then, after the loop is completed, you can check to see whether the variable is still 1 . If it is, the if statement was never entered, and the number is prime. Such a variable is often called a flag.

Listing 7.5 incorporates all the ideas we've discussed. To extend the range, we've switched to type long .

Listing 7.5 The divisors.c program.
 /* divisors.c -- nested ifs display divisors of a number */ #include <stdio.h> #define NO 0 #define YES 1 int main(void) {    long num;                      /* number to be checked */    long div;                      /* potential divisors   */    int prime;    printf("Please enter an integer for analysis; ");    printf("Enter q to quit.\n");    while (scanf("%ld", #) == 1)    {       for (div = 2, prime = YES; (div * div) <= num; div++)       {          if (num % div == 0)          {             if ((div * div) != num)                printf("%ld is divisible by %ld and %ld.\n",                    num, div, num / div);             else                printf("%ld is divisible by %ld.\n", num, div);             prime = NO;           /* number is not prime  */          }       }       if (prime == YES)          printf("%ld is prime.\n", num);       printf("Please enter another integer for analysis; ");       printf("Enter q to quit.\n");    }    return 0; } 

Note that the program uses the comma operator in the for loop control expression to enable you to initialize prime to YES for each new input number.

Here's a sample run:

 Please enter an integer for analysis; Enter q to quit.  36  36 is divisible by 2 and 18. 36 is divisible by 3 and 12. 36 is divisible by 4 and 9. 36 is divisible by 6. Please enter another integer for analysis; Enter q to quit.  149  149 is prime. Please enter another integer for analysis; Enter q to quit.  30077  30077 is divisible by 19 and 1583. Please enter another integer for analysis; Enter q to quit.  q  

Summary: Using if Statements for Making Choices

Keywords:

 if, else 

General Comments:

In each of the following forms, the statement can be either a simple statement or a compound statement. A "true" expression means one with a nonzero value.

Form 1:

 if (  expression  )  statement  

The statement is executed if the expression is true.

Form 2:

 if (  expression  )  statement1  else  statement2  

If the expression is true, statement1 is executed. Otherwise, statement2 is executed.

Form 3:

 if (  expression1  )  statement1  else if (  expression2  )  statement2  else  statement3  

If expression1 is true, then statement1 is executed. If expression1 is false but expression2 is true, statement2 is executed. Otherwise, if both expressions are false, statement3 is executed.

Example:

 if (legs == 4)      printf("It might be a horse.\n"); else if (legs > 4)      printf("It is not a horse.\n"); else    /* case of legs < 4 */ {      legs++;      printf("Now it has one more leg.\n") } 
I l @ ve RuBoard


C++ Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 314
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net