You are on page 1of 16

COS1512/201/1/2017

Tutorial letter 201/1/2017


Introduction to Programming II

COS1512
School of Computing
This tutorial letter contains the
solutions to Assignment 1
COS1512/201/1/2017

INTRODUCTION

By the time you receive this tutorial letter you should have already completed assignment 1 and we
hope that you are well on your way with your studies. This tutorial letter contains the solutions to
Assignment 1. You are welcome to e-mail me with any queries at schoema@unisa.ac.za. Also take
note of the following telephone number and the days on which the lecturer are available in case you
have to call.

Mondays Dr MA Schoeman 011 670 9178


Tuesdays Dr MA Schoeman 011 670 9178

Allocation of marks
When we mark assignments, we comment on your answers. Many students make the same mistakes
and consequently we discuss general problems in the tutorial letters. It is, therefore, important to work
through the tutorial letters and to make sure you understand our solutions and where you went wrong.
The maximum number of marks you could obtain for Assignment 1 is 80. This is converted to a
percentage. If you for instance obtained 60 marks for Assignment 1, you received 60/80 * 100 = 75%
for Assignment 1. This percentage in turn contributes a weight of 20% to the year mark, as can be
seen in the summary of the weights allocated to the assignments for COS1512 below.

Assignment
Weight
number
1 20
2 80
3 0

We give the mark allocation for the questions below. For questions 1 – 4 you will not get any marks if
you did not include the program code. Or if you only included part of the code, you will get a maximum
of 2 marks if the included code is correct. Please note that this is NOT the way exam answers will be
marked. If you did not include the output for your program, you will not get full marks for the question.
We discuss a possible solution for each question below. Please read through the solution and
discussions thoroughly.

The marks you received for question 1 was determined on the following basis:
Question not done 0/10
Question attempted, but the program does not work at all 4/10
A good attempt, but there are a few problems with your answer 8/10
The program works correctly and produces the correct output 10/10

The marks you received for question 2 was determined on the following basis:
This question was not marked. If you attempted the question, you will get 5 marks. If not, you will get 0
marks. Please go through the solution that we give for question 2 to make sure that you understand
the assert() function.

The marks you received for questions 3 and 4 was determined on the following basis:
Question not done 0/15
Question attempted, but the program does not work at all 6/15
A good attempt, but there are a few problems with your answer 11/15
The program works correctly and produces the correct output 15/15

The marks you received for question 5 was determined on the following basis:
One mark each for question 5(a) – (g), and (i) - (k), 5(l)(i) -5(l)(viii), 5(l)(x)-5(l)(xii) and 5(l)(xiv), that is
max 20 marks

2
COS1512/201/1/2017

Two marks each for question 5(h), 5(l)(ix), and 5(l)(xiii), that is max 6 marks
Seven marks for question 5(m), that is max 7 marks
Total number of marks for question 5 is max 35 marks.

3
COS1512/201/1/2017

Question 1 10 marks

In this question you had to write an overloaded function named calcCircumference with either one
or two parameters of type double. Although it was not specified in the question, our program only
displays two digits after the decimal point and validates the input. You had to overload function
calcCircumference().

Overloading is a feature in C++ that allows the programmer to define more than one function with the
same name, but with either a different number of function parameters, or with parameters of different
types. The compiler will use either the number of parameters, or the type of parameters to choose
which function to call. The first overloaded function will calculate the circumference for a circle and the
second overloaded function will calculate the circumference for a square. We show two different
outputs for the program listing below to show what happens when each of the two overloaded
functions are called.
The functions on lines 7 and
15 have the same function
Program listing:
name
1. //Ass 1 question 1 CalcCircumference().
2. #include <iostream>
The function is overloaded.
3. using namespace std;
The difference in this case is
the number of parameters in
4. //overloaded function for circumference of
these functions. In line 7 the
5. //circle Pre : radius of circle
function has one parameter
6. //Post: returns circumference
and in line 15, two
7. double calcCircumference(double radius)
8. { parameters. The compiler will
9. const double PI = 3.14285; use the number of parameters
10. return (2 * radius * PI); to decide which function to
11. } call. For instance, when the
function is called with two
12. //overloaded function for circumference of parameters, it will use the
13. //block Pre : length and width of block function that starts at line 15.
14. //Post: returns circumference When is
15. double calcCircumference(double length, double width)
16. {
17. return (2 * (length + width));
18. }

