CSC 115.005/006 Sonoma State University Spring 2022
Scribbler 2
CSC 115.005/006:
Programming I
Scribbler 2
Instructor: Henry M. Walker

Lecturer, Sonoma State University
Professor Emeritus of Computer Science and Mathematics, Grinnell College


Course Home References Course Details: Syllabus, Schedule, Deadlines, Topic organization MyroC Documentation Project Scope/
Acknowledgments

Notes:

An Introduction to Loops in C

This reading introduces both the concept and the syntax of loops in C.

Introduction

In our programs to this point, we have exerted much effort for frankly rather modest results. Each program contains a sequence of lines, and we execute each line once. Arguably, we expend more work in writing each line than in obtaining a substantial result.

As a example, consider the following simple robot dance step:

   rTurnRight (0.8, 0.6); /* turn right at 80% speed 
                             (max speed is 1.0)
                             for 6/10 seconds */
   rTurnLeft  (0.8, 0.4); /* turn left  at 80% speed 
                             for 4/10 seconds */
   rForward (0.75, 0.8);  /* move forward at 3/4 speed 
                             for 0.8 seconds */
   rBackward (0.5, 1.2);  /* move backward at half speed
                             for 1.2 seconds */

With this activity, the robot turns right, and then turns left part of the way. Next the robot moves forward and backward to approximately the starting position. Together, the robot performs several movements and ends turned a little to the right of where it started.

Since each step requires careful planning of a dance step and four thoughtfully-crafted MyroC commands. Altogether, much fuss for not much motion!

To make this code segment more interesting and more effective for the programmer, it would be nice to tell the program to repeat these movements one or more times. Within computing, the repetition of a collection of steps is often called a loop.

C provides three constructs for specifying loops within programs. Although the first two are functionally equivalent, and the third is similar (with a twist added), each type of loop highlights different components of the creatively programming process. This reading describes each of these types of loops in some detail and presents a typical example of each.

Reading Outline

C provides three basic loop forms:

Two additional capabilities:


General loop basics

Loops typically follow a common overall structure:

The loop itself contains statements that are repeated, either indefinitely or within a prescribed context. As part of this loop processing, some variables may require updating from one iteration of the loop to the next. Also, before the loop, some initialization or set up may be needed in anticipation of what will follow. Similarly, after the loop, some concluding processing may be needed.


for Loops

C's for loop provides one construct for these elements of a loop, highlighting the initialization, updating, and condition. Often, a for loop is used when a variable, sometimes called a loop control variable, is used to keep track of the repetitions within the loop.

As a specific example, consider a program that repeats the above simple robot dance step six times. For this application, the program will need a counter variable that indicates how many times the the simple robot dance step has been performed. The following program robot-dance.c performs this repetitive dance.

C's for loop syntax

C's for loop utilizes the following syntax:

preliminaries

for (variable_initialization; condition; variable_update)
   repeated_loop_body

wrap_up

As indicated in this template, the keyword for is followed by parentheses, and the code within the parentheses is divided into three sections, separated by semi-colons.


/* Program to perform a simple robot dance step six times */

#include <stdio.h>
#include <MyroC.h>

int main ()
{
  printf ("this program repeats a simple robot dance step six times\n");
  rConnect ("/dev/rfcomm0");

  int counter;  // variable to keep track of dance step repetitions

Preliminaries in this program include printing, connecting to the Scribbler 2 robot, and declaring the counter variable.


  /* repeat simple robot dance step six times */
  for (counter = 0; counter < 6; counter++)

In this for loop:


    {
      /* basic robot dance step */
      rTurnRight (0.8, 0.6); /* turn right at 80% speed 
                                (max speed is 1.0)
                                for 6/10 seconds */
      rTurnLeft  (0.8, 0.4); /* turn left  at 80% speed 
                                for 4/10 seconds */
      rForward (0.75, 0.8);  /* move forward at 3/4 speed 
                                for 0.8 seconds */
      rBackward (0.5, 1.2);  /* move backward at half speed
                                for 1.2 seconds */
    }

The loop body should consist of the four elements of the simple robot dance step, and these four statements are grouped together within brackets.


  /* wrap up */
  printf ("dance finished\n");
  rDisconnect ();

  return 0;

}

