Vous êtes sur la page 1sur 22

University of Toronto

Faculty of Applied Science and Engineering

ECE 106S

PROGRAMMING FUNDAMENTALS

Spring 2007

Midterm Test

Examiner: T.S. Abdelrahman, C. Gibson, and A. Goel

Duration: Two Hours

This exam is open textbook and open notes. Use of computing and/or communicating
devices is NOT permitted.

Do not remove any sheets from this test book. Answer all questions in the space provided.
No additional sheets are permitted.

Work independently. The value of each part of each question is indicated. The total value
of all questions is 100.

Write your name and student number in the space below. Do the same on the top of each
sheet of this exam book.

Name: ___________________________________
(Underline last name)

Student Number: ___________________________________

Q1. __________ Q7. __________

Q2. __________ Q8. __________

Q3. __________ Q9. __________

Q4. __________ Q10. _________

Q5. __________ Q11. _________


Total
Q6. __________ Q12. _________

Page 1 of 22
Question 1. (7 marks). General.

Answer the following questions either by Yes or No, or by providing a very brief and direct
answer when indicated.

(a) Yes or No? Suppose that all memory that is allocated using new is correctly de-allocated using
delete. Then program memory can never be exhausted.

(b) Yes or No? A single next instruction in the DDD debugger allows running a function to
completion.

(c) Yes or No? The following code ensures that the value of xp cannot be modified in main().

class X {
int x;
int get() const;
};

int main()
{
class X *xp;
xp->get();
}

(d) Yes or No? An object file (e.g., main.o) can be executed by changing its name to
main.exe and typing the command ./main.exe at the Linux command prompt.

(e) What is the name of the software tool you use in the lab to convert your C++ code into an
executable program?

(f) Yes or No? One should always use delete to destroy memory allocated with new before
returning from a function?

(g) Yes or No? If you do not provide a copy constructor for your class, a default one will be
created for you.

Page 2 of 22
Question 2. (12 marks). The Make Utility.

Consider the Makefile below.

1 all: difftool testtool


2
3 testtool: testtool.c testtool.h
4 gcc -g -Wall testtool.c -o testtool
5
6 difftool: difftool.o diffdata.o recurse.o
7 gcc difftool.o diffdata.o recurse.o -o difftool –lm
8
9 difftool.o: difftool.c difftool.h diffdata.h recurse.h
10 gcc -c -g -Wall difftool.c
11
12 recurse.o: recurse.c recurse.h
13 gcc -c -g -Wall recurse.c
14
15 diffdata.o: diffdata.c diffdata.h
16 gcc -c -g -Wall diffdata.c
17
18 clean:
19 rm *.o difftool

The following table shows several invocations of the Make utility using the above correct
Makefile. For each invocation, indicate the commands that are executed as a result of the
invocation, in the order in which they are invoked. To simplify providing an answer, the lines of
the Makefile are numbered as shown above; just indicate the line number corresponding to a
command in the table provided below. The invocations of Make are in the order shown in the
table.

Assume that the Makefile exists in the same directory as all the .cc and .h files.

Recall that the touch command simply updates the timestamp of its argument to the current
time.

Page 3 of 22
Make Invocation Commands Executed (indicate line number)
make clean

make recurse.o

make difftool

make all

touch difftool
make

touch diffdata.h
make

Page 4 of 22
Question 3. (9 marks). Pointers and Memory Management.

Assume that the following code will compile and run properly.

1 int a = 6;
2 int *b = &a;
3
4 int *
5 foo(int **c)
6 {
7 (**c)++;
8 *c = b;
9 int *d = new int;
10 *d = 10;
11 // Point #1
12 return d;
13 }
14
15 int
16 main()
17 {
18 int e = 7;
19 int *f = &e;
20
21 f = foo(&f);
22 (*f)++;
23 // Point #2
24 return 0;
25 }