19. int main()


20. {
21. double length, width, radius, circumference;
22. char type;
23. cout << "Would you like to calculate the circumference of"
<< "a block or a circle - " <<endl;
24. do
25. {
26. cout << "Please enter 'b' for block or 'c' for "
<< "circle): ";
27. cin >> type;
28. }while (type != 'b' && type != 'c');

29. if (type == 'b')


30. {
31. cout << "Please enter the length and width of the "
<< "block: ";
32. cin >> length >> width;

4
COS1512/201/1/2017

33. circumference = calcCircumference(length, width);


34. }
35. else
36. {
37. cout << "Please enter the radius of the circle: ";
38. cin >> radius;
39. circumference = calcCircumference(radius);
40. }
41. cout.setf(ios::fixed);
42. cout.precision(2);
43. cout << "The circumference of the figure is "
<< circumference << endl;
44. return 0;
45. }

Input and corresponding output version 1:


Would you like to calculate the circumference of a block or a circle -

Please enter 'b' for block or 'c' for circle): b


Please enter the length and width of the block: 12.34 66.678

The circumference of the figure is 158.04

Input and corresponding output version 2:


Would you like to calculate the circumference of a block or a circle -

Please enter 'b' for block or 'c' for circle): c


Please enter the radius of the circle: 44.5678

The circumference of the figure is 280.14

Question 2 This question has not been marked – 5 marks if you attempted it

In this question you had to change two dates (dd mm) to the julian date format, ensure that both dates
are valid, and calculate the number of days difference between the two dates. We used the assert
macro as follows, making use of the definition of daysPerMonth as stated in the question:

cout << "Please enter the first date (e.g. 31 3): " ;
cin >> day >> month;
assert(day >= 1 && day <= daysPerMonth[month-1]);
assert(month >= 1 && month <= 12);

To use the assert() function in your program, you must include the cassert header file in your
program:

#include <cassert>

We expected you to check the validity of the dates with the assert macro. This is of course also
possible without the assert macro.

Typically the assert macro is used to identify program errors during development. Remember that
the assert() function evaluates a boolean expression. If the result is 1 (true), the program
continues. If the result is 0, the program aborts with an exception The argument given to assert

5
COS1512/201/1/2017

should therefore be chosen so that it holds true only if the program is operating as intended. The
macro evaluates the assert argument and, if the argument expression is false the program execution
is halted. No action is taken if the argument is true, i.e. the program simply continues executing.

You did not have to handle the exception that occurs if the result of the assert() function is 0, in
your program. We just wanted to see that you did get the exception in your output, when the
conditions were not met.

We highlight the use of the assert() function in the program listing below, and show the two sets of
output when the input for the two students given in the question, is used.

Program listing:
1. Program listing
2. //Ass 1 question 2
3. #include <iostream>
4. #include <cassert>
5. using namespace std;
6. int daysPerMonth[12] = {31,28,31,30,31,30,31,31,30,31,30,31};

7. int calcJulian(int day, int month)