In this program, the wrap up after the loop involves disconnecting from the robot and printing.


Execution of the for loop will proceed as follows:


while Loops

A while loop highlights the condition that dictates when a loop continues. Any preliminaries and/or initialization occur before the while loop; variable updating is placed within the body of the loop; and any wrap up occurs afterwards.

As an example, consider the program while-obstacle.c that moves a robot forward, a little at a time, until it encounters an obstacle. The basic approach is to check the left and right obstacle sensors. If no obstacles are detected, the robot can move forward a small distance. Then the obstacles are checked again, etc. To add interest to the program, the robot beeps with successively higher notes each time it moves forward.

C's while loop syntax

C's while loop uses this syntax:

preliminaries and/or variable_initialization

while (condition)
   repeated_loop_body

wrap_up

Following this syntax, the keyword while is followed by parentheses that surround the condition.


/* This program moves the Scribbler 2 robot forward until an obstacle
   is detected
*/

#include <stdio.h>
#include <MyroC.h>

int main ()
{
  /* preliminaries */
  printf ("program to move a robot forward until an obstacle is detected.\n");
  rConnect ("/dev/rfcomm0");
  rSetForwardness("scribbler-forward");

  int pitch = 880;  /* the tone for the note A in the middle of a piano */

Preliminaries in this program include printing, connecting to the robot, and initializing a variable. (Unlike a for loop, a while does not include a mechanism to initialize variables, so the initialization is done before the while is specified.)


  /* check if both the left and right obstacle sensors
     show no obstacles */
  /* average sensor results over 3 readings */
  while ((!rGetIRTxt("left", 3)) && (!rGetIRTxt("right", 3)))

The IRTxt sensors return 1 if an obstacle is encountered and 0 otherwise. Since C considers 0 false and any nonzero number as true, the call rGetIRTxt("left", 3) will be considered true if an obstacle is detected. Since the robot should move forward if that condition is false, the code includes ! as the "not" operator.

The two parts of the condition in the while check both the left and right obstacle sensors.


    {
      rForward (0.1, 0.1);  /* move forward at 1/10 speed 
                               for 0.1 seconds */
      rBeep (0.5, pitch);   /* beep for half a second */
      pitch += 20;          /* increase pitch by 20 
                               for next iteration */
    }

The repetition_loop_body include the robot commands (rForward and rBeep) and also updates the pitch variable.


  /* wrap up */
  rDisconnect ();
  printf ("obstacle detected --- stop robot motion\n");

  return 0;
}

After the preliminaries, execution of the while loop proceeds as follows.

The wrap_up after the loop handles administrative tasks (disconnecting from the robot and printing a concluding message).


do ... while Loops

In both the for and while loops, a condition is tested at the top of the loop — before the repetition_loop_body is executed. With this placement of the condition, the loop body may never be executed at all (if the condition is false at the start).

In a do ... while loop, the condition is tested at the end of the loop, not at the beginning. Thus, the loop body will always be executed a first time (possibly initializing variables) before the condition is examined.

As an example, consider a program that reads a frequency and a time for the robot tone generator to beep and then tells the robot to generate the specified tone.

In this application, the frequency might be required to be at least 800 and no more than 4200 cycles per second. Also, the duration of the beep might be limited to a positive number less than 5 seconds.

Since the input is restricted, the program do-while-beep.c reads each value and checks if the user input is within range. If not, the user is asked to re-enter values, until valid values are obtained.

C's do ... while loop syntax

C's while loop uses this syntax:

preliminaries and/or variable_initialization

do {
      repeated_loop_body
} while (condition);

wrap_up

