There will be a three hour final exam held in our regular classroom (bldg 315 rm 216) at 9am on Wednesday April 24th, worth 40% of your final grade.
The final exam will be closed book, closed notes, and no electronics permitted, but you will be allowed one double-sided 8.5x11 inch sheet of notes.
There will be 10 questions worth 9 marks each, but the exam mark will be recorded out of 80, not 90. (Marks greater than 80 will be recorded as 80.)
If a student missed one or both midterms their final exam mark will be substituted for the missing mark(s).
If a student's final exam mark is higher than their midterm mark(s) then their final exam mark will replace the midterm mark(s).
Pretty much anything we have covered in labs, lectures, or assignments could be exam material, but it will emphasize the core topics, particularly those that were not addressed in the midterms.
Here are three practice quizzes from 2012:
Here are some practice questions dug up from years past.
I haven't checked them out yet for possible errors, and some of them are a bit over-the-top for an exam question (for the actual exam I'll aim for eight questions that can be completed in 15-30 minutes each) but these should be good practice at least ;-)
They're roughly grouped by topic, but some overlap multiple topics.
File I/O
enum FileError { NoFileError, // no error detected OpenInputError, // error opening file for input OpenOutputError, // error opening file for output UnexpectedFileEnd, // reached end-of-file at unexpected spot in program EmptyFileError, // file contained no data };Provide appropriate implementations for the three following file handling routines:
FileError OpenInputFile(ifstream& infile, char *filename); // open the named file for input, and return the opening status FileError OpenOutputFile(ofstream& outfile, char *filename); // open the named file for output, and return the opening status FileError CopyNChars(ifstream& infile, ofstream& outfile, int NumChars); // check to ensure the two files are open, // then copy NumChars characters from the input file to the output file
int CopyCapitals(ifstream& infile, ofstream& outfile)
Command line arguments
We can use a similar mechanism to pass any number of parameters
to other functions. In the example below, the sumargs
function takes a number as the first parameter, and this number
indicates the number of other parameters that will follow.
You are to implement the bodies of both the main routine
and the sumargs function, including appropriate
error checking for the number of arguments.
Classes and inheritance
Show how methods in the ultimate derived class can access the data fields
in spite of the name clashes.
Function, method, and operator overloading
Dynamic binding
Linked lists
Stacks and queues
Write a function named printzero that takes a stack as a reference parameter,
and removes all data items from the stack,
printing out every element in the stack that does not have value defaultvalue,
where defaultvalue is also declared in the stack header file.
Trees and search trees
Sketch the tree which results.
Sorting and searching algorithms
Exception handling
Templates and the STL
Testing
The hours for time zone 1 can be 0..23, while the minutes can be 0..59.
The adjustment value is a float (since some time zones differ by fractions
of an hour) and can be positive or negative.
If valid parameters are supplied then the time in zone 2 is computed
and displayed, otherwise an appropriate error message is displayed.
The header for the function is:
#include <cstdlib>
#include <iostream>
using namespace std;
double sumargs(int num, char *params[])
// num indicates the number of string parameters
// params is the array of strings to be processed
//
// the function returns the sum of the floating point equivalents
// of all the strings in params
// e.g. sumargs(3, "17", "200", "0.3") would return 217.3
//
// use atof as the string-to-float conversion function
{
}
int main(int argc, char *argv[])
// take the sum of the values of all the command line arguments,
// assuming the atof conventions are adequate for
// converting strings to numbers
{
}
(ii) Provide more meaningful names for the error types, and more meaningful
error messages.
#include <fstream>
#include <stdlib>
using namespace std;
enum ErrorTypes { err0, err1, err2, err3, err4, };
ErrorTypes process(char *n1, char *n2)
{
ifstream f1;
ofstream f2;
f1.open(n1);
if (f1.fail()) {
cout << "ERR3" << endl;
return err3;
}
f2.open(n2);
if (f2.fail()) {
cout << "ERR4" << endl;
f1.close();
return err4;
}
while (!f1.eof())
f2.put( static_cast<char>(f1.get()) );
f1.close();
f2.close();
return err0;
}
int main(int argc, char *argv[])
{
ErrorTypes result;
if (argc < 3) {
cout << "ERR1" << endl;
exit(err1);
} else if ((argc % 2) == 0) {
cout << "ERR2" << endl;
exit(err2);
} else {
for (int i = argc-1; i > 1; i-=2) {
result = process(argv[i], argv[i-1]);
if (result != err0) exit(result);
}
}
exit(err0);
}
class IntegerArray {
public:
IntegerArray(int size = 50); // create an array of the specified size
~IntegerArray(); // deallocate the array storage
void SetElement(int index, float value); // set an element to the specified value
float GetElement(int index); // return the specified element
float *GetArray() { return Elements; } // return a pointer to the array
private:
int ArraySize; // the number of elements in the dynamically-allocated array
float *Elements; // a pointer for a dynamically-allocated array of elements
};
class firstclass {
private:
int A1;
public:
int A2;
protected:
int A3;
};
class secondclass : private firstclass {
private:
int B1;
public:
int B2;
protected:
int B3;
};
class thirdclass : protected secondclass {
private:
int C1;
public:
int C2;
protected:
int C3;
};
class fourthclass : public thirdclass {
private:
int D1;
public:
int D2;
void changestuff();
protected:
int D3;
};
Assuming there are no other access methods provided,
give a list of all the class variabes that method void fourthclass::changestuff()
can access.
AStringClass AStringClass::operator()(int a, int b)
{
AStringClass tmp(b - a + 1);
for (int i = a; i <= b; i++) {
tmp.s[i-a] = s[i];
}
tmp.s[i] = '\0';
return tmp;
}
#include <iostream>
using namespace std;
int foo(int x = 0, char y = 'c');
char foo(int x, char y);
char foo(char *x, char y);
void foo(float x);
void foo(float x, int y = 0);
void foo(float x, char y);
int main()
{
cout << foo(3, 'x');
cout << foo("foo", 'x');
cout << foo(3, 4);
cout << foo(3);
cout << foo('x');
foo(3);
foo(3, 4);
foo(3, '4');
}
// Assume the function implementations follow below
(ii)
Provide an alternative set of methods which solve the problems,
and explain your solution.
#include <iostream>
using namespace std;
class Pet {
public:
Pet(char *n = NULL) {
if (n == NULL) name = NULL;
else {
name = new char[strlen(n)+1];
strcpy(name, n);
}
}
~Pet() { delete name; }
virtual void print() = 0;
protected:
char *name;
};
class Cat: public Pet {
public:
Cat(char *n = NULL, char *b = NULL) : Pet(n) {
if (b == NULL) breed = NULL;
else {
breed = new char[strlen(b)+1];
strcpy(breed, b);
}
}
void print() {
cout << name << " the cat is a " << breed << endl;
}
private:
char *breed;
};
class Dog: public Pet {
public:
Dog(char *n = NULL, char *b = NULL) : Pet(n) {
if (b == NULL) breed = NULL;
else {
breed = new char[strlen(b)+1];
strcpy(breed, b);
}
}
void print() {
cout << name << " the dog is a " << breed << endl;
}
private:
char *breed;
};
Write a main routine and function call
which clearly show polymorphism in action,
and explain the sequence of events (with respect to
polymorphism) that take place
during the relevant function and method calls.
class list {
public:
list(); // construct an empty list
list(const list& L); // copy constructor
~list(); // deallocate all list nodes
// create and insert a node at the front of the list
bool insertFront(int d);
// remove and deallocate all nodes containing data value d,
// returning a count of how many were removed
int deleteValues(int d);
private:
// specs for individual nodes within the list
struct listnode {
listnode *next;
listnode *prev;
int data;
};
// track the front element in the list
listnode *front;
// dynamically allocate and initialize a node
listnode* createNode(int d);
};
class TheClass {
public:
TheClass(int size); // creates a new (empty) TheClass which can hold
// the specified number of data elements
~TheClass(); // deletes TheClass storage space
void Insert(float data); // inserts a new data element in TheClass
float Remove(); // removes and returns a data element from TheClass
private:
float *DataList; // dynamically allocated array for holding TheClass data
int ArraySize; // size of the dynamically-allocated array
int CurrentSize; // number of data elements currently in the array
int Index; // can be used, if you need it, to track some other
// position within the array
};
Provide an implementation of the Remove method that would be valid
if TheClass represented a stack.
class stack {
public:
stack(int size = MAXSIZE);
~stack();
void push(char c);
char pop();
bool isempty();
private:
// hidden stuff
};
class queue {
public:
queue(int size = MAXSIZE);
~queue();
void enqueue(char c);
char dequeue();
bool isempty();
private:
// hidden stuff
};
A palindrome is a word that is spelled the same backwards as forwards,
e.g. "bob", "a", "adbda", etc.
You are to implement
a palindrome-checking function that operates precisely as follows:
You may assume that the default stack and queue size are sufficiently
large to handle the user's input. The function header is supplied below.
bool IsPalindrome() {
stack::stack();
stack::~stack();
Boolean stack::isempty();
Boolean stack::isfull();
datatype stack::top();
void stack::pop();
void stack::push(datatype d);
(You may assume that datatype and Boolean are data types defined
in the stack header file.)
void printzero(stack& s)
9
/ \
/ \
1 7
/ \
2 3
\
5
/
1
// return the position of the key value in the array segment,
// or -1 if the value is not present
int search(int arr[], int lower, int upper, int key)
{
if (key < arr[lower]) return -1;
if (key > arr[upper]) return -1;
if (lower > upper) return -1;
if (lower < 0) return -1;
int midpoint = (lower + upper) / 2;
if (key == arr[midpoint]) return midpoint;
if (key < arr[midpoint])
return search(arr, lower, midpoint-1, key);
return search(arr, midpoint+1, upper, key);
}
int partition(int arr[], int first, int last)
{
int lower, upper;
int pivotvalue = arr[first];
lower = first;
upper = last;
do {
while ((pivotvalue >= arr[lower]) && (lower <= last)) lower++;
while (pivotvalue < arr[upper]) upper--;
if (lower < upper) swap(arr[lower], arr[upper]);
} while (lower < upper);
swap(arr[first], arr[upper]);
return upper;
}
void quicksort(int arr[], int first, int last)
{
if ((first >= last) || (first < 0)) return;
int pivot = partition(arr, first, last);
quicksort(arr, first, pivot-1);
quicksort(arr, pivot, last);
}
#include <iostream>
using namespace std;
void f1(double t);
int main()
{
try {
cout << "stage 1" << endl;
f1(80);
cout << "stage 2" << endl;
f1(40);
cout << "stage 3" << endl;
}
catch (int x) {
cout << x << endl;
}
cout << "stage 4" << endl;
}
void f1(double t)
{
cout << "Beginning f1" << endl;
if (t < 50) throw 25;
}
void printsquares(char *data[], int numvalues)
// printsquares takes as parameters an array of null-terminated strings
// and an integer describing the number of strings in the array
// (an error message is generated if there is not at least one string)
//
// printsquares evaluates each string to see if it is a positive integer,
// and if so prints the square of that integer
// (if not then an error message is generated)
You may use existing library routines, but include a comment indicating
which C++ library is required.
However, the developers of the Java programming language decided not
to include multiple inheritance as an option for classes in that language.
Describe possible advantages and disadvantages associated with such
a decision.
#include <iostream>
#include <string>
#include <stack>
using namespace std;
const int MAXSIZE = 256;
int main(int argc, char *argv[])
{
stack<string> MyStack;
string *s;
string t;
for (int i = 1; i < argc; i++) {
s = new string(argv[i]);
MyStack.push(*s);
}
cout << MyStack.size() << endl;
while (!MyStack.empty()) {
t = MyStack.top();
MyStack.pop();
cout << t << endl;
}
}
void timeCalc(int hours1, int minutes1, float diff);
Write a set of test values you would apply to determine if the
function was working correctly. For each test set, give a value for
hours1, minutes1, diff, and the expected result, plus a short description
of why that particular test set has been included