(a) (3.5 marks). Complete the following diagram by showing the values of variables and/or
pointers when execution reaches the point labeled “Point #1”. For an integer variable,
simply show the integer value inside the corresponding box. For a pointer, indicate the value
of the pointer by drawing an arrow from the box corresponding to the pointer to the box
corresponding to the variable the pointer points to.

a b c

d e f

new int

Page 5 of 22
(b) (3.5 marks). Complete the following diagram by showing the values of variables or pointers
when execution reaches the point labeled “Point #2”. For an integer variable, simply show
the integer value inside the corresponding box. For a pointer, indicate the value of the
pointer by drawing an arrow from the box corresponding to the pointer to the box
corresponding to the variable the pointer points to. Cross out any variables, pointers or
memory allocations that no longer exist.

a b c

d e f

new int

(c) (2 marks). While the program will run correctly as written, it contains a non-fatal memory
allocation problem. Write the single line of code that will fix the error. Specify the line
number in the program after which the line of code should be inserted.

Page 6 of 22
Question 4. (8 marks). Scopes.

The following class definition describes a simple C++ class called sampleClass.

#include <iostream>
using namespace std;

class sampleClass {
private:
int val;
public:
sampleClass();
sampleClass(int v);
~sampleClass();
};

sampleClass::sampleClass()
{
val = 0;
cout << "Constructing " << val << endl;
}

sampleClass::sampleClass(int v)
{
val = v;
cout << "Constructing " << val << endl;
}

sampleClass::~sampleClass()
{
cout << "Destructing " << val << endl;
}

Page 7 of 22
Consider the following code, which uses sampleClass:

sampleClass a(1);

void f1()
{
sampleClass a[2];
cout << "Leaving f1()" << endl;
return;
}

sampleClass *f2()
{
sampleClass *a = new sampleClass(2);
cout << "Calling f1()" << endl;
f1();
cout << "Leaving f2()" << endl;
return a;
}

int main()
{
sampleClass a(3);

if ((2 + 2) == 4) {
cout << "Calling f2" << endl;
sampleClass *a = f2();
cout << "Back from f2" << endl;
delete a;
}
cout << "Leaving main" << endl;
return 0;
}

Page 8 of 22
In the space provided below, write the output that an execution of the above program would
produce in the order in which it is produced. Use one entry in the table for each line of output
produced.

Page 9 of 22
Question 5. (12 marks). Classes and Objects.

Consider the following definitions and partial implementation.

struct triplet {
int first;
int second;
int third;
};

class mystery {

private:
int x;
int y;
struct triplet* the_triplet;
public:
mystery(int f, int s, int t);
~mystery();
mystery & mystery_member(const mystery & other) const;

};

mystery::mystery(int f, int s, int t) {


the_triplet = new struct triplet;
the_triplet->first = f;
the_triplet->second = s;
the_triplet->third = t;
}

mystery::~mystery() {
delete the_triplet;
}