8. {
The assert function is
9. int totaldays = 0; used to check if the input
10. for (int i = 0; i < month-1; i++) meets the criteria .If it
11. totaldays += daysPerMonth[i]; meets the criteria, the
12. totaldays += day; program will continue. If
the criteria are not met,
13. return totaldays;
the assert function will
14. } throw an exception error.
15. int main()
16. {
17. int day, month, difference, julianfirst, juliansecond;
18. cout << "Please enter the first date (e.g. 31 3): " ;
19. cin >> day >> month;
20. assert(day >= 1 && day <= daysPerMonth[month-1]);
21. assert(month >= 1 && month <= 12);
22. julianfirst = calcJulian(day, month);
23. cout << "The Julian format of the first date is " << julianfirst
<< endl;
24. cout << endl<< "Please enter the second date (e.g. 31 3): " ;
25. cin >> day >> month;
26. assert(day >= 1 && day <= daysPerMonth[month-1]);
27. assert(month >= 1 && month <= 12);
28. juliansecond = calcJulian(day, month);
29. cout << "The Julian format of the second date is "
<< juliansecond << endl;
30. if (julianfirst > juliansecond)
31. difference = julianfirst - juliansecond;
32. else
33. difference = juliansecond - julianfirst;
34. cout << endl <<"There are "<< difference << " days difference"
<< " between the two dates." <<endl;

6
COS1512/201/1/2017

35. return 0;
36. }

Input and corresponding output :


Please enter the first date (e.g. 31 3): 31 12
The Julian format of the first date is 365

Please enter the second date (e.g. 31 3): 03 03


The Julian format of the second date is 62

There are 303 days difference between the two dates.

Question 3 15 marks

Discussion of Solution

The first step is to create the input file. We created the input file Nrs.dat by using the Code::Blocks
editor and creating a new source file, entering the data, and saving it as a file with an extension of
.dat. (You could also have used Notepad.) Save your input file in the same directory where you
save your program.

The header file for the fstream library has to be added to the code with the #include <fstream>
directive for file processing.

The contents of the input file (and any output file should the program have produced one or more) can
be viewed with Code::Blocks. This file is opened with File | Open Project or File and by
selecting the correct file in the correct directory.

We open the input file Nrs.dat by associating the file name with the ifstream variable, as shown in
the statements (lines 18 to 20 in the program listing) below:

18 //Open the input file.


19 cout << "Opening the input file..." << endl;
20 fin.open("Nrs.dat");

Note that if you create the input file in a directory different from the one where you save your program,
you need to specify the path as well, when specifying the filename, e.g.
C:\unisa\cos112\datafiles\Nrs.dat

When using a file it is essential to test whether the file is available. The following code segment tests
whether the input file is available before attempting to extract from it:
21 if (!fin)
22 {
23 cout << "Error accessing input file." << endl;
24 exit(1);
25 }

In the above code segment the program is terminated immediately when exit(1) is invoked. We
need to add
#include <cstdlib>
to our program i.e. the header file for the library that contains the exit() function.

7
COS1512/201/1/2017

To reopen the input file Nrs.dat, we first have to close it, and then we have to open it again as an
ifstream and also check that it is available in lines 28 to 35:

28. //Reset to the beginning of the file.


29. fin.close();
30. fin.open("Nrs.dat");
31. if (!fin)
32. {
33. cout << "Error accessing input file." << endl;
34. exit(1);
35. }

Program Listing:
1. //Assignment 1 Question 3
2. //Calculate the average and the standard
3. //deviation of a list of numbers from a file.

4. #include <iostream>
5. #include <fstream>
6. #include <cstdlib>
7. #include <cmath>
8. using namespace std;

9. void calcAvg(ifstream& in_stream, double& average, int& count);


10. //Calculates the average of a list of numbers from a file.

11. void stdDeviation(ifstream& in_stream, double& stdDev, double average,


int count);
12. //Calculates the standard deviation of a list of numbers from a file.
One gets input from a file into
13. int main()
your program, or send output to
14. { a file from your program by
15. ifstream fin; using streams, or special
16. double avg = 0, stdDev = 0; objects as they are called in
17. int nrOfNrs; C++. The type for input-variable
streams is named ifstream,
18. //Open the input file. and for outputvariable
19. cout << "Opening the input file..." << endl; streams, ofstream.
20. fin.open("Nrs.dat"); One connects the object to the
21. if (!fin) file by opening the file, as is
22. { done in the code. We include
23. cout << "Error accessing input file." << endl; the fstream header file as
24. exit(1); well.
25. } Please see section 6.1 in
Savitch for more information.
26. //Calculate the average of the numbers in the file.
27. calcAvg(fin, avg, nrOfNrs);

28. //Reset to the beginning of the file.


29. fin.close();
30. fin.open("Nrs.dat");
31. if (!fin)
32. {
33. cout << "Error accessing input file." << endl;
34. exit(1);

8
COS1512/201/1/2017

35. }

36. //Calculate the standard deviation of the numbers in the file.


37. stdDeviation(fin, stdDev, avg, nrOfNrs);

38. //Close the file.


39. fin.close();

40. //Output the average and standard deviation.


41. cout.setf(ios::fixed);
42. cout.setf(ios::showpoint);
43. cout.precision(2);
44. cout << "The average of the numbers in the file is "<< avg << "." << endl
<< "The standard deviation of the numbers in the file is " << stdDev
<< "." << endl;

45. return 0;
46. }

