Hong Kong University of Science and Technology COMP104: Programming Fundamentals and Methodology Fall 2003, Lecture Section 1, 2 Final Examination Wednesday 17 December, 4:30 – 7:30PM Student Name: Student ID: Lecture Section: key Lab Section/TA Name: Instructions: 1. This is a closed-book, closed-notes examination. 2. Check that you have all 19 pages (including this cover page). 3. Write your name, student ID, lecture section, lab section/TA name on this page. 4. Please circle your answer. 5. Answer all questions in the space provided. Rough work should be done on the back pages. Question Score 1 /6 2 /5 3 /4 4 /8 5 /3 6 /5 7 /3 8 /4 9 /8 10 /7 11 /6 12 /10 13 /4 14 /17 15 /10 Total /100 1 Questions 1 & 2 – Pointers Question 1: (6 marks) a) (4 marks) What is the output of the following program? #include <iostream> using namespace std; void main( ){ int a[3] = {1, 3, 5 }, b = 23, c = 48; int *p1 = a, *p2 = &b, *p3 = 0; p1++; (*p1)++; p3 = p2; *p3 = p1[1]; for(int i = 0; i < 3; i++) cout << a[i]; cout << endl; cout << b << endl; } Answer: 145 (1 mark for each digit) 5 b) What is the output of the following program? (2 marks) #include <iostream> using namespace std; void swap(int* left, int* right) { int* p; p = left; left = right; right = p; } void main( ){ int a = 3, b = 5; swap(&a, &b); cout << a << " " << b << endl; } Answer: 3 5 (1 mark each) 2 Question 2: (5 marks) Please fill the blank part of the following code. Your task is to store the data of 2D array A to 1D array P. Important: You must use pointer arithmetic to access the values of P instead of subscripts. #include <iostream> using namespace std; const int m = 3; const int n = 5; void main( ){ int A[m][n] = { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10}, {11, 12, 13, 14, 15} }; int i, j; int * P = new int[m * n]; // Store the data of 2D array a[3][5] to 1D array P[15] // Add your code below // -----------------------------------------for(i = 0; i < m*n; i++) cout << P[i] << " "; cout << endl; } Answer: for(i = 0; i < m; i++) for(j = 0; j < n; j++) *(P + i*n + j) = A[i][j]; -1 for each mistake , -2 if P[i*n+j] = A[i][j] -2 if the arithmetic formula P+i*n+j is incorrect 3 Questions 3 & 4 – Dynamic Objects Question 3: (4 marks) What is wrong with the following code? #include <iostream> using namespace std; 1 int main() { 2 int a = 5, *p = &a; 3 int *q = new int ; 4 *q = *p; 5 cout << a << “ “ << *p << “ “ << *q; 6 delete p; 7 return 0; 8 } Answer: 2 marks - The memory unit pointed by p is not dynamically allocated, so “delete p” (line 6) is wrong. 2 marks - We should delete the memory unit allocated by q to avoid memory leak, so “delete q” is necessary before “return 0” (line 7). Or a direct correction is also allowed: Replace “delete p” with “delete q”. 4 Question 4: (8 marks) Write a function that given a POSITIVE integer, returns a pointer to an integer array with the following properties: 1. The size of the array is equal to the length of this integer. 2. Each element in the array contains a digit of this integer. 3. The storage order should be like this: the most significant digit is stored in the 0th position of the array, the second most significant digit is stored in the 1st position of the array, …, the least significant digit is stored in the last position of the array. For example, given 14582, your function should return a pointer to an array {1, 4, 5, 8, 2}. The function prototype is given here: int* decompose(int num); Hint: Use dynamic objects and assume memory allocation is always successful. Answer: int* decompose (int num) { int result = num; int count = 1; // Find count – 3 marks while (result >= 10) { result /= 10; count ++; } int *p = new int[count]; // allocate dynamic array – 1 marks result = num; // set array values – 3 marks for (int i = 0; i < count; i++) { p[count-1-i] = result % 10; // -2 if reversed: p[i] = result%10 result /= 10; } return p; // return result - 1 mark } also: -4 if returns pointer to static local array 5 Question 5 & 6 – Struct Question 5: (3 marks) Find the errors in the following code. Give the line number and error description. 1 struct S1 { 2 int a; 3 S2 b; 4 }; 5 struct S2 { 6 int a; 7 S1 b; 8 S2 c; 9 }; 10 S2 s = 3; Answer: Line 3 : member b uses struct 'S2' before it is defined Line 8 : recursive definition of S2 not allowed Line 10 : assigning an integer value to a variable of type struct S2 is illegal 6 Question 6: (5 marks) Given the following declaration and definitions: #include <string> struct St_StudentName{ string EnglishName; string ID; }; struct St_StudentScore{ string ID; int score; }; St_StudentName stu1[100]; St_StudentScore stu2[100]; The array stu1 contains a list of all the students’ EnglishNames and IDs. The array stu2 contains a list of the same students (possibly in a different order) with their IDs and scores. Complete the following code segment to output the score of all students with the name “Tom” (e.g., the score of “Tom” is output, but the score of “Tommy” is not). for(int i = 0; i < 100; i++){ … // add an if statement here … // add a for statement here … // add an if statement here cout << stu2[j].score << endl; } Answer: for(int i = 0; i < 100; i++){ if(stu1[i].EnglishName == "Tom") for(int j = 0; j < 100; j++) if(stu2[j].ID == stu1[i].ID) // 2 marks // 1 marks // 2 marks cout << stu2[j].score << endl; } 7 Questions 7 to 10 – Linked List Question 7: (3 marks) The following program is supposed to allocate nodes, put them into a linked list, print them out and then destroy them. Fix the bugs in the program. #include <iostream> using namespace std; struct linkedList{ int number; linkedList* next; }; 1 int main() { 2 linkedList* head=NULL; 3 linkedList* current; 4 for(int i=0;i<10;i++){ 5 current = new linkedList; 6 current->number = i; 7 current.next = head; 8 head = current; 9 } 10 while(head->next!=NULL){ 11 cout << head->number << endl; 12 current = head->next; 13 delete current; 14 head = current; 15 } 16 return 0; 17 } Answer: 1 mark: line 7: change to “current->next = head;” 1 mark: line 10: change to “while(head!=NULL){” 1 mark: line 13: change to “delete head;” (or lines 12-14 change to: current = head; head = head->next; delete current; ) 8 Question 8: (4 marks) What is the output of the following program? #include <iostream> using namespace std; struct myList{ int data; myList* next; }; int main() { myList* head; myList* cur; myList* previous=NULL; for(int i=0;i<4;i++){ head=new myList; head->data=0; head->next=previous; for(cur=previous;cur!=NULL;cur=cur->next) head->data+=1+2*cur->data; previous=head; } while(previous!=NULL){ cout<<previous->data<<endl; cur=previous; previous=previous->next; delete cur; } return 0; } Answer: 13 4 1 0 (1 mark each) 9 Question 9: (8 marks) The function below should insert a value as the head of a given UNORDERED linked list. Be careful to first search for the given value. The value is inserted only if it does not exist in the list. If the value exists, the function does nothing. struct linkedList{ int data; linkedList* next; }; The function prototype is given. Implement the function. void insert(linkedList* &head, int value); Answer: void insert(linkedList* &head, int value){ linkedList* cur; for(cur=head; cur!=NULL; cur = cur->next) // 2 marks if(cur->data == value) return; cur = new linkedList; // 1 mark // 1 mark // 1 mark cur->data = value; // 1 mark cur->next = head; // 1 mark head = cur; // 1 mark } (-1 mark for each mistake) 10 Question 10: (7 marks) Write a RECURSIVE function that searches for a given element in an unordered linked list (no marks will be given unless it is recursive). The function should return true if the element is found and false otherwise. The node definition and function prototype are: struct Node { int data; Node *next; }; bool recursiveSearch(Node* Head, int searchElement); Answer: bool recursiveSearch(Node* Head, int searchElement) { if (Head == NULL) // 2 marks return false; else if (Head->data == searchElement) // 2 marks return true; else return recursiveSearch(Head->next, searchElement); // 3 marks } 11 Question 11 – Circular Linked List (6 marks) Below is part of an insertion function for inserting a node at the rear of a circular linked list. Please complete the missing part of this implementation. void insertRear(NodePtr& Rear, int item) { NodePtr New; New = new Node; New->data = item; // answer the missing part using the space below } The node definition is: struct Node { int data; Node *next; }; Answer: if(Rear == NULL){ // insert into empty list – 3 marks Rear = New; Rear->next = Rear; return; } // insert to end of the list - 3 marks New->next = Rear->next; Rear->next = New; Rear = New; 12 Question 12 – Doubly linked list (10 marks) Given an unordered doubly linked list (without dummy head and not circular), where the node is defined as: struct Node { int data; Node* next; Node* prev; }; typedef Node* NodePtr; Write a function void ReverseDoublyLinkedList(NodePtr& pHead) that reverses the given list pHead. Note that: Your function should accept the head pointer of the list and modify the pointers. Your program must be short and simple; Note: marks will be deducted if your program has more than 7 semicolons. The original list is a doubly linked list that does NOT have a dummy head node, therefore it is NOT a circular doubly linked list. 10 20 40 55 70 Head Answer: void ReverseDoublyLinkedList(NodePtr& head) { if(head == NULL) // do nothing empty list return; while(head->next != NULL) { NodePtr temp = head->next; head->next = head->prev; head->prev = temp; head = head->prev; } head->next = head->prev; head->prev = NULL; } OR 13 void ReverseDoublyLinkedList(NodePtr& head) { if(head == NULL) // do nothing empty list return; NodePtr cur = head; while(cur != NULL) { // reverse pointers NodePtr temp = cur->next; cur->next = cur->prev; cur->prev = temp; cur = cur->prev; } while(head->prev != NULL) // move head pointer to other end head = head->prev; } OR void ReverseDoublyLinkedList(NodePtr& head) { if(head == NULL) // do nothing empty list return; NodePtr cur = head; while(cur != NULL) { // reverse pointers NodePtr temp = cur->next; cur->next = cur->prev; cur->prev = temp; head = cur; // move head behind cur cur = cur->prev; } } Marking scheme: Overall scheme: +10 marks if all correct (-1 for each minor bug if nearly all correct) +5 if have swap idea (-1 for each minor bug related to swap) +0 if nothing or long answer Also: -1 if fails for empty list -1 if fails for list with one node -2 if fails to reverse links on last node -1 if Head not reset -1 for each semicolon beyond 7 -1 for each additional unique mistake 14 Question 13 & 14 – Class / ADT Question 13: (4 marks) What is the output of the following program? #include <iostream> using namespace std; class cPoint { public: cPoint(); cPoint(int x1, int y1); int getX(); int getY(); void print(); private: int x; int y; }; cPoint::cPoint(){ x = y = 0; cout << "Default Constructor called" << endl; } cPoint::cPoint(int x1, int y1){ x = x1; y = y1; cout << "Explicit-Value Constructor called" << endl; } void cPoint::print(){ cout << "(" << x << "," << y << ")" << endl; } int cPoint::getX(){ return x; } int cPoint::getY(){ return y; } void sum(cPoint p1, cPoint p2){ cPoint( (p1.getX()+p2.getX()), (p1.getY()+p2.getY()) ).print(); } void main(){ cPoint p1(1,2); cPoint p2; sum(p1,p2); } Answer: Explicit-Value Constructor called // 1 mark each Default Constructor called Explicit-Value Constructor called (1,2) 15 Question 14: (17 marks) A polynomial P(X) = C[0] + C[1]*X1 + … + C[i]*Xi + …+ C[99]*X99 can be represented by the class below (where the highest power of the polynomial is limited to 99): class Polynomial { public: Polynomial(); void set(string n, double *A, int numCoefficients); void display(); int maximum_order() const; Polynomial add(const Polynomial G) const; private: string name; // name of the polynomial double C[100]; // C[i] = coefficients of the term Xi }; For example, assuming an object of type Polynomial T is declared with the name “T1” with C[0], C[1], C[2] set to 1,2,3 respectively and C[j] = 0 for 99 >= j >=3, then T is equivalent to the polynomial T1(x) = 1 + 2*X1 + 3*X2. a) (3 marks) Write the default constructor of this class, where the default name of the polynomial is “F”, and all the coefficients are set as zero. Polynomial::Polynomial() { name = "F"; for (int i=0;i<100;i++) C[i] = 0.0; } 16 b) (4 marks) The program code below is supposed to define P as P(X) = 1 + 2*X1 + 3*X2 double A[ ] = {1,2,3}; Polynomial P; P.set(“P”,A,3); A Comp104 student implements the member function set() as below void set(string n, double *A, int numCoefficients) { int i; name = n; if(numCoefficients <= 100) for(i=0; i<=numCoefficients; i++) C[i] = A[i]; else cout << "The index is too large, exiting program"; exit(0); } Correct the bugs. Answer: // 1 mark - the function should be void Polynomial::set(string n, double *A, int numCoefficients) // 1 mark - should be for(i=0; i < numCoefficients; i++) // 1 mark - C[i] should be set as zero for numCoefficients <= i <= 99. // e.g., add the code below before if(numCoefficients <= 100) for(int j=0;j<100;j++) C[j] = 0; // 1 mark - Add parenthesis (curly brackets) to the else statement 17 c) (7 marks) Write the member function add(). If polynomials p and q are P(x) = -3X + 2*X15 and Q(x) = 7 + 3X - 3*X15 respectively, then r = p.add(q); set r as result(x) = 7 - 1*X15 Polynomial Polynomial::add(const Polynomial G) const { Polynomial result; // 1 mark result.name = "result"; // 1 mark for (int i=0;i<100;i++) // 1 mark result.C[i] = C[i] + G.C[i]; // 3 marks return result; // 1 mark } d) (3 marks) Write the member function maximum_order(), which returns the maximum order of a polynomial. E.g., if polynomial p is P(x) = -3X + 2*X15, p.maximum_order() returns 15. If polynomial q is Q(x) = 100, then q.maximum_order() returns 0. int Polynomial::maximum_order() const { int i; for(i=99;i>0;i--) if (C[i] != 0.0) break; return i; } -1 for each mistake (0 marks if incorrectly starts scanning from beginning of array) 18 Question 15 – Dynamic Class (10 marks) The following models a queue of passengers at a bus stop. The struct Passenger models a passenger waiting for a bus, and the class BusStop models a bus stop. A BusStop has a linked list of passengers. struct Passenger { int waitingTime; // waiting time for passenger at bus stop Passenger *next; // pointer to next passenger }; class BusStop { public: BusStop(); ~BusStop(); void addPassenger(); // call when new passenger arrives & set waitingTime=0 void incrWaitingTimes(); // increment waitingTime of all Passengers by one void pickupPassengers(); int length() const; // call when bus arrives // return number of passengers waiting double averageWaitingTime() const; // calculate avg waiting time of // all passengers currently at bus stop private: Passenger *head; int size; // pointer to linked list of passengers // number of passengers }; BusStop::BusStop () { head = NULL; size = 0; } a) (5 points) Implement the destructor BusStop::~BusStop(). Do not call any other member functions. BusStop::~BusStop () { while(head != NULL) { Passenger *cur = head; head = head->next; delete cur; } } Minor mistake: -1 each +1 if answer only deletes first node of list 0 marks if calls pickupPassengers() 19 b) (5 points) Implement BusStop::averageWaitingTime(). This function returns the average waiting time of passengers currently at the bus stop. double BusStop::averageWaitingTime() const { double time = 0; // either time or size must be double type Passenger *cur = head; while(cur != NULL) { time += cur->waitingTime; cur = cur->next; } if(size==0) // 1 mark return 0; return time / size; } Each minor mistakes -1 mark -3 marks if it destroys head -3 marks if doesn’t access cur->waitingTime -2 marks if both size and time are integers causing integer division -1 if has division by zero when size=0 20