CPS 202 Week 5, Chapter 5 Selection Statements Review homework for week 4 -------------------------- A programming language really starts to become something more than a glorified calculator when it can actually make decisions. With the logic that we can add to our programs with selection statements, we can start to write truly useful programs. if switch conditional statement if -- The if statement is one of the most versatile statements in C, or in any similar language. To use the if statement in its most basic form, we have to learn about the relational and logical operators. Relational operators < less than > greater than <= less than or equal to >= greater than or equal to == equal to != not equal to We look at these operators as ways of answering questions, questions for which there are only two possible answers, yes or no, or, in C terms, 1 or 0. a = 4 b = 5 is a less than b? -yes int a=4; int b=5; if (a < b) The test evaluates to a 0 if the test fails, or 1 if the test is successful. It is important to remember that C always is looking for that one answer, no matter what the question. The tests that require special mention are == and !=. The == must be used to test for equality. Using a single = results in assignment, not a logical test. int i = 4; if (i == 5) if (i = 5) // Assigns the value of 5 to i In the second if test, i is set to 5. Since all if statements must evaluate to a 1 or a 0, anything not 1 is converted to 0. In an assignment, the value of the assignment is the value assigned. Since 5 is not 0, the result is true. In other words, the test will never fail. != is harder to mess up than ==. The main thing is to remember the !. if (i == 5) { // body of the if } Just like main() uses curly braces to denote where the start and end of the function are, so too does if use curly braces to combine statements. Everything inside the braces will be done if the test is a success. If the test fails, control reverts immediately following the ending curly brace. With the if statement, as with many other statements we have yet to learn about, the curly braces are optional if there is only a single statement in the body of the if. So: if (i == 5) { printf("i is 5\n"); } can be written as just: if (i == 5) printf("i is 5\n"); This is a perfectly acceptable and common practice. You must be careful, though, when adding code: if (i == 5) printf("i is 5\n"); i = 0; The indents make it look as though the assignment is a part of the body of the if, but it is not. The assignment will happen whether or not i is 5. When adding code to an if with no braces, you must be sure to add the braces. Logical Operators && and || or ! not It is often the case that you will wish to combine several relational tests together. You do this using the and and or logical operators. Use && when the two parts of the test must be true. Use || when any of the tests need to be true. // Print a message when the speed is acceptable if (speed >= 40 && speed <= 65) printf("Speed is OK."); // Print a message if the age is 10 or 20 years if (age == 10 || age == 20) printf("The age is perfect."); Use the logical not to reverse a relational test. If the result of a test is a 1, placing a ! in front makes it 0. // Print a message if not old enough if (!(age >= 21)) printf("Too young"); Interestingly, the expression "!0" is equal to 1 and "!1" is equal to 0. Short-circuiting ---------------- One of the features of C's logical operators is an efficiency method called short-circuiting. This allows parts of a series of tests to be skipped, if the program can determine the answer based on prior tests. For example, with an && test, both sides must be true for the whole expression to be true. If the first part fails, there is no need to do the second part. speed = 35; if (speed >= 40 && speed <=65) Here, the first test fails - since all parts must pass for an and to be true, the whole thing is false. If speed is 50, then the first test is passed, and the second must be done - it passes, so the whole thing passes. If speed is 70, then the first passes but the second fails. With an or test, any one result must be true for the whole expression to be true. age = 10; if (age == 10 || age == 20) Here, age is 10, so the first test passes. Since only one test needs to pass, the second test is never done. If age is 20, then the first test fails, bu the second one passes. By placing more processor intensive code later in a list of && and || related tests, you can avoid running code that will just waste cycles. else ---- Often with an if, you want to do something if the if test failed. For this, we use the else keyword: if (speed >= 40 && speed <= 65) printf("Speed is OK"); else printf("Speed is not OK"); Multiple tests can be combined using else/if combinations: if (speed < 40) printf("Too slow"); else if (speed > 65) printf("Too fast"); else printf("Speed is OK"); Not every if has an else - only use them when needed. Dangling else ------------- The dangling else problem comes up when there are multiple ifs and elses that look like they match up one way, but really match up another way: if (speed > 65) if (speed > 100) printf("Way too fast"); else printf("Speed is OK"); In this case, the else is dangling because by the indents, it looks like the else belongs to the 65 if. But the problem is that the else goes with the most recent if, so it prints "OK" if the speed is between 66 and 100. To fix this, add braces where needed: if (speed > 65) { if (speed > 100) printf("Way too fast"); } else printf("Speed is OK"); Conditional expression ---------------------- A curious little piece of C, the conditional expression uses the ? and the : characters. The conditional expression is like an if/else, but much more compact: flag = 2; if (speed > 65) flag=1; else flag=0; The conditional expression is perfect for times like these: flag = (speed > 65) ? 1 : 0; The condition and the two possibilities are included on the expression. First, the test is done. If the test is true, do what's after the question mark (like set flag = 2). If it fails, then do what's after the colon. Only place the ? and : are used in C. switch ------ A switch is like a series of if/else's with few and finite equality tests. switch (statement) { case value1: ............. ............. break; case value2: ............. ............. break; case default: ............. ............. break; } The statement in the switch's parentheses must evaluation to a single value. That value is found in the case list, and when found, it is run. If there is a default, and nothing was found, then the default is run. The break statement is used to stop the code in the case. Without a break statement, the program would get to the end of the code for value1 and immediately drop into the code for value2. This is called fall-through, and is often done on purpose. switch(month) { case 1: printf("January"); break; case 2: printf("February"); break; case 3: printf("March"); break; } Without the break before case 2, when month is == 1, then "JanuaryFebruary" prints. You do NOT want to use switch for ranges, nor for large numbers of possible answers. switch(speed) { case 1: case 2: case 3: case 4: ... case 39: printf("Speed too slow"); break; case 40: case 41: case 65: printf("Speed OK"); break; } and etcetera. This is the only place we'll see switch and case, but break will show itself again later.