1. The purpose of this question
was to check that you can write a complete working program in C or C++.
A number is considered “big” if it is greater than 100, “medium” if it is between 20 and 100, or “little” if it is less than 20. Write a program that reads a sequence of numbers typed by the user, for each number the program must print a simple report indicating whether it is big, medium, or little, and whether it is odd or even. The program should continue until the user enters a negative number.
Enter numbers, terminated by a negative...
? 37
37 is a medium odd number.
? 25846
25846 is a big even number.
? 7
7 is a little odd number.
? 124
124 is a medium even number.
? –1
First I’ll make a general plan of the program, then fill in the details. After printing the initial explanation “Enter numbers…”, the program goes into a loop, repeatedly accepting a numeric input, and processing it in some way. Just having that much of a plan allows us to start writing the program:
#include <iostream>
void main(void)
{ cout << “Enter numbers, terminated by
a negative...\n”;
while ( some condition )
{
int num;
cout << “? “;
cin >> num;
process num in some way } }
This just leaves two parts to be worked out: “some condition” and “process num in some way”. I’ll start with the latter, but either would do.
To process the input value, we can see
there is a simple pattern to follow. First the number itself is printed,
followed by “is a”. Then we print “big”, “medium”, or “little” depending on the
size of the number, then we print “even” or “odd” depending on the parity of
the number, and finally we print “number.” And that’s it. Four simple phases.
The first is easier than falling off a
bicycle:
cout << num << “ is a“;
The second has three possible cases, each
of which can be chosen with a simple condition, so an “if … else …” construct
is ideal:
if (num<10)
cout
<< “ little”;
else if (num<=1000)
cout
<< “ medium”;
else
cout
<< “ big”;
Just because the question describes the
problem in terms of how many digits a number has, that doesn't mean that you
have to work out some way to count those digits. A two digit number must be
between 10 and 99; forget about logarithms or counting the number of times you
can divide by ten before the number is reduced to zero.
Be very careful with the placement of
semicolons, and remember that when you have a number of mutually exclusive
possibilities, it is almost always best to use a sequence of if … else if …
else if … else … statements, and there isn’t much that can go wrong.
The third phase is just as simple, but
requires you to be able to tell whether a number is odd or even. Divide a
number by two and look at the remainder, 1 means odd and 0 means even. Remember
that in C, the % operator gives the remainder after a division, and you’ve got
it:
if (num%2==1)
cout
<< “ odd”;
else
cout
<< “ even”;
If you can’t think how to do something like that (checking for oddness or evenness) don’t panic, pretend there is a function that does the job, and use it:
if (isOdd(num))
cout
<< “ odd”;
else
cout
<< “ even”;
That way, at least you have a fundamentally correct program that shows you know how to do the important things. You can add a note saying that you are aware that there is no “isOdd” function in C. Later, if you work out how to do it, you can easily add a definition of such a function to your program without disrupting what you’ve already done.
The fourth phase is of course absolutely
trivial:
cout << “ number.\n”;
Now all we have to think about is how to end
the loop. Whenever num is –1, the loop should stop. We could make the loop say
“while (num!=-1)”, but that would require a lot of other modifications: the
variable “num” is only declared inside the loop, so we would have to move its
declaration, and make sure it has an initial value that is not –1. We would
also have to make sure that “process num in some way” (the stuff we just worked
out) does absolutely nothing when num is –1. That is a lot of changing.
It would be much easier to make the loop
naturally run for ever “while (1)”, and put a conditional break inside the
loop, just after reading the value of num:
if (num==-1) break;
A lot of programmers strongly prefer having a loop condition that does the job, and avoiding breaks. It is largely a matter of taste, but once you have a good working design it is a shame to have to change it all.
A nice clear simple program is likely to be a nice clear correct program.
After all that, the complete program would
be:
#include <iostream>
void main(void)
{ cout << “Enter numbers, terminated by
a negative...\n”;
while (1)
{
int num;
cout << “? “;
cin >> num;
if
(num==-1)
break;
cout << num << “ is a“;
if
(num<10)
cout << “ little”;
else if (num<=1000)
cout << “ medium”;
else
cout << “ big”;
if
(num%2==1)
cout << “ odd”;
else
cout << “ even”;
cout << “ number.\n”; } }
There are an enormous number of other
correct answers that would be equally acceptable. You could have checked the conditions
differently, instead of a three-way test for size followed by a two-way test
for parity, you could have had a
six-way test that checks both at once. Usually it is best to program for
separate things separately, but that is the sort of thing you learn by
experience.
Here is how the program would look if you
avoided using the break statement:
#include <iostream>
void main(void)
{ cout << “Enter numbers, terminated by
a negative...\n”;
int
num=0;
while (num!=-1)
{
cout << “? “;
cin >> num;
if
(num!=-1)
{
cout << num << “ is a“;
if (num<10)
cout << “ little”;
else if (num<=1000)
cout << “ medium”;
else
cout << “ big”;
if (num%2==1)
cout << “ odd”;
else
cout << “ even”;
cout << “ number.\n”; } } }
I would say that’s more complex, and therefore less desirable.
2. The purpose of this question
was to check that you could define and properly use functions.
Define a function that takes two integers, and returns the product of (i.e. multiplies together) all the integers between those two numbers.
product(1,4) should
produce 24 because
1´2´3´4=24
product(5,10) should
produce 151200 because 5´6´7´8´9´10=151200
product(7,5) should
produce 210 because
7´6´5=210
The question clearly calls for a function
that has two parameters, both ints, and returns a result that is also an int.
Perhaps just writing down a template for such a function would be a good start:
int product(int a, int b)
{ work out the answer;
return the answer; }
so again, if you run out of time, at least you’ve shown that you know how to declare a function even if you can’t fill in the works.
Now, how do we multiply together all the numbers between a and b? A simple loop that runs a variable through each number between a and b is an obvious idea; each time round the loop, multiply that variable into the running product. We must make sure that the running product starts out at 1, and that should do the trick:
int answer=1;
for (int i=a; i<=b; i+=1)
answer*=i;
then “return the answer” becomes the single statement “return answer”.
A few things to note: be careful with the
condition part of a for statement. It should be a condition for continuing
to execute the loop. Saying “i<b” would not execute the loop when i is equal
to b, the the last value would fail to be added. Also, “i+=1” and “answer*=i”
are just C shorthand for “i=i+1” and “answer=answer*i”; you could just as well
use “i++” for the first one.
Before we feel too pleased with ourselves
at getting the answer so quickly, let’s make sure it is right. The third
example product(7,5)=210 points out that we can not rely on the arguments being
“in order”, the first might be the biggest. What would happen to out loop if
a=7 and b=5?
Initially i is set to 7, then the test
i<=b is equivalent to 7<=5, which is false, so the loop terminates
immediately, and 1 is returned incorrectly as the result.
There are a million ways to fix this
problem. The easiest is to say “if the arguments a and b are in the wrong
order, swap them round”. Fixing bugs isn’t always so easy, but it is worth
spending a little time looking for a really simple answer.
So, the whole function definition could be:
int product(int a, int b)
{ int answer=1;
if
(a>b)
{
int temp; temp=a; a=b; b=temp; }
for
(int i=a; i<=b; i+=1)
answer*=i;
return answer; }
And the little bit of program showing how to call your function could simply be this:
void main(void)
{ cout << “The product of the numbers
between 1 and 6 is “;
cout
<< product(1,6);
cout
<< endl; }
Things to make sure you understand:
When swapping the values of two variables
(a and b above) a temporary variable is required. I’m sure you we already aware
of that. Many programmers would have declared this variable temp at the same
time as total: “int total=0,
temp;”. However, it is best to make your temporary
variables as temporary as possible. When I include the declaration of temp
inside the curly brackets surrounding the exchange: { int temp; temp=a; a=b; b=temp; } that new
variable called temp only exists inside those curly brackets. In the rest of
the program it is as though the name had never been mentioned before. You can
reuse temp as a variable name or even as a function name without any risk of
interference or confusion.
The same
applies to the declaration of the loop variable “i” inside the for statement.
When you write something like this:
for
(int i=a; i<=b; i+=1)
answer*=i;
The variable “i” only exists for the loop
itself, by the time you get to the next statement (the return), it is as though
“i” had never been mentioned, so there is no risk of you accidentally re-using
it (“i” is a very common variable name), or relying on it having some
particular value.
Making
variables as local as you possibly can is nearly always a good thing. The
general claim that global variables are bad is just a generalization of this
principle.
3. The purpose of this question
was to check that you can use arrays correctly.
Write a program that allows the user to enter a very large number of integers, all in the range 0 to 100. When all the numbers have been entered, the program should report how many times each different integer appeared in the input. It should only report numbers that appeared at least once. The user will indicate the end of the inputs by entering –1.
Hint: Don't make an array that stores all the numbers that were entered, then go through counting them. Instead, make an array with an entry for each possible number, which counts the appearances of the numbers as they are entered
Of course, you would not normally be given
such a hint. This test was only concerned with seeing whether or not you could
handle arrays correctly, it would be counterproductive to risk that some of you
might not realise this easy way of doing things, and make a really
over-complicated bit of program that wouldn't have much of a chance of being
correct.
You don’t need to store all the numbers
that the user inputs in an array. You do need an array to count the number of
times each input appears, but the individual inputs do not need to be kept.
This is fortunate, because we have no idea how many numbers the user will type.
Even if you give your array 1000000 elements, it is possible that your program
will be fed automatically generated numbers, and there could potentially be
billions of them.
So this is the plan. We have an array with
just 101 entries (numbered 0 to 100) in which we count how many times each
number has appeared. Let’s call the array “count”. So count[0] tells us how
many times we’ve seen the number 0, count[1] tells us how many times we’ve seen
the number 1, and so on, all the way up to count[100] telling us how many times
we’ve seen the number 100. Luckily the question told us that all the inputs
will be in the range 0 to 100, so we know how big to make the count array.
This means that all we have to do is set
all the entries in count to 0, then start reading the inputs. Every time we
read the number n we increment the value of count[n]. At the end we just print
out the entries in count that are not still zero.
Remember, in C (and of course C++) when you
declare an array you specify how many elements it has, and those elements are
numbered from zero up. If you declare an array like this “int A[4];”, the four
elements of A will be called A[0], A[1], A[2], and A[3]. There is no A[4]. The
number that appears in the array declaration can not be used as an array index.
This is counter-intuitive, and the cause of many errors.
Here is the whole program:
#include <iostream>
void main(void)
{ int count[101];
for
(int i=0; i<=100; i+=1)
count[i]=0;
while (1)
{
int n;
cin >> n;
if
(n==-1)
break;
count[n]+=1; }
for
(int i=0; i<=100; i+=1)
if
(count[i]!=0)
cout << i << “ appeared “ << count[i] <<
“times\n”; }
There is one very minor fault, hardly worth mentioning, but I will. If a number x appeared exactly once in the input, count[x] will be 1, and the program will print “… 1 times”. When of course it should print “… 1 time”. There are many ways to fix this, just as there are many ways to write the whole program. I’ll show two of them. For each, I’ll just rewrite the last 3 lines.
1. Expand the “if” to check for ==1 and >1, instead of just !=0
(also using a temporary variable “times” to avoid saying count[i] so many times)
for
(int i=0; i<=100; i+=1)
{
int times=count[i];
if
(times==1)
cout << i << “ appeared “ << “1 time\n”;
else if (times>1)
cout << i << “ appeared “ << times << “times\n”;
} }
2. Use a conditional expression to choose whether “time” or “times” is printed
(also using a temporary variable “times” to avoid saying count[i] so many times)
for
(int i=0; i<=100; i+=1)
{
int times=count[i];
if
(times!=0)
cout << i
<< “ appeared “
<< times
<< ( times==1 ? “time\n” : “times\n”) ; } }
Some
of you cleverly remembered that arrays can be initialised with their
declaration, like this:
{ int count[101] = { 0 };
So
long as you do make sure the array is filled with zeros, how you do it isn't
really important.