CPS202 Week 7 Chapter 6 Loops Review MiniQuiz --------------- Review Quiz 2 ------------- Loops There are three main types of loops in C: while do/while for Before we talk about these loops, let's discuss briefly what a loop is. A loop is a bit of code that you want to be able to run more than once. By having a loop, you can return to the top of the bit of code and execute all the lines until you hit the bottom, and then either start again, or stop. A loop might be used to validate input or to count items. We will go over many nice uses for loops today. While ----- First, we'll tackle the while loop, since it is arguably the simplest. The while loop is a loop that executes 0 or more times - meaning that depending on the loop, it may not execute at all. while (test) { body } The test is any conditional, just like in an if statement. As long as the condition evaluates to true, the loop will continue to run. As soon as the condition is false, the loop stops and control moves to the line of code immediately following the loop. i = 0; while (i < 10) { printf("i is %d\n",i); i++; } In this loop, we initialize i to 0, and test it to see if it is less than 10. It is, so we enter the body of the loop and print the value of i. Then we increment i by one, and return to the test. 1 is less than 10, so we do it again, and keep doing it until i is 9. Then we bump up i to 10, and 10 is no longer less than 10, so the loop stops. This loop prints: 0 1 2 3 4 5 6 7 8 9 Note that indents are used to separate the body of the loop from the while keyword itself and the surrounding code. This indentation can be critical to the proper understanding of any loop. while(1) ... this is a special loop, known as an infinite loop. It will never end based on the condition, because the condition is always true. We use this kind of loop to do something an unknown number of times, or if the conditions to break out of the loop are extensive. Break out of any loop with the break keyword: while(1) { printf("Enter a vote count: "); scanf("%d",&votes); if (votes < 0) { printf(" * Cannot have negative votes!\n"); } else break; } This is an input validation loop. When the problem in our homework or quizzes lend themselves to input validation, I will expect it to be used. Note that like in an if statement, if only one statement makes up the body, then the curly braces are optional. do/while -------- The do/while is the loop that I personally use the least. It runs one or more times, but always at least the one time. This is because the test is done at the end of the loop instead of at the beginning. do { body } while(test); This loop combines the two keywords, do and while. The program starts at the top, executing the lines of code in the body. Then the while is hit, and the test is done. If the test evaluates to true, then the program loops all the way back to the do, and does the body again. When the test finally evaluates to false, the loop stops. Let's look at the first while loop converted into a do/while: i = 0; do { printf("i is %d\n",i); i++; } while (i < 10); This one starts with 0 again, and prints it, then bumps 0 to 1, and so on. It gets to 9, prints it, bumps 9 to 10, tests it, and finally the test fails. Here, the result is the same - a list of numbers from 0 to 9. Our validation loop might work better with a do/while: do { printf("Enter a vote count: "); scanf("%d",&votes); if (votes < 0) { printf(" * Cannot have negative votes!\n"); } } while(votes < 0); Here, there is no need for the break, because the while takes care of stopping the loop. I don't like this method, because I don't like do/while loops. Of course, that is all a matter of personal preference. The curly braces can be left off a one-statement body, but that can look funny: i = 10; do printf("%d\n",i--); while (i > 0); Here, since the while is not visually connected to the do with curly braces, it might get misinterpreted by a reader. for --- The for loop combines three common parts of many loops: initialization, test, and change. The while and do/while loops only have the test built in. for (a ; b ; c) { body } a is the initialization. It is executed only once, the first time into the loop. b is the test. It is executed every time through the loop, including the first time. If the test evaluates to true, the body of the loop is executed. If not, control passes to the next line following the loop. The change is executed every time the loop completes and before the next run though the loop. for (i=0; i<10; i++) printf("i is %d\n",i); The pattern is: init, test, body. Change, test, body. Change, test, body. In the case above, i is initialized to 0, and then i is compared to 10. If i is less than 10, the body is executed, and 0 is printed. Then i is incremented, and 1 is compared to 10, and so on. Finally, 9 is printed, i is change to 10, and the test fails. Any part of the for loop can be left out - there may be multiple installations or changes that you wish to do elsewhere: for ( ; i<10; i++) // i is initialized elsewhere for (i=0; i<10; ) // i is updated elsewhere You can combine multiple parts using the comma operator: for (i=j=0; i<10; i++) for (i=0, j=1; i<10; i++) for (i=0; i<10; i++, j++) If you leave out all parts, then you get an infinite loop: for (;;) { body } Of course, the curly braces are optional with one-statement bodies. To go backwards through a loop: for (i=10; i>=0; i--) Be careful of the so-called fence-post error, which you get when you include too many iterations in the loop: for (i=0; i<=10; i++) // Do you really want <= ? Also known as an off-by-one error. break ----- We've already seen the break keyword in use in a loop - yes, it is the same break keyword as we saw with the switch statement. One important thing to remember: you can nest one loop inside another. When you do, the break works for the innermost loop only. for (i=0; i<10; i++) { for (j=0; j<10; j++) { if (i == 5) break; // Only breaks out of the "j" loop } } continue -------- In addition to ending the loop early, you can also restart it early, with the continue keyword. while(1) { printf("Enter a number from 0 to 100: "); scanf("%d",&num); if (num < 0 || num > 100) { printf("* Invalid number\n"); continue; } total+=num; } When using break with switch in a loop, you have to be very conscious of where the keyword "belongs": printf("Enter your choice: "); flag = 0; while(1) { scanf("%d",&choice); switch(choice) { case 1: doMenu1(); flag = 1; break; case 2: doMenu2(); flag = 1; break; case 3: doMenu3(); flag = 1; break; case 4: doMenu4(); flag = 1; break; default: printf("* Please enter a number between 1 and 4\n"); continue; } if (flag == 1) break; } In the above example, the continue keyword is not a part of the switch, so it can be used directly in the switch to restart the while loop. However, since the break keyword is a part of the switch, we have to use a flag variable to indicate that a proper choice was made so that we can exit the loop at the end. goto ---- The goto keyword, along with the concept of "Labels" allows the programmer to tell the program execution to jump to almost any point within a program. To use the goto: goto LABEL; Labels are typically typed in upper case, and often are completely unindented, to make them stand out in the code. Neither upper casing nor unindenting, however, are required: goto READ; goto write; When placing a label, it is done by typing the label name, followed by a colon: READ: write: Using gotos, you can simulate any loop, while at the same time, making it harder to read. i = 0; TOP: if (i < 10) goto END; printf("%d\n",i); i++; goto TOP; END: This is the same as our while loop, but using gotos and labels. The best use for gotos is to exit out of highly nested loops: for (i=0; i<10; i++) { for (j=0; j<10; j++) { for (k=0; k<10; k++) { if (i == 5) goto END; } } } END: Overuse of gotos and labels can lead to what is called "spaghetti code." This is because if you printed the code out on paper and connected the gotos and the labels with a pencil, the end result would likely look like a plate of spaghetti. The term is used derisively - the use of gotos is frowned upon in many situations, and I have seen coding standards that forbid it unless there is a good explanation for their use. The Null statement ------------------ One good source of bugs is the Null statement, or a statement that does nothing: for (i=0; i<10; i++); printf("i is %d\n",i); Prints "i is 10" and that is all. Why? Because of the ; at the end of the for loop. That is an instance of the Null statement. while(1); // <-- bad for (i=0; i<1000000; i++); // <-- timer?? Usually they are not used on purpose, so watch out for them. if (i == 0); else printf("i is not 0\n"); Best to explain in comments if they are used.