47. void calcAvg(ifstream& in_stream, double& average, int &count)


48. {
49. double total = 0, next;
50. count = 0;
51. while(in_stream >> next)
52. {
53. total += next;
54. count++;
55. }
56. average = total/count;
57. }

58. void stdDeviation(ifstream& in_stream, double& sDev, double average, int count)
59. {
60. double total = 0, next = 0, avg_std = 0;
61. while (in_stream >> next)
62. {
63. total += pow((next - average), 2);
64. }
65. avg_std = total/count;
66. sDev = sqrt(avg_std);
67. }

Inputfile:
20.5 34.1 67.2 76.4
31.2 89.6 97.6 45.3

Output:
Opening the input file...
The average of the numbers in the file is 57.74.
The standard deviation of the numbers in the file is 27.03.

Process returned 0 (0x0) execution time : 0.137 s


Press any key to continue.

9
COS1512/201/1/2017

Question 4 15 marks

Discussion:
The purpose of the program is to read a file character by character. The input file (we used
employee.txt) contains a list of employee names. Your task was to read the employee names
character by character and create userids of eight characters long for each employee before writing
them to the output file. Each userid consists of the first eight alphabetical characters in an employee’s
name. Spaces and non-alphabetical characters were excluded. In addition, if the employee name
excluding spaces and non-alphabetical characters consists of less than 8 characters, the userid will
also contain less than 8 characters. Semi-colons indicated the end of an employee name and is also
used to separate userids in the output file.

We did not write a function to perform this task – it is performed by the main function. We did, however
write a function to read and display the input file, as well as the output file that was created from the
input file. It is good programming practice to put the code that does all the reading and writing
together.

When implementing our solution, once again the first step is to create the input file. Since the purpose
of the program is to process files, the #include <fstream> and #include <cstdlib> directives
have to be included in the program in order to use the files and to test that they exist before they are
used. The names of the input and output files are requested from the user.

In this program we process the input file as a text file (see section 6.3 in Savitch). A text file is typically
processed in the following way:
char ch;
infile.get(ch);
while (!infile.eof())
{
//process ch
infile.get(ch);
}

Compare this to the typical way to read a file containing values that should be processed as int,
string or float (as in Question 3), e.g. a file containing one int followed by a string on each line:

int value;
string name;
while (infile >> value >> name)
{
//process value and name
}

After having created the output file, we added some code to read the input file and display the
contents, as well as some code to do the same for the output file. Note that after the output file is
created and closed, it now acts as an input file if we want to read and display its contents. We
therefore need an ifstream definition. For this purpose, in line 29 and 30, we defined:
ifstream indisplay; //to display the input file
ifstream outdisplay;//to display the output file

The first declaration will represent the original input file. The second declaration will represent the
created output file as an input file.

Note that when file streams are passed as arguments to a function, they need to be reference
parameters for the function, since they will be modified, as can be seen from the header for the
function checkFile in line 15:
void checkFile(ifstream& infile).

10
COS1512/201/1/2017

The file streams should be passed by reference rather than by value since the internal state of a file
stream object may change with an open operation even if the contents of the file have not changed.
When you declare a reference parameter, the function call will pass the memory address of the actual
parameter, instead of copying the parameter value into the formal parameter.

