CS 434 Exam 3 Solution Spring 2004

Problem Points Notes 1 21 2 17 3 24 Some C++ compilers generate code that evaluates function parameters in left-to-right order, and others generate code that evaluates parameters right-to-left. Both solutions are acceptable. 4 18 5 15 6 15 For part a., use any sequence such that *r  0 and *r < *q. For part b., use any sequence such that *r  0 and *r  *q. 7 18 This program implements insertion sort without using an array. Instead, the values to be sorted are stored on the runtime stack and accessed using a combination of recursion and nonlocal references. Total 128 1. Convert this Triangle program to an equivalent TAM program.

let var a:Integer; var b:Integer; var c:Integer in begin getint(var b); getint(var c); a:=(b–8)*(c+5); putint(a*a) end

0: PUSH 1 ; a 1: PUSH 1 ; b 2: PUSH 1 ; c 3: LOADA 1[SB] ; b 4: CALL getint 5: LOADA 2[SB] ; c 6: CALL getint 7: LOAD (1) 1[SB] ; b 8: LOADL 8 9: CALL sub ; b–8 10: LOAD (1) 2[SB] ; c 11: LOADL 5 12: CALL add ; c+5 13: CALL mult ; (b–8)*(c+5) 14: STORE (1) 0[SB] ; a 15: LOAD (1) 0[SB] ; a 16: LOAD (1) 0[SB] ; a 17: CALL mult ; a*a 18: CALL putint 19: POP (0) 3 20: HALT 2. Show the runtime stack contents for this Triangle program just before returning from the deepest level of recursion. Use the input value 80.

let var b:Integer; func g(z:Integer):Integer ~ if z>1 then z-1+g(z/3) else 5 in begin getint(var b); putint(g(b+1)) end

Address Contents 0 global b=80 1 parameter=81 2 dynamic link=0 3 static link=0 4 return address 5 z–1=80 6 parameter=27 7 dynamic link=2 8 static link=0 9 return address 10 z–1=26 11 parameter=9 12 dynamic link=7 13 static link=0 14 return address 15 z–1=8 16 parameter=3 17 dynamic link=12 18 static link=0 19 return address 20 z–1=2 21 parameter=1 22 dynamic link=17 23 static link=0 24 return address 25 5 3. Write the output of this C++ program in the box to the right. void print (string s) { cout << s << endl; } Visitor class Node { BinaryOp public: virtual int visit (Visitor *) = 0; }; visitBinaryOp class Visitor { BinaryOp public: virtual int visit (Node *node) visitBinaryOp { print("Visitor"); return node–>visit(this); } BinaryOp virtual int visitLeaf (Leaf *) = 0; visitBinaryOp virtual int visitBinaryOp (BinaryOp *) = 0; }; Leaf class Leaf: public Node { visitLeaf public: int value; Leaf Leaf (int i): value (i) { } visitLeaf virtual int visit (Visitor *v) Multiply { print("Leaf"); return v->visitLeaf(this); } }; Leaf class BinaryOp: public Node { visitLeaf public: Node *left, *right; Add BinaryOp (Node *l, Node *r): left (l), right (r) { } BinaryOp virtual int visit (Visitor *v) visitBinaryOp { print("BinaryOp"); return v->visitBinaryOp(this); } virtual int fun (int, int) = 0; Leaf }; visitLeaf class Evaluator: public Visitor { Leaf public: virtual int visitLeaf (Leaf *node) visitLeaf { print("visitLeaf"); return node->value; } Subtract virtual int visitBinaryOp (BinaryOp *node) { print("visitBinaryOp"); Divide return node->fun(node->left->visit(this), 41 node->right->visit(this)); } or: }; Visitor class Add: public BinaryOp { BinaryOp public: Add (Node *l, Node *r): BinaryOp (l, r) { } virtual int fun (int left, int right) visitBinaryOp { print("Add"); return left+right; } BinaryOp }; visitBinaryOp class Subtract: public BinaryOp { Leaf public: Subtract (Node *l, Node *r): BinaryOp (l, r) { } visitLeaf virtual int fun (int left, int right) { print("Subtract"); return left-right; } Leaf }; visitLeaf class Multiply: public BinaryOp { Subtract public: Multiply (Node *l, Node *r): BinaryOp (l, r) { } BinaryOp virtual int fun (int left, int right) visitBinaryOp { print("Multiply"); return left*right; } }; Leaf class Divide: public BinaryOp { visitLeaf public: Divide (Node *l, Node *r): BinaryOp (l, r) { } BinaryOp virtual int fun (int left, int right) visitBinaryOp { print("Divide"); return left/right; } Leaf }; void main ( ) { visitLeaf Node *w=new Multiply (new Leaf (8), new Leaf (9)); Leaf Node *x=new Add (w, new Leaf (10)); visitLeaf Node *y=new Subtract (new Leaf (5), new Leaf (3)); Multiply Node *z=new Divide (x, y); Add Evaluator * evaluator = new Evaluator; Divide cout << evaluator->visit (z) << endl; } 41 4. Consider again the C++ program from problem 3. For each of the nine classes, draw the class object (method table).

