CSE 109 Final Examination   Thursday  15 December 2005
<<<<<<<<<<<<<<<<<<<<<<<<<<<<SUGGESTED ANSWERS>>>>>>>>>>>>>>>>>>>>>>>>>>
1.  Write a C program (compiled with "gcc -xc") similar to the unix "cp"
command.  In particular, it should take (demand) two arguments, the first
the name of the (text) file to be copied, the second the name of the file
to contain the copy. For example, if the executable file is stored in
"a.out" then the command
   a.out x y
should create in the file 'y' a copy of the file 'x', provided the file
'x' exists.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <stdio.h>

void check(int b,char *mess,char *m1, char *m2);

int main(int ct,char **arg)
{FILE *fin,*fout;
 char ch;
 check(ct==3,"Usage: ",arg[0]," <input> <output>");
 fin=fopen(arg[1],"r");
 check(fin!=NULL,"Failure to open the input file '",arg[1],"'");
 fout=fopen(arg[2],"w");
 check(fout!=NULL,"Failure to open the output file '",arg[2],"'");
 ch=getc(fin);
 while(ch!=EOF)
 {putc(ch,fout);
  ch=getc(fin);
 }
 fclose(fout);
}

void check(int b,char *mess,char *m1, char *m2)
{if(!b)
  {printf("ERROR: %s%s%s\n",mess,m1,m2);
   exit(1);
  }
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
2.  Assume that the binary file 'final.dat' contains 10 blocks of data,
with each block created from the struct below. Write a C program
(compiled with "gcc -xc") that prompts the user for the number of a block
and responds by displaying the contents of the struct stored at that
block, if the block number is legitimate, where the blocks are numbered
0, 1, 2, ..., 9.
  struct ABlock
  {int a;
   double b;
  }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <stdio.h>

struct ABlock
{int a;
 double b;
};

void check(int b,char *mess);

int main()
{FILE *fin;
 struct ABlock dat;
 int block;
 fin=fopen("final.dat","rb");
 check(fin!=NULL,"Failure to open 'final.dat'");
 printf("Enter the number of the block- ");
 scanf("%d",&block);
 check(block>=0 && block<=9,"Bad block number entered");
 fseek(fin,block*sizeof(struct ABlock),SEEK_SET);
 fread(&dat,sizeof(struct ABlock),1,fin);
 printf(" a = %d, b = %f\n",dat.a,dat.b);
}

void check(int b, char *mess)
{if(!b)
  {fprintf(stderr,"ERROR: %s\n",mess);
  exit(1);
  }
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
3.  We normally think of a point as a pair of ints (or doubles), but we could
generalize the idea to a pair where the first member of the pair is of one
type and the second member of the pair is of a second type.  Write a
template (the declaration and code) for a class called Point whose instances
have variables of different types for the two entries. Below is code that
should compile and produce the indicated output, given your template.  Your
template need only have the necessary declarations to enable the code below
to compile and run correctly.
  Point <bool,char> p(true,'a');
  cout<<p<<endl;     //OUTPUT: (1,a)
                     //NOTE: "cout<<true<<false" displays 10
  p.setX(false).setY('q');
  cout<<p<<endl;     //OUTPUT:  (0,q)
  Point <double, Point<bool,char> > r(7.3,p);
  cout<<r<<endl;     //OUTPUT:  (7.3, (0,q))
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <fstream.h>

template <class X, class Y>
class Point
{public:
  Point(const X & a, const Y & b);
  Point & setX(const X &a);
  Point& setY(const Y &b);
  template <class A, class B>
  friend ostream & operator << (ostream & out,const Point<A,B> & p);
private:
  X x;
  Y y;
};

template <class X, class Y>
Point<X,Y>::Point(const X & a, const Y & b):x(a), y(b){}

template <class X, class Y>
Point<X,Y> &Point<X,Y>::setX(const X &a){x=a; return *this;}

template <class X, class Y>
Point<X,Y>& Point<X,Y>::setY(const Y & b){ y=b; return *this;}

template <class X, class Y>
ostream & operator << (ostream & out, const Point<X,Y> &p)
{out<<"("<<p.x<<", "<<p.y<<")";
 return out;
}

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
4.  Below is the declaration for the class List, which is meant to maintain
a list of integers.  Write the declaration and definitions (code) for a
sublcass, MyList, that adds the method sort(), which sorts the list in
ascending order, and the operator +=, which adds an int to the end of the
list.  With your class, the sample code should compile and produce the
indicated output.
 class List
 {public:
    List(int n=100);  //a list of n entries; error if n<1
    void add(int n);  //add n to the end of the list
    int length()const;  //number of entries in list
    int capacity()const;  //maximum number of entries
    int & at(int n);   //get entry at location n
    static void check(bool b, char *mess);
  private:
    int *data;
    int max,       //maximum number of items in list
         count;   //number of items in list
};

MyList p(20);
for(int j=0; j<5; j++)
   p+=(j-2)*(j-2);
p.sort();
for(int j=0; j<5; j++)
  cout<<p.at(j)<<" ";   //OUTPUT:  0 1 1 4 4
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <fstream.h>
class MyList: public List
{public:
  MyList(int n=100);
  void sort();
  MyList & operator +=(int n);
private:
  void swap(int &a, int &b,bool &c);
};

MyList::MyList(int n):List(n){}

MyList & MyList::operator +=(int n)
{add(n);
 return *this;
}

void MyList::sort()
{bool sorted;
 do
   {sorted=true;
   for(int j=1; j<length(); j++)
     if(at(j-1)>at(j))
       swap(at(j-1),at(j),sorted);
   }
 while(!sorted);
}

void MyList::swap(int & a, int &b,bool &c)
{int temp;
 temp=a;
 a=b;
 b=temp;
 c=false;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
5.  Write an EASY program that reads in two numbers, assumed to be positive,
and displays 1 if the first number evenly divides the second number and
displays 0 otherwise, e.g., if the first number is 4 and the second is 13,
then 0 is displayed, because 13/4 has a remainder of 1.
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
x
y
begin
 read x
 read y
 if y/x*x==y goto one
 write 0
 halt
one:
 write 1
 halt
end
 4
13
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
6. Write the MACH1 code that corresponds to the EASY program below. Recall
   MACH1 operators: read(0), write(1), load(2), store(3), clear(4), add(5),
   sub(6), mult(7), div(8), addi(9), subi(10), multi(11), divi(12),
   jumpl(13), jumpg(14), halt(15).

    x
    begin
      read x
      write (x-4)+(x-3)*(x-2)
      halt
    end
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
0 0   0  read
3 14    1  store x
2 14    2  load x
10 4  3   x-4
3 511 4   push x-4
2 14    5   load x
10 3  6    x-3
3 510 7   push x-3
2 14    8   load x
10 2  9     x-2
7 510 10     (x-3)*(x-2)
5 511 11    (x-4)+(x-3)*(x-2)
1  0  12    write result
15 0  13    halt
0 0   14    x
E
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
7.  Write a class Lex that acts as a lexical analyzer for the list of
arguments appearing on the command line, where the items in the language are
"{", "}", ",", "...",  and IDENT (any string of lower case letters).  The
analyzer should return one of the Lex constants IDENT (0), LBRACK (1),
RBRACK (2), COMMA(3), ELLIPSES(4),  and JUNK (5).  The code below indicates
how the class could be used.
    int main(int ct,char **arg)
    {Lex lex(ct,arg);
     char *toks[]={"IDENT", "LEFTBRACKET", "RIGHTBRACKET", "COMMA", "ELLIPSES",
        "JUNK"};
     cout<<"Here are the tokens on the command line:\n";
     while(lex.hasNext())
       cout<<toks[lex.next()]<<endl;
    }
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
#include <fstream.h>

class Lex
{public:
  static const int IDENT=0, LBRACK=1, RBRACK=2, COMMA=3, ELLIPSES=4,
    JUNK=5;
  Lex(int ct, char**arg);
  bool hasNext();
  int next();
private:
  int count,loc;
  char **list;
};

Lex::Lex(int ct, char **arg):count(ct),loc(1),list(arg){}

bool Lex::hasNext(){return loc<count;}

int Lex::next()
{char *vals[]={"", "{", "}", ",", "..."};
 int n;
 if(loc>=count)
   return JUNK;
 n=loc;
 loc++;
 if(list[n][0]>='a' && list[n][0]<='z')//check for all lower case letters
   {int k=1;
   while(list[n][k]!='\0' && list[n][k]>='a' && list[n][k]<='z')
     k++;
   if(list[n][k]=='\0')
     return IDENT;
   return JUNK;
   }
 for(int j=1; j<5; j++)
   if(strcmp(list[n],vals[j])==0)
     return j;
 return JUNK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
8.  Below is the contents of the file enigma.cc.  Write the output that is
displayed on the screen when enigma.cc is compiled and run.
#include <stdio.h>
class A
{public:
   A(int n=0):x(n){}
   void a(){printf("A::a()\n");}
   void b(){a(); c();}
   virtual void c(){printf("A::c()\n");}
   int x;
};

class B : public A
{public:
  B(int n=0):A(n){}
  void a(){printf("B::a()\n");}
  void c(){printf("B::c()\n");}
};

void foo(A*x,A*y)
{x->x++;
 y->x++;}

void bar(B*x,B y)
{y.x++;
 x->x++;
}

int main()
{A a(42);
 B b;
 a.b();
 b.a();
 b.b();
 printf("%s\n",b.x>0?"positive":"correct");
 foo(&a,&a);
 printf("%d\n",a.x);
 bar(&b,b);
 printf("%d\n",b.x);
}
<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
A::a()
A::c()
B::a()
A::a()
B::c()
correct
44
1
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