mystery & mystery::mystery_member(const mystery & other) const {

// This is the mystery

Page 10 of 22
(a) (6 marks). Indicate by placing an X in the appropriate column whether each of the following
statements that appear in the body of a main() function that uses mystery is valid, or not
valid given the definition of mystery above. A statement is valid if it compiles and
executes correctly. A statement is not valid if it either generates a compile-time error, or if it
compiles correctly, but produces a run-time error (i.e., the programs stops with an error as
soon as the statement is executed). Assume that each of the statements is independent of the
others.

Statement Valid Not


Valid
mystery f(1,2,3);

mystery g;
mystery f(1,2,3);
cout << f.y;
mystery f(1,2,3);
mystery g(4,5,6);
g=f;
mystery f(1,2,3);
mystery g(4,5,6);
if(g<f) return (0);
mystery f(1,2,3);
mystery g(4,5,6);
mystery_member(g) = f;

(b) (6 marks). Indicate by placing an X in the appropriate column whether each of the following
statements that appear in the body of the member function mystery_member is valid, or
not valid given the definition of mystery above. A statement is valid if it compiles
and executes correctly. A statement is not valid if it either generates a compile-time error, or
if it compiles correctly, but produces a run-time error (i.e., the programs stops with an error
as soon as the statement is executed). Assume that each of the statements is independent of
the others.

Statement Valid Not


Valid
x=0;
the_triplet->first=1;
cout << y;
cout << other.x;
other.x = the_triplet->second;
other.the_triplet->third = 0;

Page 11 of 22
Question 6. (8 marks). Memory Management.

Consider the following definition of the two classes, database and element.

class database {
private:
int count;
element** thearray;
public:
:
:
:
};

class element {
private:
int count;
char* name;
public:
:
:
:
};

The public functions of each of the two classes include the constructors, accessor methods and
the destructor.

A main function uses these class definitions to construct a database object called
mydatabase and many element objects as shown in the figure below.

means NULL

count
thearray
0 1 2 3 dynamically allocated array n-1
mydatabase

dynamically
allocated count count count
name name name
objects of type
element

dynamically allocated char arrays

Page 12 of 22
(a) (4 marks). Write the following constructors for the two classes, database and element.
The constructor for element should initialize count to 0 and name to an empty string. The
constructor for database should initialize count to 0 and dynamically create an n element
array as shown in the figure above. Each element of the array should be initialized to NULL.

database::database(int n) {

element::element() {

(b) (4 marks). Write the destructors of the two classes, database and element such that no
memory leaks exist when the object mydatabase goes out of scope. Note that all variables
are dynamically allocated as indicated in the above figure, except mydatabase, which is an
automatic variable. Write your code in the space provided below.

database::~database() {

element::~element() {

Page 13 of 22
Question 7. (12 marks). Objects.

Study the following class definition and implementation.

struct pair {
int first;
int second;
};

class usePair {
private:
bool valid;
struct pair* thepair;

public:
usePair();
usePair(int f, int s);
~usePair();
void setFirst(int f);
void setSecond (int s);
usePair & operator= (usePair rhs);
void print();
};

#include "usepair.h"
#include "iostream"
using namespace std;

usePair::usePair() {
valid = true;
thepair = new struct pair;
thepair->first = 0;
thepair->second = 0;
}

usePair::usePair(int f, int s) {
valid = true;
thepair = new struct pair;
thepair->first = f;
thepair->second = s;
}

usePair::~usePair() {
delete thepair;
}

void usePair::setFirst(int f) {
thepair->first = f;
}

void usePair::setSecond(int s) {
thepair->second = s;
}

Page 14 of 22
usePair & usePair::operator= (usePair rhs) {
valid = rhs.valid;
thepair->first = rhs.thepair->first;
thepair->second = rhs.thepair->second;
rhs.thepair->first = thepair->second;
rhs.thepair->second = thepair->first;
return (*this);
};

void usePair::print() {
cout << “(“ << thepair->first
<< “,” << thepair->second
<< “)” << endl;
}

Now consider the following main function, which uses the above class.
#include “iostream”
#include “usePair.h”
using namespace std;
int main () {
usePair a(1,1);
usePair b(4,16);
usePair c = b;
usePair d;
a.print(); // Statement # 1
b.print(); // Statement # 2
c.print(); // Statement # 3
d.print(); // Statement # 4

a.setFirst(0);
b.setFirst(8);
c.setSecond(20);
d.setFirst(5);
d.setSecond(10);

a.print(); // Statement # 5
b.print(); // Statement # 6
c.print(); // Statement # 7
d.print(); // Statement # 8

a=b;
d=c;

a.print(); // Statement # 9
b.print(); // Statement # 10
c.print(); // Statement # 11
d.print(); // Statement # 12
return (0);

Page 15 of 22
Indicate what is being printed by each statement in the above main function. For simplicity, each
statement that produces output has been given a number, and you can write the output of each
statement in the table below.

Statement # Output

10

11

12

Hint: A picture is worth a thousand words.

Page 16 of 22
Question 8. (9 marks). Linked Lists.

(a) (3 marks). You are given two pointers P and Q to the singly-linked list shown below.
Assume that each node in the list contains a data field (of type integer) and a next field.
Use the P and Q pointers to switch the positions of the nodes B and C so that the nodes
occur in the order A, C, B and D. Do not simply swap the integer values associated with
nodes B and C. Also, do not change the values of P and Q and do not use any additional
variables.

A B C D
1 2 3 4

data next

P Q

(b) (6 marks). You are again given two pointers P and Q to the list shown below. Use these
pointers to switch the positions of the nodes B and E so that the nodes occur in the order A,
E, C, D, B and F. Do not simply swap the integer values associated with nodes B and E, and
do not change the values of P and Q. You can declare and use one additional variable.

A B C D E F
1 2 3 4 5 6
data next
P Q

Page 17 of 22
Question 9. (6 marks). Tree Traversals.

(a) (3 marks). Give the inorder, preorder, and postorder traversals of the tree shown below. The
tree represents the mathematical expression x – y + z.

- z

x y

Inorder Traversal:

Preorder Traversal:

Postorder Traversal:

(b) (3 marks). The following tree is a Binary Search Tree (BST) that contains all integers
between 1 and 14. Give the inorder traversal of the tree.

10

6 11

2 7 12

1 3 9 14

5 8
13

Inorder Traversal:

Page 18 of 22
Question 10. (5 marks). Tree Traversals.

Write a recursive function to perform the triple-order traversal of a binary tree, meaning that for
each node of the tree, the function first visits the node, then traverses its left subtree (in triple-
order), then visits the node again, then traverses its right subtree (in triple-order), then visits the
node again. Hence, the triple-order traversal of the tree shown below is:

3 4 2 2 2 4 1 1 1 4 3 5 5 5 3.

4 5

2 1

Write a recursive function to perform the triple-order traversal of a binary tree. Assume that
visiting a node simply prints its key to cout. Your code should be very short (5-6 lines)!
Excessively long code will be penalized.

You may assume the following declarations:

class treenode {
public:
int data;
treenode *left;
treenode *right;
};
treenode *Root; // root of the tree

void tripleorder (treenode *rt) {

// This is how tripleorder is called


tripleorder(Root);

Page 19 of 22
Question 11. (6 marks). C++ I/O.

Your task is to expand the command parser from Lab 3 to implement an additional operation,
printmultiple, which accepts multiple student numbers and prints out a record for each
student. The command format is:

printmultiple N stnum1 stnum2 ... stnumN

The first parameter, N, indicates the number of student numbers that follow on the line. The
following examples are both valid commands:

printmultiple 0
Done.
printmultiple 2 987654321 987654320
OUTPUT FOR STUDENT 987654321 APPEARS HERE
OUTPUT FOR STUDENT 987654320 APPEARS HERE
Done.

If any of the numbers are invalid (e.g., “foo” or “-12”), you should skip processing the
remainder of the line without printing an error message. You may assume that you have
access to the following function, which handles the printing of the student record:

bool printStudent (int stnum);

The printStudent function will return a false value if the student number does not exist in
the database; in this event, you should skip the remaining student numbers, without printing
an error message. When you are finished processing the printmultiple command (whether
there were errors or not) you should print “Done”. You are not expected to handle any other
errors, or produce any additional output.

Using only the cin operator for input, complete the following code fragment for processing a
single printmultiple command:

char buffer[MAX_COMMAND_SIZE];

// ...
if (!strcmp(buffer, “printmultiple”)) {

Page 20 of 22
Question 12. (6 marks). Recursion.

A tail-recursive function is a special kind of recursive function in which after completing all
other operations, the function simply calls itself and returns the result of this call. Below, the
factorial function is shown on the left. Write a tail-recursive factorial function. A template for
this function is shown on the right.

Original function Tail-recursive function

int int
factorial(int n) factorial( )
{ {
if (n <= 1) return 1;
return n * factorial(n-1);
}

return factorial( );
}

Called: factorial(n); Called: factorial ( );

Page 21 of 22
THIS PAGE IS INTENTIONALLY BLANK FOR ANSWER OVERFLOWS

Page 22 of 22