5.1
Here's one answer, there are many others.
const int SENTINEL = 0;
int count = 0;
int num;
int numNeg = 0;
int numPos = 0;
cin >> num;
while(num != SENTINEL)
{
if (num > 0)
{
numPos += 1;
}
else
{
numNeg += 1;
}
count += 1;
cin >> num;
}
cout << "number of positive #'s = " << numPos << endl;
cout << "number of negative #'s = " << numNeg << endl;
5.2
Most systems will indicate 7 words have been read. The words are "This", "is", "the", "start," , "this", "is", "the".
5.3
const int FEET_PER_MILE = 5280; const int OUNCES_PER_LB = 16; const double E = 2.718; const double GRAMS_PER_POUND = 453.59; const double FT_LBS_PER_ERG = 1.356e7;
5.4
Giving word a value means the loop test will be
true the first time it is checked, so the loop body will execute.
This means an extraction cin >> ... statement is
needed, then a check to see that the word extracted isn't the
sentinel word.
word = "dummy";
while (word != LAST_WORD)
{
cin >> word;
if (word != LAST_WORD)
{
numWords += 1;
}
}
5.5
Here's one solution:
const String LAST_WORD = "end";
const String LAST_WORD_II = "finish";
int numWords = 0;
String word = "dummy";
while (word != LAST_WORD && word != LAST_WORD_II)
{
cin >> word;
if (word != LAST_WORD && word != LAST_WORD_II)
{
numWords += 1;
}
}
Note that && is used, not the or operator ||
. This can be confusing, but numWords should
be incremented when the word just entered is neither of the sentinel
values. As long the word is NOT "end" and is NOT "finish", the count is
incremented.
5.6
Dos-machines and Unix machines support I/O redirection. Program 5.2 can be used on all machines that have C++ compilers. However, specifying a path to the directory containing data files may be more difficult on some machines than others. You may have a version of Program 5.4 (countw2.cc) that uses a "file-window" that allows you to navigate the file-system looking for files. There are 25,758 words in Romeo and Juliet
5.7
To modify Program 5.6 (numbers.cc) to read floating point numbers requires that the variables total and number be changed to type double. No other changes are necessary.
5.8
The statement
cout << "average = " << (double) total/numNums << endl;
WILL cause a floating point value to be printed. This more C-style
cast of (double)
has higher precedence than the division operator / so is interprted
as ( (double) total) / numNums yielding the correct
result.
Using the more C++-style cast below will NOT cause the correct
value to be printed.
cout << "average = " << double(total/numNums) << endl;
Here the entire int expression total/numNums is cast to a double. The
expression is evaluated first, then cast to a double. The int division
loses information before the cast is executed.
5.9
The cast
int value = int(sqrt(25.3));
will properly cast the result of the sqrt function (accessible via math.h) so
that compilers won't issue a warning.
5.10
The following program will work:
#include5.11#include main() { cout << "largest int value = " << INT_MAX << endl; cout << "smallest int value = " << INT_MIN << endl; }
In Program 5.7 (mindata.cc) changes needed to find the largest value read are:
In Program 5.8 (mindata2.cc) the variable name must also change as must the message printed. In addition, the if statement inside the while loop should be
while(cin >> number)
{
numNums += 1;
if (number > maximum)
{
maximum = number;
}
}
5.12
Here's one program.
#include// compute sum of all odd and of all even numbers entered main() { const int SENTINEL = 0; int num; int evenTotal = 0; int oddTotal = 0; int numOdd = 0; int numEven = 0; cin >> num; while (num != SENTINEL) { if (num % 2 == 0) // even number, update stats { numEven += 1; evenTotal += num; } else { numOdd += 1; oddTotal += num; } cin >> num; } cout << "average of even numbers = " << double(evenTotal)/numEven << endl; cout << "average of odd numbers = " << double(oddTotal)/numOdd << endl; }
5.13
To modify either Programs 5.2 or 5.3 to calculate the average word length in of the words processed requires adding a variable numLetters and a statement in the while loop to accumulate the total of all the letters.
int numLetters = 0;
while (infile >> word)
{
numWords += 1;
numLetters += word.length();
}
cout << "average word length = " << double(numLetters)/numWords << endl;
void ReadNums(int & numNums, int & total)
// postcondition: returns number of numbers read (numNums)
// and total of all numbers read (total)
The body of the function is the prompt and loop from Program 5.6. If only the average is to be calculated, the function header would be
void ReadNums(double & average)
Alternatively, the value could be returned by the function, with no parameters passed into the function:
double ReadNums()
5.15
void GetName(String & first, String & last)
// postcondition: return first/last names entered by user
{
cout << "enter first name: ";
cin >> first;
cout << "enter last name: ";
cin >> last;
}
It's possible to do all input on one line:
cout << "enter first and last name (with space between): ";
cin >> first >> last;
5.16
If FingerPrint calculates the average of all word lengths in addition to
the other statistics, a variable numLetters needs to defined and
initialized to zero.
int numLetters = 0;
In the loop of the function, the statement
numLetters += word.Length();
can be used to update the number of letters read for each word. After the loop, the statement:
average = double(numLetters)/(small + medium + large);
would be added. The header of the function requires that a double parameter 'average' be added:
void
FingerPrint(String filename, int & small, int & medium, int & large,
double & average)
5.17
The function below sets roots to infinity (a value set by
calling a function from math.h) if the roots are NOT real.
void
Roots(double a, double b, double c, double & root1, double & root2)
// precondition: a,b,c coefficients of ax^2 + bx + c
// postcondition: sets root1 and root2 to roots of quadratic
// exception: if roots are imaginary, set to infinity
{
double discriminant = b*b - 4*a*c;
if (discriminant < 0)
{
root1 = root2 = infinity(); // from math.h
}
else // get both roots
{
double base = sqrt(discriminant);
root1 = (-b + base)/(2*a);
root2 = (-b - base)/(2*a);
}
}
5.18
The values printed are 3 and 4.5. Because a function cannot modify
value parameters, it doesn't matter what the function
Mystery does to
its parameters. This assumes that as shown in the code fragment in the
book num and top are NOT global variables (don't worry if you don't know
what global variables are).
5.19
The memory location associated with the variable num in main is
referred to by the identifiers first AND second
in the function Change (see diagram below). Thus the statement
first += 2;
references the memory diagrammed below (defined for num in main)
and changes the value there to 10 (8 + 2).
The statement
second *= 2;
references the same memory and multiplies 10*2 to get 20, storing
the value in the only memory location shown, yielding 20.
void Change(int & first, int & second)
{ | /
first += 2; | /
second *= 2; | /
} | /
| /
main() | /
{ +-----+
int num = 8; | |
+-----+
Change(num,num);
cout << num << endl;
}
5.20
void ExtremeWords(String & firstAlph, String & lastAlph)
// postcondition: firstAlph = alphabetically first word read
// lastAlph = alphabetically last word read
{
// fence-post, first word read stored
string word;
if (cin >> word)
{
firstAlph = lastAlph = word;
}
// read other words
while (cin >> word)
{
if (word < firstAlph)
{
firstAlph = word;
}
else if (lastAlph < word)
{
lastAlph = word;
}
}
}
5.21
void Swap(int & a, in t& b)
// postcondition: inerchange values of a and b
{
int temp = a; // need temporary storage
a = b;
b = temp;
}
string response;
do{
cout << "enter response: ";
cin >> response;
if ("deposit" == response)
{
DoDeposit();
}
else if ("withdraw" == response)
{
DoWithdraw();
}
else if ("information" == response)
{
DoAccountInformation();
}
} while (response != "quit");
5.23
The first loop is relatively easy to convert to a for loop as shown:
int k = 0;
while (k <= 100)
{
k += 2;
cout << "even number = " << k << endl;
}
is equivalent to:
int k;
for(k=0; k <= 100; k += 2)
{
cout << "even number = " << k << endl;
}
The second loop can yield several different for loops, two are shown below.
int total = 0;
int num;
while (cin >> num)
{
total += num;
}
In this for loop, there are empty initialization and increment sections, but the loop is equivalent to the while loop above.
int total = 0;
int num;
for(; cin >> num; )
{
total += num;
}
In this for loop, the initialization and increment aren't really related to the guard at all, but the loop functions correctly. Try to avoid writing this kind of loop [although many programmers would like this style of programming.
for(total = 0; cin >> num; total += num);
5.24
The while loop is preferable because it's possible that a loop
to read words will not ready any words. For example, if I/O
redirection is used, or a file specified by the user (see countw2.cc)
doesn't exist, then no words will be read.
Whenever it's possible for a loop to execute zero times, a while loop is preferable to a for loop. 5.25 A switch statement cannot be used in icecream.cc because in that program several if/else statements are used to distinguish among string values. A switch statement CANNOT have a string as its 'argument', only variables of type int (and char, and other integral types) can be used with switch statements. 5.26 See the primes program earlier in the book (primes.cc). 5.27
int numRows;
int j,k;
cout << "enter number of rows: ";
cin >> numRows;
// first pattern
// *
// * *
// * * *
// * * * *
// and so on
for(j=1; j <= numRows; j++)
{
for(k=0; k < j; k++) // iterate j times
{
cout << "* ";
}
cout << endl;
}
// for pattern below
// *
// * *
// * * *
// * * * *
//
const int MIDDLE = 40; // middle of 80-column screen
for(j=1; j <= numRows; j++)
{
// tab over
for(k=0; k < MIDDLE - j + 1; k++)
{
cout << " ";
}
for(k=0; k < j; k++)
{
cout << "* ";
}
cout << endl;
}
cout << "enter distance from start ";
cin >> goal;
do{
jump = die.Roll();
if (jump == 1)
{
position += 1;
}
else
{
position -= 1;
}
} while (abs(position) != goal);
5.29
void DoSimulation(int numSteps, int & distFinal, int & distMax) // precondition: numSteps = duration of random walk simulation // postcondition: distFinal = final distance from start of simulated random walk // distMax = maximal distance from start5.30 One such expression is shown below.
position += 2*die.Roll() - 1;
since 2*die.Roll() is either 0 or 2, the right-hand-side of the expression evaluates to either -1 or +1. 5.31 To simulate a walk on a lattice (sometimes this kind of distance is called Manhattan-geometry after the gridwork-like layout of streets in New York City), a four sided die could be rolled with the outcome indicating whether a step is taken in the North/South/East/West direction. It is still necessary to keep both x/y coordinates.
Another approach might use a coin or two-sided die to determine whether the north/south OR the east/west direction would change. Another two sided die could determine up/down or left/right. 5.32 It is more likely that the one-dimensional random walk will visit the origin than that the two-dimensional walk will return to the origin. In both cases it is possible for this to happen. 5.33 Imagine a circle of n lilly-pads. If the pads are arranged in a circle, jumping from one to the other is like walking in a circle. This can be done by equating pads with numbers 0, 1, 2, ... (n-1). A "left" jump in the randwalk.cc corresponds to subtracting 1 from the current "pad". However, an if statement can be used to equate -1 with (n-1) so that such a jump continues around the circle.
bool IsLeap(int year)
// postcondition: returns true if year is a leap year, else false
{
Date d(2,1,year); // February first of given year
return d.LastDay == 29;
}
2
Use Date d(month,day,year) where the values of month,
day, and year reflect your date of birth. Then, to print the day
of the week on which you were born, the code below will work.
cout << d.DayOfWeek() << endl;
3
We need to worry if the program we're writing will be in use past
the year 2738, or if it will be used now to generate dates that far
in the future. A long int can represent a value of about 2 billion, so
this isn't a problem if the one-millionth day is in 2738.
4 A field width of 4 will cause the days to be farther apart. Unfortunately, the header "S M T W Th F S" is NOT printed using a fieldwidth, so this will NOT be lined up properly.
Since dayOfWeek is incremented before the statement checking the remainder when divided by 7 ( dayOfWeek % 7 == 0 ) a new line is started after every Saturday (the comments in the code reflect this too). The if statement is needed after the loop in case the last week stopped in the middle of the week in which case the last line needs to be ended with a newline (endl).
5 Among other fencepost problems are
6 To print a calendar for an entire year the function Calendar should be called 12 times, once for each month, i.e., as shown below (assuming that a function MonthName exists to print the name of a month given the corresponding number 1 == January, etc.).
for(k=1; k <= 12; k+=1)
{
cout << MonthName(k) << endl;
Calendar(k,year);
}
If this code is included in calendar.cc then that program will need to
be recompiled because it has changed, but the program date.cc will NOT
need to be recompiled, it has not changed.