This construct starts with the keyword do and an open bracket {. The repeated_loop_body follows, with an closed bracket }, the keyword while and a condition in parentheses.


/* this program reads a frequency and a time from the terminal
   and generates a beep for the prescribed pitch and time.

   As part of error checking,
      the frequency must be between 800 and 4200, and the user
          is asked to re-enter any value outside this range.
     the time must be positive and less than 5.0, and the user
          is asked to re-enter any time outside this range.
*/

#include <stdio.h>
#include <MyroC.h>

int main ()
{
  /* preliminaries */
  printf ("program to generate a beep for a prescribed frequency and time\n");
  rConnect ("/dev/rfcomm0");

  int freq;
  double time;

Preliminaries include printing an opening message, connecting to the robot, and declaring variables.

No need to read values for freq and time in this section, as the point of the loop is to read appropriate values from the user. Since the loop body is always executed at least once in a do ... while loop, the user will have supplied the required values before proceeding.


  /* first read frequency */
  do {
    printf ("enter a frequency between 800 and 4200, inclusive");
    scanf ("%d", &freq);

    if ((freq < 800) || (freq > 4200))
      {
	printf ("frequency must be between 800 and 4200, try again\n");	
      }
  } while ((freq < 800) || (freq > 4200)) ;

The first do ... while handles reading of frequency, and the loop will continue until the read value is within the required range.

In this code, the purpose of the if statement is to notify the user in case of an error. Without the if, the user would be prompted for another value, but the user might not know why there was a need to enter the value again.

Reminder: In the conditions for the if and do..while statements, recall that C's || operator means "or". See the reading on Boolean expressions for more about conditions with "and" (&&) and "or" (||).


  /* second read time */
  do {
    printf ("enter a positive time less than 5.0");
    scanf ("%lf", &time);

    if ((time < 0) || (freq >= 5.0))
      {
	printf ("time must be between 0.0 and 5.0, try again\n");	
      }
  } while ((time <0.0) || (time >= 5.0)) ;

The second do ... while loop handles reading the time parameter and checks that valid times are entered.


  printf ("frequency and time are read:  here comes the beep!\n");
  rBeep (time, freq);

  /* wrap up */
  rDisconnect ();
  printf ("program completed\n");

  return 0;
}

Once valid numbers are entered for the frequency and duration of the tone, the program can proceed to generate the prescribed beep and finish up.


As illustrated in this example, the do ... while loop can be useful when initialization is needed before a loop condition is first tested. Otherwise, all three loop constructs allow one or more statements to be repeated as long as desired.


Two Additional Capabilities

Typically, within a loop, the expectation is that the computer will move systematically from the start of the loop to the end. However, sometimes it is convenient to jump out the loop or to jump from the middle of a loop to its beginning. C's break and continue statements, respectively, provide these capabilities.


The break Statement

The break statement exits the current loop, so program execution starts with the statement immediately after the current loop. (When one loop is inside another, break jumps out of the innermost loop.)

As an example, consider the first sample program in this reading, in which a simple robot dance step was repeated six times. Now consider what should happen if an obstacle was detected in front of the robot before it moved forward. The robot could still turn right and left, but it could not move forward as desired.

One possibility would be to stop the dance prematurely, after turning right and left, as the robot could not complete the initial rForward command. The following code checks for obstacles and exits the loop if an obstacle is detected:


  /* repeat simple robot dance step six times */
  for (counter = 0; counter < 6; counter++)
    {
      /* basic robot dance step */
      rTurnRight (0.8, 0.6); /* turn right at 80% speed 
                                (max speed is 1.0)
                                for 6/10 seconds */
      rTurnLeft  (0.8, 0.4); /* turn left  at 80% speed 
                                for 4/10 seconds */
      /* check for obstacles before moving forward */
      if ((rGetIRTxt("left", 3)) || (rGetIRTxt("right", 3)))
         {
	    printf ("obstacle detected, exiting dance\n");
	    break;
         }
      rForward (0.75, 0.8);  /* move forward at 3/4 speed 
                                for 0.8 seconds */
      rBackward (0.5, 1.2);  /* move backward at half speed
                                for 1.2 seconds */
    }