Also note that we have to close both the input file and the output file (line 72 and 73 in the program
listing below) before we can open them again to display their contents on the screen (see line 74 to
line 94 in the program listing below). The content of the output file can also be viewed with
Code::Blocks. This file is opened with File | Open Project or File and by selecting the
correct file in the correct directory.

Program listing :

1. //Ass 1 question 4
2. #include <iostream> // for screen/keyboard i/o
3. #include <fstream> // for file
4. #include <cstdlib> // for exit

5. using namespace std;

6. // Precondition:
7. // The input file is a text file.
8. // The input file has been opened.
9. //
10. // Postcondition:
11. // The output file is a text file.
12. // The output file has been opened.
13. // Output file will contain userids created from initials and
14. // surnames read from the input file

15. void checkFile(ifstream& infile)


16. {
17. char ch;
18. infile.get(ch);
19. while(!infile.eof())
20. {
21. cout << ch;
22. infile.get(ch);
23. }
24. }

25. int main()


26. {

27. ifstream infile;


28. ofstream outfile;
29. ifstream indisplay;
30. ifstream outdisplay;

11
COS1512/201/1/2017

31. string inName, outName;

32. cout << endl << "Enter the input file name. " << endl;
33. cin >> inName;
34. cout << endl << "Enter the output file name. " << endl
35. << "WARNING: ANY EXISTING FILE WITH THIS NAME WILL"
36. <<" BE ERASED." << endl;
37. cin >> outName;

38. infile.open(inName.c_str());
39. if (infile.fail())
40. {
41. cout << "Cannot open file " << inName << " Aborting!"
<< endl;
42. exit(1);
43. }

44. outfile.open(outName.c_str());
45. if (outfile.fail())
46. {
47. cout << "Cannot open file " << outName << " Aborting!"
<< endl;
48. exit(1);
49. }

50. char ch;


51. int count = 0;
52. infile.get(ch);
53. while(!infile.eof())
54. {
55. ch = tolower(ch);
56. if (ch >= 'a' && ch <='z')
57. {
58. count ++;
59. if (count <= 8)
60. outfile << ch;
61. }
62. else
63. { //when a semicolon is reached the previous userid is
//complete
64. if (ch == ';')
65. {
66. outfile << ch;
67. count = 0;
68. }
69. }
70. infile.get(ch);
71. } //end while !infile.eof

12
COS1512/201/1/2017

72. infile.close();
73. outfile.close();

74. //This part was not required, but it is always a good idea to
// read the file that was created to make sure it is correct.
75. //We first read the original input file, and display its content
76. indisplay.open(inName.c_str());
77. if (indisplay.fail())
78. {
79. cout << "Cannot open file " << inName << " Aborting!" << endl;
80. exit(1);
81. }
82. cout << endl << "The contents of the input file is: "<< endl
<< endl;
83. checkFile(indisplay);
84. indisplay.close();

85. //Now we read the file that was created as an input file and
//display the content
86. outdisplay.open(outName.c_str());
87. if (outdisplay.fail())
88. {
89. cout << "Cannot open file " << outName << " Aborting!"
<< endl;
90. exit(1);
91. }
92. cout << endl << "The contents of the output file is: " << endl
<< endl;
93. checkFile(outdisplay);
94. outdisplay.close();

95. return 0;
96. }

Input and corresponding output 1:


Please enter the input file name :
wrongfilename.dat
Cannot open file wrongfilename.dat Aborting!
Press any key to continue . . .

Input and corresponding output 2:


Enter the input file name.
employee.dat

Enter the output file name.


WARNING: ANY EXISTING FILE WITH THIS NAME WILL BE ERASED.
userid.dat

The contents of the input file is:

13
COS1512/201/1/2017

SS van der Merwe;PJ Ferreira;HW du Plessis;DF Kodisang;AA Papoudopolous;


G Mhlanga;TRF Schoeman;LJ Marais-Le Roux;CG Roux;B Nicholaidis;TT
Tshabalala;RV Mississipi;

