(6-2) Iteration in Caofallon/cpts121/lectures/L6-2.pdf · 5 C. Hundhausen, A. O’Fallon...
Transcript of (6-2) Iteration in Caofallon/cpts121/lectures/L6-2.pdf · 5 C. Hundhausen, A. O’Fallon...
(6-2) Iteration in C II H&K Chapter 5
Instructor - Andrew S. O’Fallon
CptS 121 (February 21, 2020)
Washington State University
C. Hundhausen, A. O’Fallon2
Don’t Forget About Flowcharts!
Recall: flowcharts provide visual
representations of algorithms and/or
processes
Excellent tool for verifying logical flow
C. Hundhausen, A. O’Fallon3
General Structure of Flowchart for Loops
Process body
of loop
Condition?
Yes or
T
No or
F
C. Hundhausen, A. O’Fallon4
Conditional Loops (1)
In the previous lecture, we considered loops
whose number of iterations was known at
the time the loop started
In practice, we don’t always know in
advance how many times a loop will
execute!
– Often, the loop body itself determines whether
another execution is necessary
C. Hundhausen, A. O’Fallon5
Conditional Loops (2)
Consider, for example, the following extension to
the Tollbooth application:
– Suppose that, for safety reasons, the tollbooth limits the
number of vehicles that can cross the bridge on a given
day to a certain tonnage.
– Suppose that you want to read in vehicle data from a file
to simulate cars crossing the bridge.
– When the maximum tonnage has been reached, not more
data are read from file.The program prints out a message
reporting
the revenues collected for the day
the number and total weight of all cars that crossed for the
day
– See next slide for a possible solution
C. Hundhausen, A. O’Fallon6
Conditional Loops (3)
#include <stdio.h>
#define MAX_TONS_PER_DAY 20
#define POUNDS_PER_TON 2000
…
void main(void) {
int vehicle_count, axles;
double weight, tons, toll, total_tolls;
FILE *infile;
infile = get_and_open_file();
count = tons = total_tolls = 0;
while (tons < MAX_TONS_PER_DAY) {
axles = read_num_axles(infile);weight = read_weight(infile); toll = compute_toll(axles,weight);count++; /* Another car has crossed. */
tolls += toll; /* Another toll has been collected */
tons += weight/2000.0; /* Add weight of this car */ /* to running total*/
}
printf("%d cars, weighing %.2f tons, crossed the bridge today.",
count, tons);
printf("$%.2f in tolls was collected today.",total_tolls);
}
C. Hundhausen, A. O’Fallon7
Conditional Loops (4)
A possible sequence of questions that can guide loop design,
applied to previous example
Question Answer Implications for
design
1. What are the inputs? Weight of vehicle, #
of axles
Input vars:weight, axles
2. What are the outputs? # and weight of
vehicles that cross
bridge; tolls collected
Output vars: count,
tons,
total_tolls
C. Hundhausen, A. O’Fallon8
Conditional Loops (5)
A possible sequence of questions that can guide loop design,
applied to previous example (cont.)
Question Answer Implications for design
3. Is there repetition? Yes! We repeatedly
Get # axles and
weight
Calculate toll
Add weight to total
weight
Add toll to total tolls
Add 1 to vehicle
count
Program variable needed: MAX_TONS_
PER_DAY
C. Hundhausen, A. O’Fallon9
Conditional Loops (6)
A possible sequence of questions that can guide loop design,
applied to previous example (cont.)
Question Answer Implications for design
4. Do I know in advance
how many steps will be
repeated?
No. Loop will NOT be
controlled by counter
5. How do I know how long
to keep repeating steps?
As long as the total
weight of the vehicles
is below the maximum
The loop repetition
condition is total_tons <
MAX_TONS_
PER_DAY
C. Hundhausen, A. O’Fallon10
Sentinel-Controlled Loops (1)
Often we want to continue looping until a certain
value, called a “sentinel,” is encountered
For example, suppose we change the requirements
of the Tollbooth application slightly:
– There is no maximum on the total weight of the vehicles
that cross the bridge on a given day
– We will read in vehicle data interactively
– The user will tell us that there are no more vehicles for the
day by entering ‘n’ when asked whether there is another
vehicle that needs to cross (‘n’ = “No” the sentinel value)
C. Hundhausen, A. O’Fallon11
Sentinel-Controlled Loops (2)
#include <stdio.h>
#define SENTINEL_VALUE 'n'
#define POUNDS_PER_TON 2000
…
void main(void) {
int count, axles;
char continue;
double weight, tons, toll, total_tolls;
count = tons = total_tolls = 0;
printf("Did at least one car cross the bridge? (y/n) ");
scanf(" %c ",&continue); /* Note blanks absorb whitespace */
while (continue != SENTINEL_VALUE) {
axles = read_num_axles(); /* assume these two functions read */
weight = read_weight(infile); /* prompt user interactively */
toll = compute_toll(axles,weight);
count++; /* Another car has crossed. */
total_tolls += toll; /* Another toll has been collected. */
tons += weight/2000.0; /* Add weight of this car to total*/
printf("Did another car cross the bridge? (y/n) ");
scanf(" %c ",&continue); /* Note blanks absorb whitespace */
}
…
C. Hundhausen, A. O’Fallon12
Sentinel-Controlled Loops (3)
Note that this could also be rewritten as a for loop:…printf("Did at least one car cross the bridge? (y/n) ");
for (scanf(" %c ",&continue);
continue != SENTINEL;
scanf(" %c ",&continue))
{
axles = read_num_axles(); /* assume these two functions read */
weight = read_weight(infile); /* prompt user interactively */
toll = compute_toll(axles,weight);
count++; /* Another car has crossed. */
total_tolls += toll; /* Another toll has been collected. */
tons += weight/2000.0; /* Add weight of this car to total*/
printf("Did another car cross the bridge? (y/n) ");
}
…
C. Hundhausen, A. O’Fallon13
Endfile-Controlled Loops (1)
Often, as in the original toll booth
application, we read input data in from a file
We want to continue processing data until
there is no more data to process
In other words, we want to continue
processing data until the end of the file is
encountered
We can use the endfile-controlled loop
pattern to do this
C. Hundhausen, A. O’Fallon14
Endfile-Controlled Loops (2)
For example, suppose that we change the requirements of the tollbooth application again– We will read the input values from a text file, as
before
– We will continue reading axle/weight pairs until we reach the end of the file
– We will need to redesign two functions we wrote in class a couple of weeks ago: read_num_axles
read_weight
– Let's look at the implementation…
C. Hundhausen, A. O’Fallon15
Endfile-Controlled Loops (3)
fscanf actually returns a value indicating the number of items it successfully reads in
If it encounters the end of the file, it returns as its result the value of the standard constant EOF (which is a negative integer)
We can thus redesign read_num_axles to return EOF if it encounters the end of the file:
int read_num_axles(FILE *infile) {
int num_axles, input_status;
input_status = fscanf(infile,”%d”,&num_axles);
if (input_status != EOF)
return (num_axles);elsereturn input_status;
}
C. Hundhausen, A. O’Fallon16
Endfile-Controlled Loops (4)
For the sake of simplicity, we will assume that data always come in pairs, so we won't check for EOF in read_weight
Challenge question: Do you see another problem with adding EOF-checking to read_weight? Explain.
The next slide puts the solution together
C. Hundhausen, A. O’Fallon17
Endfile-Controlled Loops (5)
#include <stdio.h>
#define POUNDS_PER_TON 2000
…
void main() {
int count, test_axles, axles;
double weight, tons, toll, total_tolls;
FILE *infile;
infile = get_and_open_file();
count = tons = total_tolls = 0;
test_axles = read_num_axles(infile);
while (test_axles != EOF) {
axles = test_axles; /* We can accept this value as valid. */weight = read_weight(infile); /* Assume EOF won't be seen. */toll = compute_toll(axles,weight);count++; /* Another car has crossed. */
total_tolls += toll; /* Another toll has been collected. */
tons += weight/2000.0; /* Add weight of this car to total*/
test_axles = read_num_axles(infile); /* Prepare for next */
/* iteration. */
}
…
}
C. Hundhausen, A. O’Fallon18
Flag-Controlled Loops (1)
In the previous examples, we have assumed that input data are always in the proper format:
– When we ask for the number of axles, we will obtain an integer (either interactively from the user, or from the input file)
– When we ask for the weight, we will obtain a double (either interactively from the user, or from the input file)
In the real world, this assumption is faulty– People enter invalid data all the time
– Files contain invalid data all the time
Flag-controlled loops ensure that valid data are read in
C. Hundhausen, A. O’Fallon19
Flag-Controlled Loops (2)
Recall that the fscanf function returns EOF when the end of the file is encountered
Likewise fscanf and scanf return the value 0 when at least one the data values it reads in could not be converted to the specified type
– For example, assume the following scanf statement
int my_int, input_status;
printf("Please enter an integer: ");
input_status = scanf("%d",&my_int);
If the user were to type in "wow" here, input_statuswould be assigned the value 0, since "wow" cannot be converted to an int
C. Hundhausen, A. O’Fallon20
Flag-Controlled Loops (3)
The final C interative construct, the do-while loop, can be used to trap this situation and re-prompt the user:
int my_int, input_status;
char skip_ch;
do {
printf("Please enter an integer: ");
input_status = scanf("%d",&my_int);
do { /* nested do-while skips rest of data line */
scanf("%c", skip_ch);
} while (skip_ch != '\n');
} while (input_status == 0);
Notice that, unlike the while and for loop constructs, the do-while loop construct is guaranteed to execute at least once.
C. Hundhausen, A. O’Fallon21
Flag-Controlled Loops (4)
You try it: Given this pattern, tailor interactive versions of read_num_axles so that they only accept valid input (an intor a double) from the user (work with a partner for 5 minutes)
int read_num_axles() {
int num_axles, input_status;
/* your code goes here */
}
double read_weight() {
double weight;
int input_status;
/* your code goes here */
}
C. Hundhausen, A. O’Fallon22
Flag-Controlled Loops (5)
Now let's go one step further. Let's do a reality check on each input value to make sure it's not only of the correct type, but within an acceptable range:
– Num_axles should be between 2 and 5 (no unicycles allowed!)
int read_num_axles() {
int num_axles, input_status, input_ok;
char skip_ch;
do {
printf("Please enter the number of axles: ");
input_status = scanf("%d",&num_axles);
input_ok = (input_status != 0 && num_axles > 1 &&
num_axles < 6); /* status flag */
if (!input_ok)
printf("The value you entered is invalid.");
do { /* skip rest of data line */
scanf("%c", &skip_ch);
} while (skip_ch != '\n');
} while (!input_ok);
return num_axles;
}
C. Hundhausen, A. O’Fallon23
Flag-Controlled Loops (6)
Now let's go one step further (cont.).– Weight should be between 200.0 and 4000.0
double read_weight() {
int input_status, input_ok;
char skip_ch;
double weight;
do {
printf("Please enter the vehicle weight: ");
input_status = scanf("%lf",&weight);
input_ok = (input_status != 0 &&
weight >= 200.0 &&
weight <= 4000.0);
if (!input_ok)
printf("The value you entered is invalid.");
do { /* skip rest of data line */
scanf("%c", &skip_ch);
} while (skip_ch != '\n');} while (!input_ok);
return weight;
}
C. Hundhausen, A. O’Fallon24
References
J.R. Hanly & E.B. Koffman, Problem Solving
and Program Design in C (8th Ed.), Addison-
Wesley, 2016
P.J. Deitel & H.M. Deitel, C How to Program
(7th Ed.), Pearson Education , Inc., 2013.