The for statement maintains its primary purpose: repeating a simple robot dance step six times. Within this structure, the if statement checks whether the dance can continue without obstacles. If no obstacles are encountered, the dance continues. However, if an obstacle is detected, after the robot turns right and left, the break statement terminates the loop, and the program resumes execution after the for. (In the original program, "dance finished" was printed, and the connection to the robot was terminated.)


The continue statement

Just as the break statement jumps control to what follows the loop, a continue skips the rest of the loop body for the current iteration and moves to the next iteration.


To illustrate the continue statement, consider again the first sample program in this reading, and again consider the possibility that an obstacle might be encountered. In the example for a break, the program execution jumped out of the loop when an obstacle was encountered. As an alternative, the robot might turn right a small amount to begin. If no obstacle is found, the robot might complete its dance step. Otherwise, the remainder of this dance step is omitted, but the robot may continue to turn and try to dance.

A possible coding of this approach follows:


  /* repeat simple robot dance step six times */
  for (counter = 0; counter < 6; counter++)
    {
      /* start a small turn right */
      rTurnRight (0.8, 0.2); /* turn right at 80% speed 
                                (max speed is 1.0)
                                for 2/10 seconds */


      /* check for obstacles before moving forward */
      if ((rGetIRTxt("left", 3)) || (rGetIRTxt("right", 3)))
         {
	    printf ("obstacle detected, skipping the dance this time\n");
	    continue;
         }

      /* The remainder of the robot dance step follows */
      rTurnRight (0.8, 0.4); /* turn right at 80% speed 
                                for 4/10 seconds */
      rTurnLeft  (0.8, 0.4); /* turn left  at 80% speed 
                                for 4/10 seconds */
      rForward (0.75, 0.8);  /* move forward at 3/4 speed 
                                for 0.8 seconds */
      rBackward (0.5, 1.2);  /* move backward at half speed
                                for 1.2 seconds */
    }

The for and initial rTurnRight maintain the overall motion of the robot (slowing turning right 6 times). Further, the last part of the loop performs the remainder of the now-familiar dance step without change. However, if an obstacle is encountered (so the robot cannot move forward in its dance), then this iteration of the dance is omitted, and the loop continues with the next small right turn.


Warning

Although the break statement can be very useful in some contexts, break also can be abused. For some beginning programmers, the appearance of break sometimes means that a loop's condition is misleading. For example, consider the program that moves a robot forward until an obstacle is found.

Conceptually, the while condition highlighted the test for obstacles, so the code clearly indicated the intention to move forward until an obstacle was found. The following code, however, obscures the nature of the loop:


  while (1) /* a misleading condition - not what is intended!!!!!
    {
      if ((rGetIRTxt("left", 3)) || (rGetIRTxt("right", 3)))
         {
	    break;  /* an awkward recovery 
	               from a misguided while condition */
	 }
      rForward (0.1, 0.1);  /* move forward */
      rBeep (0.5, pitch);   /* beep for half a second */
      pitch += 20;          /* increase pitch for next iteration */
    }

In this code,


Suggestion — programming tip

Before using a break statement, look again at the condition in a for or while loop. Often a restructuring of the code provides a simpler and cleaner program without the need for break. (Of course, simpler and cleaner code also is more likely to be correct than code with a convoluted structure!)

Sometimes break can work very well (hence, its inclusion with the C programming language). However, in some cases, break also can cover fuzzy thinking and add to program complex and the introduction of errors.



created 15 July 2016 by Henry M. Walker
revised 24 July 2016 by Henry M. Walker
example for the continue statement added 12 September 2016 by Henry M. Walker
Valid HTML 4.01! Valid CSS!
For more information, please contact Henry M. Walker at walker@cs.grinnell.edu .