760 likes | 774 Views
This lecture discusses program control in detail, including decision control, nested if-else structures, switch control structure, repetition control, and the role of functions in top-down design.
E N D
Program Control - Details 60-140 Lecture 3 Dr. Robert D. Kent
Lecture 3: Outline • Program control • Generalities versus details • Decision control • Nested if-else control structures • The switch control structure • Repetition control • Nested while and do-while control structures • The for control structure • The role of functions in Top-Down design • Impact on formulation of well-defined control structures
3A : Program control Generalities versus Details
Generalities versus Details • Previously, we introduced the basic C control structures • Decision (Selection) • if if-else switch • Repetition • while do-while for • We shall now take another look, in more detail • Usage and patterns • Flexibility
Generalities versus Details • Usage and patterns • How are the control structures used in simple, versus complicated, programming circumstances? • What patterns emerge often? • These can be re-used • Flexibility • How flexible is the syntax and grammar of the control structures? • Efficiency versus Clarity
3B. Decision Control Nested if-else and Switch
3b: Outline • Review • Nested if-else control structures • The switch control structure
Review • We have introduced the structured control mechanisms for decision and selection • Decision: • if ( condition ) Statement ; • Either – perform the Statement (simple or compound) or NOT ! • Straightforward in most cases
Review • If Statement is compound, use braces and indentation • if ( condition ) { Statement1 ; ......StatementN ; } • Indentation improves the readability (hence, understanding) of the code for humans.
Review • Selection: • if ( condition )T_statement ; /* do when cond is True */ elseF_statement ; /* do when cond is False */ • Once again, if using compound statements, or if placing a simple statement on a following line, use indentation to improve code readability. • This is an either-or situation – perform EITHER the True clause OR the False clause, but not both! Many styles exist – use one style consistently in program code. If ( condition ) { T_stmts ; } else { F_stmts ; }
Review • Simple Selection: • ( condition ) ? T_statement : F_statement • This simple selection structure uses the ternary operator ?: • This form may be used as a single control structure/statement • It is most often incorporated into another statement (eg. printf) as a component (nested) sub-structure. • If Value is 60, output is: Answer is A printf( “Answer is %c\n”, (Value > 50) ? ‘A’ : ‘B’ ) ;
Multiple selection – A simple sort • Problem: • Enter three integer values and output them in the order from largest to smallest • All values inputted are distinct • Note – there are six (6) separate cases to account for • This is called sorting • Later we will discuss this for an arbitrary number of values
Multiple selection – A simple sort CPU instructions are binary for relational comparisons and logic operations. Thus, an expression like: A > B && B > C requires three (3) separate operations, namely: Temp1 = A>B Temp2 = B>C Exprvalue = Temp1 && Temp2 • Solution: • int A, B, C ;scanf( “%d%d%d”, &A, &B, &C ) ; • if ( A > B && B > C ) printf( “%d %d %d\n”, A, B, C ) ; if ( A > C && C > B ) printf( “%d %d %d\n”, A, C, B ) ; if ( B > A && A > C ) printf( “%d %d %d\n”, B, A, C ) ; if ( B > C && C > A ) printf( “%d %d %d\n”, B, C, A ) ; if ( C > A && A > B ) printf( “%d %d %d\n”, C, A, B ) ; if ( C > B && B > A ) printf( “%d %d %d\n”, C, B, A ) ; • Note the number of distinct operations • Can this be improved upon (made more efficient)? 3 x 6 = 18
Multiple selection – A simple sort • Improved Solution: • if ( A > B ) if ( B > C ) printf( “%d %d %d\n”, A, B, C ) ; else if ( A > C ) printf( “%d %d %d\n”, A, C, B ) ; else printf( “%d %d %d\n”, C, A, B ) ; else if ( A > C ) printf( “%d %d %d\n”, B, A, C ) ; else if ( B > C ) printf( “%d %d %d\n”, B, C, A ) ; else printf( “%d %d %d\n”, C, B, A ) ; • Note the number of distinct operations • Can this be improved upon (made more efficient)?NO ! A minimum of 2 – a maximum of 3! Divide and Conquer (binary subdivision) strategy.
Multiple selection • Multiple selection logic arises when a choice between more than two possible outcomes may happen • C provides two control structures to deal with these situations • if-else (with nesting) • switch
Multiple selection • Problem: • Part of a calculator program requires the user to input a value from 1 to 4 indicating his/her choice of the operation to perform on two values A and B (assume A, B already entered) • RESULT: C = A operation B ; • The interpretation of the inputs is defined as • 1 - Add • 2 - Subtract • 3 - Multiply • 4 - Divide
Multiple selection : if-else • Solution using if-else : • printf ( “Enter operation code >” ) ;scanf ( “%d”, &Code ) ; if ( Code == 1 ) C = A + B ; else if ( Code == 2 ) C = A – B ; else if ( Code == 3 ) C = A * B ; else C = A / B ;
Multiple selection : switch • Solution using switch : • printf ( “Enter operation code >” ) ;scanf ( “%d”, &Code ) ; switch ( Code ) { case 1 : C = A + B ; break ; case 2 : C = A – B ; break ; case 3 : C = A * B ; break ; case 4 : C = A / B ; break ; default : printf ( “Error in input\n” ) ; break ; }
Multiple selection : switch • Problem: • Count the number of times that the ‘A’ (or ‘a’) or ‘B’ (or ‘b’) key is pressed, and all remaining alphabetic character keystrokes. • Solution considerations: • Need counters for A-keystrokes, B-keystrokes and all other alphabetic keystrokes. • Must ignore non-alphabetic keystrokes such as digits and punctuation and control signals (eg. ‘\n’) • We must differentiate between the alphabetic characters that are not (‘a’, ‘A’, ‘b’, ‘B’), but which must be counted, and the non-alphabetic keystrokes that are not counted Recall that the ASCII character code treats the lower case and upper case alphabetic character sequences as ordinal sequences: ‘a’ < ‘b’ < ... < ‘z’ ‘A’ < ‘B’ < ... < ‘Z’
Multiple selection : switch • intAcnt = 0, Bcnt = 0, Alphacnt = 0 ; char Ch ; • switch( Ch = getchar() ) { case ‘a’ : /* lower case */ case ‘A’ : /* upper case */Acnt++ ; break ; case ‘b’ : /* lower case */ case ‘B’ : /* upper case */Bcnt++ ; break ; default : if ( (Ch > ‘b’ && Ch <= ‘z’) || (Ch > ‘B’ && Ch <= ‘Z’) ) Alphacnt++ ; break ; }
Multiple selection : switch getchar() is a function from <stdio.h> that obtains one character from stdin. In this scenario, the character inputted is assigned to Ch variable. The value of the condition is the same as the value of Ch. • intAcnt = 0, Bcnt = 0, Alphacnt = 0 ; char Ch ; • switch( Ch = getchar() ) { case ‘a’ : /* lower case */ case ‘A’ : /* upper case */Acnt++ ; break ; case ‘b’ : /* lower case */ case ‘B’ : /* upper case */Bcnt++ ; break ; default : if ( (Ch > ‘b’ && Ch <= ‘z’) || (Ch > ‘B’ && Ch <= ‘Z’) ) Alphacnt++ ; break ;}
Multiple selection : switch • intAcnt = 0, Bcnt = 0, Alphacnt = 0 ; char Ch ; • switch( Ch = getchar() ) { case ‘a’ : /* lower case */ case ‘A’ : /* upper case */Acnt++ ;break ; case ‘b’ : /* lower case */ case ‘B’ : /* upper case */Bcnt++ ;break ; default : if ( (Ch > ‘b’ && Ch <= ‘z’) || (Ch > ‘B’ && Ch <= ‘Z’) ) Alphacnt++ ;break ;} Use of break implies that the switch must be immediately exited.
Multiple selection : switch • intAcnt = 0, Bcnt = 0, Alphacnt = 0 ; char Ch ; • switch( Ch = getchar() ) {case ‘a’ : /* lower case */ case ‘A’ : /* upper case */Acnt++ ; break ; case ‘b’ : /* lower case */ case ‘B’ : /* upper case */Bcnt++ ; break ; default : if ( (Ch > ‘b’ && Ch <= ‘z’) || (Ch > ‘B’ && Ch <= ‘Z’) ) Alphacnt++ ; break ; } Logic Patterns! - reused
Multiple selection : switch In this case, if Ch is assigned ‘a’, the first case ‘a’ is compared and found to match, but since there is no specific statement to execute, the processing logic advances to the next case clause (‘A’) and performs the statement: Acnt++ ; • intAcnt = 0, Bcnt = 0, Alphacnt = 0 ; char Ch ; • switch( Ch = getchar() ) {case ‘a’ : /* lower case */ case ‘A’ : /* upper case */Acnt++ ; break ; case ‘b’ : /* lower case */ case ‘B’ : /* upper case */Bcnt++ ; break ; default : if ( (Ch > ‘b’ && Ch <= ‘z’) || (Ch > ‘B’ && Ch <= ‘Z’) ) Alphacnt++ ; break ; } Note that break is not required for each case clause. Lack of a break implies that the next casemust be processed.
Multiple selection : switch Recall that the ASCII character code treats the lower case and upper case alphabetic character sequences as ordinal sequences: ‘a’ < ‘b’ < ... < ‘z’ ‘A’ < ‘B’ < ... < ‘Z’ If Ch is alphabetic and not ‘a’, ‘b’, ‘A’ or ‘B’, then it must lie within one OR the other range of characters. • intAcnt = 0, Bcnt = 0, Alphacnt = 0 ; char Ch ; • switch( Ch = getchar() ) { case ‘a’ : /* lower case */ case ‘A’ : /* upper case */Acnt++ ; break ; case ‘b’ : /* lower case */ case ‘B’ : /* upper case */Bcnt++ ; break ;default : if ( (Ch > ‘b’ && Ch <= ‘z’) || (Ch > ‘B’ && Ch <= ‘Z’) ) Alphacnt++ ; break ; } The default clause is used to handle all other cases that are not explicitly coded. It is possible that this clause may involve complicated logic and processing steps.
Multiple selection : switch • It is possible to nest multiple statements and control structures within each case clause of the switch structure • Usually this leads to coding that is difficult to understand • Typically, it is advised to keep the logic of each case clause relatively simple and direct • Later, we will see that complicated logic is best encapsulated within C functions (library or user-defined) and these functions can be called (referenced/invoked) within the case clauses.
3C. Repetition Control While, Do-while and For
3c: Outline • Review • Nested while and do-while control structures • The for control structure
3c. Repetition • Repetition logic may be of two forms • Pre-condition testing : enter, or re-enter, the loop body if the condition is true. • Post-condition testing : enter the loop body in all cases (performing the body a minimum of once), then repeat the loop body only if the condition is true. • C supports three forms of repetition control structures • while • do-while • for
Repetition : while • while ( condition_expression ) statement ; • while ( condition_expression ) { statement1 ; ......statementN ; } FALSE cond TRUE process
Repetition : do-while • do statement ; while ( condition_expression ) ; • do { statement1 ; ......statementN ; } while ( condition_expression ) ; • MUST execute the body (process) at least once! process TRUE cond FALSE
Repetition : Nesting • Consider a do-while that contains another do-while structure: Nested do-while loop. process TRUE TRUE cond cond FALSE FALSE
Repetition : Nesting Start Process_1 • Nesting of control structures within other control structures occurs quite often in programming • Loop structures require care in order to ensure that all control conditions are properly established • Always remember to check that any statements that must be performed outside the formal control structure (eg. initializations) are strongly coupled to the structure. • Inner loop structures may reference variables that are controlled by outer loop structures. In such cases special attention must be paid to the interface between the structures. Process_k InterfaceLogic_k Process_k+1 Stop
Repetition : Nesting 1.0 4.3 -1 5.63 7.532 6.1 8.3 -3.14159 975.64 478.5 24.6789 -53.5 -1.0 1.0 4.3 -1 5.63 7.532 6.1 8.3 -3.14159 975.64 478.5 24.6789 -53.5 -1.0 • Problem: Find the averageof the averages of lists of non-negative real numbers. • Each sublist will be terminated by a negative value • Each sublist must contain at least one non-negative value, except the last (final) sublist • The last sublist will consist only of the delimiter sentinel negative number. This allows for the scenario where a user starts the program and then decides not to enter any values – they must enter a negative number, however.
Repetition : Nesting 1.0 4.3 -1 5.63 7.532 6.1 8.3 -3.14159 975.64 478.5 24.6789 -53.5 -1.0 • Problem: Find the averageof the averages of lists of non-negative real numbers. • Variables: • intNumLists, Num ; float Value, Ave, Sum, AveSum, AveAve ; • Initializations: • Start of Program: Within Program: • NumLists = 0 ; Num = 0 ;AveSum = 0.0 ; Sum = 0.0 ;
Repetition : Nesting 1.0 4.3 -1 5.63 7.532 6.1 8.3 -3.14159 975.64 478.5 24.6789 -53.5 -1.0 • Average of a sub-list terminated by negative sentinel: • Num = 0 ; Sum = 0.0 ;do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ;if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; }} while ( Value >= 0 ) ; if ( Num > 0 ) Ave = Sum / Num ;
Repetition : Nesting • Average of a sub-list terminated by negative sentinel: • Num = 0 ; Sum = 0.0 ; do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ; if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; } } while ( Value >= 0 ) ; if ( Num > 0 ) Ave = Sum / Num ; • Treat this code as a unit (module).
1.0 4.3 -1 5.63 7.532 6.1 8.3 -3.14159 975.64 478.5 24.6789 -53.5 -1.0 Repetition : Nesting • Average of sub-list averages (terminated by negative sentinel): • NumLists = 0 ;AveSum = 0.0 ;do {/* Input sublist and find its average */if ( Num > 0 ) {AveSum = AveSum + Ave ;NumLists++ ; }} while ( Num > 0 ) ; if ( NumLists > 0 ) AveAve = AveSum / NumLists ;printf ( “Average of averages = %f\n”, AveAve ) ;
Repetition : Nesting NumLists = 0 ;AveSum = 0.0 ;do {/* Input sublist and find its average */ Num = 0 ; Sum = 0.0 ; do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ; if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; } } while ( Value >= 0 ) ; if ( Num > 0 ) Ave = Sum / Num ; if ( Num > 0 ) {AveSum = AveSum + Ave ;NumLists++ ; }} while ( Num > 0 ) ; if ( NumLists > 0 ) AveAve = AveSum / NumLists ;printf ( “Average of averages = %f\n”, AveAve ) ; • Merge codes together: • NumLists = 0 ;AveSum = 0.0 ;do {/* Input sublist and find its average */ Num = 0 ; Sum = 0.0 ; do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ; if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; } } while ( Value >= 0 ) ; if ( Num > 0 ) Ave = Sum / Num ; if ( Num > 0 ) {AveSum = AveSum + Ave ;NumLists++ ; }} while ( Num > 0 ) ; if ( NumLists > 0 ) AveAve = AveSum / NumLists ;printf ( “Average of averages = %f\n”, AveAve ) ; To complete the program, place the code into main and add necessary #include and documentation.
Repetition : Nesting NumLists = 0 ;AveSum = 0.0 ; do { /* Input sublist and find its average */ Num = 0 ; Sum = 0.0 ; do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ; if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; } } while ( Value >= 0 ) ;if ( Num > 0 ) Ave = Sum / Num ; if ( Num > 0 ) {AveSum = AveSum + Ave ;NumLists++ ; } } while ( Num > 0 ) ; if ( NumLists > 0 ) AveAve = AveSum / NumLists ;printf ( “Average of averages = %f\n”, AveAve ) ; It may be useful to examine the code to clean up any obvious inefficiences.
Repetition : Nesting NumLists = 0 ;AveSum = 0.0 ; do { /* Input sublist and find its average */ Num = 0 ; Sum = 0.0 ; do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ; if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; } } while ( Value >= 0 ) ; if ( Num > 0 ) { Ave = Sum / Num ; AveSum = AveSum + Ave ;NumLists++ ; } } while ( Num > 0 ) ; if ( NumLists > 0 ) AveAve = AveSum / NumLists ;printf ( “Average of averages = %f\n”, AveAve ) ; It may be useful to examine the code to clean up any obvious inefficiences.
Repetition : Nesting NumLists = 0 ;AveSum = 0.0 ; do { /* Input sublist and find its average */ Num = 0 ; Sum = 0.0 ; do {printf( “Enter a number (<0 to quit) : ” ;scanf( “%f”, &Value ) ; if ( Value >= 0 ) { Sum = Sum + Value ; Num++ ; } } while ( Value >= 0 ) ; if ( Num > 0 ) { AveSum += Sum / Num ;NumLists++ ; } } while ( Num > 0 ) ; if ( NumLists > 0 ) AveAve = AveSum / NumLists ;printf ( “Average of averages = %f\n”, AveAve ) ; It may be useful to examine the code to clean up any obvious inefficiences.
Repetition : Nesting • Be systematic • Top-Down • Bottom-Up • Stepwise Refinement • Test your algorithms and codings • Use simple tests first, then add complexity • Make sure special cases are treated • Clean up code once you have the basic idea working.
Repetition : for • for ( init_stmt ; cond_expr ; update_stmt ) statement ; • for ( init_stmt ; cond_expr ; update_stmt ) { statement1 ; ......statementN ; } INITIALIZE COND UPDATE F T PROCESS
Repetition : for • Example: Find the sum of all integers from 1 to 10. • int Sum = 0, k ; for ( k = 1 ; k <= 10 ; k++ ) Sum = Sum + k ;
Repetition : for • Example: Find the sum of all integers from 1 to 10. • int Sum, k ; for ( k = 1, Sum = 0 ; k <= 10 ; k++ ) Sum = Sum + k ; • This form has the advantage that it localizes the initialization of Sum to the actual location of the for structure • Otherwise, the programmer might forget to do this if the for is repeated within the program
Repetition : for • Example: Find the sum of all odd integers from 1 to 10. • int Sum, k ; for ( k = 1, Sum = 0 ; k <= 10 ; k += 2 ) Sum = Sum + k ;
Repetition : for • Example: Find the sum of all odd integers from 1 to 10. • int Sum, k ;/* OR, recognizing that (2k-1) is always odd */ for ( k = 1, Sum = 0 ; k <= 5 ; k++) Sum = Sum + k + k - 1 ;
Repetition : for • Simplified syntax: • for ( Slot1 ; Slot2 ; Slot3 ) Stmt ; • Each Slot may contain an executable expression or assignment expression • Each Slot may be empty • Use with careful planning and make sure you know what you are doing • The Stmt is optional • There may be no Stmt, but the semi-colon is mandatory!
Repetition : for • Complex syntax: • for ( init_list ; cond ; update_list ) ..... • for ( init_list ; init_cond ; update_list ) .....