Final Exam
Version: <VERSION>
Academic Integrity
● Aggies do not lie, cheat, or steal, nor tolerate those who do.
● We hope you have fun solving these problems, even though this is an exam ☺
● You can do this!
Exam Guidelines
● You will have 120 minutes to complete and submit this exam.
● Do not write outside of the margin box. We scan the exams and anything outside those lines
will likely get cut off.
● You cannot use any electronic devices (including calculators, phones, smart watches, and
computers)
● You may use
o A writing utensil (e.g. pen/pencil)
o Scratch Paper that we provide.
§ Scratch paper may not have the margin box, so leave a margin around the edge
of your scratch paper to avoid having information cut off when scanned.
o Up to 5 pages of exam aids.
§ Exam aids can be pages up to 8.5X11 inches and can be handwritten or printed
on both sides.
§ Do not use exam aids for scratch work.
· If you use an exam aid for scratch work, submit with exam.
● Start Exam when prompted.
● Stop exam when you are finished or when time expires.
o Attach any scratch work to the end of your exam. Including exam aids used for scratch
work.
o Submit your exam.
§ You may keep your exam aids if they were not used for scratch work.
Fill in name and UIN before exam starts
Name:________________________________________________________________________________________________
UIN:__________________________________________________________________________________________________
Name:___________________________________________
2 / 12
Q1 - Code Tracing (30 points)
Overview
●
●
In the following parts you will be given small pieces of code. Determine what each piece
of code prints, and fill in the blanks.
For each piece of code, assume that the file has #include <iostream> and using
namespace std;
Q1.1
class Letter{
char * ptr;
public:
Letter(char value) : ptr(new char(value)) { }
Letter(const Letter &other):ptr( new char( *(other.ptr))){}
void setValue(char value){
*ptr = value;
}
char getValue() const { return *ptr; }
};
ostream& operator<<(ostream& out, const Letter n) {
out << n.getValue();
return out;
}
int main() {
Letter L1('c');
Letter L2 = L1;
cout << L1 << L2;
L1.setValue('j');
cout << L1 << L2;
L2 = L1;
}
This code prints: __________
Does the code have a memory leak? (write “yes” or “no”) _________
Is it possible to call the default constructor? That is, would the code still
compile if we added the line Letter L3; at the end of main? (write “yes” or “no”) _________
Fill the table to identify which type of copy each line performs,, i.e. fill the table with either
Shallow or Deep:
Letter L2 = L1;
Shallow/Deep
L2 = L1;
Name:___________________________________________
Q1.2
class Foo{
public:
int* a;
double* b;
Foo(int* aptr, double b): a(aptr), b(new double(b)) {}
~Foo(){
delete b;
}
Foo(const Foo& other){
a = other.a;
b = new double(*other.b);
}
};
int main(){
int* ptr = new int(7);
Foo pi(ptr, 3.14);
Foo e(ptr, 2.72);
Foo morePi = pi;
*ptr = 3;
*pi.b = 3.1415;
cout << *morePi.a << ", " << *morePi.b;
delete ptr;
}
This code prints: __________
Does this code have a memory leak? (write “yes” or “no”) _________
Q1.3
class Foo{
int* x;
public:
Foo(): x(new int(3)) {}
int& val(){
return *x;
}
Foo(const Foo& other){
x = new int(*(other.x));
}
};
int main(){
Foo a,b;
a.val() = 4;
a = b;
b.val() = 5;
Foo c = a;
c.val() = 6;
cout << a.val() << b.val() << c.val();
}
This code prints: __________
Does this code have a memory leak? (write “yes” or “no”) _________
3 / 12
Name:___________________________________________
Q1.4
class Demo {
int *ptr;
public:
Demo(int num){
cout << "A";
ptr = new int(num);
}
Demo( const Demo &obj){
cout << "B";
ptr = new int;
*ptr = *obj.ptr;
}
~Demo(){
cout << "C";
delete ptr;
}
};
int main() {
Demo Demo1(10);
Demo Demo2(Demo1);
}
This code prints: __________
Does this code have a memory leak? (write “yes” or “no”) _________
Q1.5
class A {
public:
int value;
A() : value(2) {}
void operator++() {
value = value * 3;
}
void print() {
cout << value << endl;
}
};
int main() {
A oA;
++oA;
++(oA.value);
oA.print();
}
This code prints: __________
4 / 12
Name:___________________________________________
Q1.6
class A{
int x;
public:
virtual void f() {
cout << "A";
}
};
class B : public A{
public:
void f(){
cout<< "B" ;
}
};
int main(){
B* ptr = new B();
A x = *ptr;
A& y = *ptr;
A* z = ptr;
x.f();
y.f();
z->f();
}
This code prints: __________
Q1.7
class A{
public:
void print(){
cout << "A";
}
};
class B : public A{
public:
void print(){
cout << "B";
}
};
int main(){
B x;
A y = x;
A& z = x;
x.print();
y.print();
z.print();
}
This code prints: __________
5 / 12
Name:___________________________________________
Q1.8
6 / 12
class Number{
int x;
public:
Number() : x(7) {}
int operator!(){
return x;
}
friend const istream& operator>>(const istream& is, Number& num);
};
const istream& operator>>(const istream& is, Number& num){
num.x--;
return is;
}
int main(){
Number n;
cin >> n >> n;
cout << !n;
}
This code prints: __________
Q1.9
class Foo{
public:
int* data;
Foo() : data(new int(5)) {}
Foo(const Foo& other){
data = new int(*other.data);
cout << "X";
}
~Foo(){
delete data;
cout << "Y";
}
Foo& operator=(const Foo& other){
data = new int(*other.data);
cout << "Z";
return *this;
}
};
int main(){
Foo a, b;
Foo c = a;
*a.data = 7;
cout << *c.data;
b = a;
}
This code prints: __________
Does this code have a memory leak? (write “yes” or “no”) _________
Name:___________________________________________
7 / 12
Q1.10
class A{
public:
int x;
A() : x(2) {}
int f(){
return x;
}
};
class B : protected A{
int y;
public:
B() : y(5) {}
virtual int f(){
return y;
}
};
class C : public B{
public:
int z;
C() : z(9) {}
int f(){
return z;
}
};
int main(){
C obj;
cout << obj.f();
B* ptr = &obj;
cout << ptr->f();
}
This code prints: __________
Fill the table to identify which values main can access, i.e. fill the table with either Yes or No:
ptr.x
ptr.y
Can main access? (Yes/No)
Fill the table to identify which values C can access, i.e. fill the table with either Yes or No:
A::x
Can C access? (Yes/No)
B::y
Name:___________________________________________
Q2 - Ragged Non-Sparse Matrix (35 points)
8 / 12
Overview
A ragged matrix is a matrix whose rows may not have the same number of columns. A sparse
matrix is a matrix that contains many zeroes. We may not want all the zeroes. Your goal is to
turn a non-ragged matrix into a ragged non-sparse matrix, which is a ragged matrix that doesn’t
contain any zeroes.
Requirements
Write the function int* RaggedNonSparseMatrix(int**& matrix, int numRows,
int numCols);
This function should transform matrix into a ragged non-sparse matrix. You will need to return
an integer array indicating the new sizes of all rows.
● Use row-major ordering when working with your 2D array.
●
You must resize the array.
●
You cannot have any memory errors or memory leaks
●
Throw an instance of std::invalid_argument (with whatever error message you want) if any
of the following is true:
●
○
arr is nullptr
○
numRows is 0
○
numCols is 0
You may not use any libraries besides stdexcept
Examples
●
●
If RaggedNonSparseMatrix(matrix, numRows, numCols) is called with
○ matrix
■ 1 0 0 1
5 2 1 0
3 2 4 5
○ numRows is 3
○ numCols is 4
After calling the function
○ matrix
■ 1 1
5 2 1
3 2 4 5
○ The function returns the array
■ 2 3 4
Name:___________________________________________
Q2 Answer (Ragged Non-Sparse Matrix)
9 / 12
int* RaggedNonSparseMatrix(int**& matrix, int numRows, int numCols)
Name:___________________________________________
Q3 - Prioritize 3s (35 points)
10 / 12
Overview
Given a linked list, move to the front all nodes whose values are divisible by 3
Requirements
Write the function void prioritize3s(LinkedList& l). This function should traverse a
linked list of integers and find all nodes whose value is divisible by 3. Then, the function should
move those nodes to the beginning of the linked list.
● The argument l should be modified by this function.
● Add nodes to the beginning of the list as soon as you find them while traversing the list
○ This means that when the function returns, the first node of the list will be the last
node from the original list which was divisible by 3
● You must not have any memory errors or leaks
● You may not use any libraries
Assume the following definition for LinkedList:
struct Node {
int data;
Node* next;
Node(int data, Node* next) : data(data), next(next) {}
}
class LinkedList {
private:
Node* head;
public:
LinkedList() : head(nullptr) {}
//Assume rule of 3 is implemented correctly
~LinkedList();
LinkedList(const LinkedList& other);
operator=(const LinkedList& other);
Node* getHead() { return head; }
void setHead(Node* node) { head = node; }
}
//Write this function
void prioritize3s(LinkedList& l)
See the next page for examples
Name:___________________________________________
11 / 12
Examples
Input list: 14 -> 22 -> 3 -> 32 -> 42 -> 4
First, 3 is moved to the front, since 3 is divisible by 3: 3 -> 14 -> 22 -> 32 -> 42 -> 4
Then 42 is moved to the front, because 42 is also divisible by 3
List after calling prioritize3s: 42 -> 3 -> 14 -> 22 -> 32 -> 4
Input list: 23 -> 27 -> 61 -> 36 -> 51 -> 14
List after calling prioritize3s: 51 -> 36 -> 27 -> 23 -> 61 -> 14
Input list: 3 -> 6 -> 12 -> 24 -> 0
List after calling prioritize3s: 0 -> 24 -> 12 -> 6 -> 3
Input list: empty linked list
List after calling prioritize3s: empty linked list
Name:___________________________________________
Q3 Answer (Prioritize 3s)
void prioritize3s(LinkedList& l)
12 / 12