The contents of the output file is:

ssvander;pjferrei;hwduples;dfkodisa;aapapoud;gmhlanga;trfschoe;ljmarais;cgr
oux;bnichola;tttshaba;rvmissis;

Question 5 35 marks

(a) A pointer is the memory address of a variable. A variable’s address can be thought of as
‘pointing’ to the variable. See section 9.1 in Savitch. (1)

(b) The deferencing operator is the *operator (the asterisk) used in front of a pointer variable. It
dereferences the pointer variable to produce the variable to which the pointer is pointing to. (1)

(c) Assuming both p1 and p2 have been declared as pointers, i.e. as follows:
int *p1, *p2;
In the assignment statement p1 = p2, the value of one pointer (p2) is assigned to another
pointer (p1). Basically you are using the actual pointers (addresses of memory locations). With
the assignment statement *p1 = *p2, you are using the actual variables to which the pointers
are pointing to. (1)

(d) A dynamic variable is a variable that is created and destroyed during the execution of the
program. It is created using the new operator. (1)

(e) The new operator produces a new, nameless variable, with a specified data type and returns a
pointer that point to this new variable. This means that the only way the program can access
the variable is through the pointer pointing to it. (1)

(f) The delete operator eliminates (releases or erases) a dynamic variable and returns the
memory that the dynamic variable occupied to the freestore. It releases the memory so that it
can be used for the creation of new dynamic variables. (1)

(g) The freestore (also called the heap) is a special area in memory that is reserved to be used for
dynamic variables. (1)

(h) Dynamic variables are created in a reserved space in memory (the freestore or heap). They
are created and destroyed while the program is running. Automatic variables are automatically
created when the function in which they are declared is called and automatically destroyed
when the function ends. The ordinary variables we use in the programs we write for COS1512
are automatic variables. (2)

(i) A dynamic array is an array whose size is not specified when it is declared in the program.
Instead, its size is determined while the program is running. (1)

14
COS1512/201/1/2017

(j) They are flexible in terms of size since the size of the array can be specified during the run
time of the program. This avoids the problem of specifying an array that is too small (not having
enough elements) or too big (wasting computer memory space). (1)

(k) An array variable is a pointer variable that points to the first indexed variable in an array. (1)

(l) i. int *fPtr1, *fPtr2; (1)

ii. fPtr1 = &total; (1)

iii. cout << "The address of total is " <<fPtr1 ;


OR since fPtr1 is pointing to total, alternatively this statement will do the same:
cout << "The address of total is " <<&total ; (1)

iv. *fPtr1 += score; (1)

v. cout << "The value of the int object pointed to by fPtr1"


<< "is " << *fPtr1; (1)

vi. fPtr2 = new int; (1)

vii. cin >> *fPtr2; (1)

viii. fPtr1 = fPtr2; (1)

ix. delete fPtr1;


The value of the variable that fPtr2 is pointing to is now undefined, since that memory
location has been released. (2)

x. typedef int* IntPtr; (1)

xi. IntPtr p; (1)

xii p = new int[10]; (1)

xiii for (int i = 0; i<10; i++)


p[i] = 0; (2)

xiv delete [] p; (1)

(m)
Program:
#include <iostream>
using namespace std;
int main()
{
typedef int* IntArrayPtr; (½)

15
COS1512/201/1/2017

IntArrayPtr a; (½)
int size, max;
cout << " How many scores will be entered? ";
cin >> size;

a = new int[size]; (1)


cout << "Please enter " << size << " scores: " <<endl;
for (int i = 0; i < size; i ++) (½)
cin >> a[i]; (1)

max = 0; (½)
for (int i = 0; i < size; i ++) (½)
if (a[i] > max)
max = a[i]; (1)

cout << endl << " The highest score is " << max; (½)

delete [] a; (1)
return 0;
}

Output:
How many scores will be entered? 5
Please enter 5 scores:
67
55
78
65
75

The highest score is 78


Process returned 0 (0x0) execution time : 16.990 s
Press any key to continue.

©
UNISA
2017

16