N Node 0 Node::Node (default) visit 0 Visitor::Visitor (default) NV Visitor 0 NV visit 01 Visitor::visit N0 visitLeaf 0 N0 visitBinaryOp 0 Leaf::Leaf

NL Leaf 0 Leaf::visit NL visit 01 BinaryOp::BinaryOp NB BinaryOp 0 NB visit 01 BinaryOp::visit N0 fun 0 Evaluator::Evaluator (default) NE Evaluator 0 NV visit 01 Evaluator::visitLeaf NE visitLeaf 02 NE visitBinaryOp 03 Evaluator::visitBinaryOp

NA Add 0 Add::Add NB visit 01 NA fun 02 Add::fun

NS Subtract 0 Subtract::Subtract NB visit 01 NS fun 02 Subtract::fun

NM Multiply 0 Multiply::Multiply NB visit 01 NM fun 02 Multiply::fun

ND Divide 0 Divide::Divide NB visit 01 ND fun 02 Divide::fun 5. Consider the C++ declaration below. Assume a byte-addressable machine such that each double uses 8 bytes, each int uses 4 bytes, each char uses 1 byte, and each float uses 4 bytes. Also assume that s[0][0].d[0] is at location 0, and two-dimensional arrays are stored in row-major order.

struct {double d[3]; int i; char c[8]; float f;} s[30][20];

a. Determine the total size in bytes for variable s.

(8*3+4+1*8+4)*30*20=24000

b. Determine the location of s[10][0].c[1]

(8*3+4+1*8+4)*10*20+(8*3+4+1)=8029

c. Determine the location of s[20][5].d[2]

(8*3+4+1*8+4)*(20*20+5)+8*2=16216 6. Consider the C++ program below.

void f(int*& a, int*& b) { if (*a < *b) a=b; else { delete b; b=a; } } void main( ) { int *p, *q, *r; p=q=new int; r=new int; cin >> *q; cin >> *r; if (*r < 0) f(q, r); else f(r, q); cout << *p << endl; cout << *q << endl; cout << *r << endl; }

a. Can any sequence of input values cause a memory leak (garbage)? If so, specify such input values, and draw a picture that clearly represents the situation in the heap just before the program ends.

Yes, consider this input sequence: 2 1.

2 1 garbage

p q r

b. Can any sequence of input values cause a dangling pointer? If so, specify such input values, and draw a picture that clearly represents the situation in the heap just before the program ends.

Yes, consider this input sequence: 1 2.

1 deleted 2

dangling p q r

c. Very briefly state how some programming languages (not C++) prevent both memory leaks and dangling pointers.

Garbage collection. 7. Write the output of this Triangle program in the box to the right. Use this input: 3 6 9 2 5 8 1 4 7 0 let proc copy (x:Integer, var y:Integer) ~ 3 begin 3 6 putint(x); y:=x; 3 6 9 end; 2 proc doit (proc p(x:Integer, var y:Integer)) ~ 2 3 5 let var n:Integer; proc check(i:Integer, var j:Integer) ~ 2 3 5 6 8 begin 1 if i<=n then begin 1 2 3 4 j:=i; 1 2 3 4 5 6 7 putint(j); put(' '); end 1 else begin 2 j:=n; 3 putint(j); put(' '); 4 p(i, var n); 5 end; 6 end in begin ! body of proc doit 7 puteol( ); 8 getint(var n); 9 if n>0 then begin p(n, var n); doit(proc check); putint(n); puteol( ); end else puteol( ); end in doit(proc copy);