CSCI 159 Bonus lab exercises

The bonus lab is an independent exercise (we won't be specifically covering it in the labs), and is due by 11:59:59pm Friday Dec. 5th

Unlike previous labs, there is only a single exercise for the bonus lab, to be completed in bonus.cpp.

Here is the collection of new C++ syntax elements we'll be using for the bonus lab.

We'll also be working with code elements from nearly all the labs so far, so refer to the appropriate lab syntax page as needed for refreshers.


Follow our usual setup process

CORRECTION Apologies, I didn't realize I'd missed putting the bonus section into the make159 file. You'll need to do a little extra to obtain the bonus lab. From your home directory enter the following sequence of commands exactly the way they're shown here:
cd  csci159
ssh  csci  fork  csci159-12/bonus  csci159-12/$USER/bonus
git  clone  csci:csci159-12/$USER/bonus
Everything else will work normally after that (make bonusx, make submit, etc).

  1. Log in, open a browser, go to the bonus lab page, open a terminal window:
    (see lab 2 if you need a refresher on any of the steps)

  2. get the bonus lab:

  3. Go into your newly created bonus directory and begin the edit/compile/test/submit routine: As with previous labs, you'll see that the .cpp file is nearly empty to start with.


Design exercise (to be done in bonus.cpp)

The overall purpose of the bonus lab will be to get practical experience working with pointers for dynamic allocation and deallocation (new and delete) and to practice using pointers to structs.

The program itself is an extension/revision of lab6.cpp, so be sure you've finished lab6 before tackling bonus.cpp. To copy across your lab6.cpp into your bonus.cpp, do the following (after obtaining the bonus lab with the usual make -f command):
    cd
    cd  csci159/bonus
    cp  ../lab6/lab6.cpp  bonus.cpp
The bonus.cpp should now contain a copy of your lab6 code, which will be a good starting point for the rest of the bonus lab.

From a user perspective, the functionality of our bonusx executable will be the same as in lab6x: if they run the two programs the behaviour will appear the same.

The difference is that our storage array will no longer be an array of structs, instead it will be an array of pointers to structs. Actual package structs will be created as part of the insert process and deleted as part of the remove process, which means that at any given moment we'll only be storing as many structs as are actually in the queue, rather than every element of the array being a full struct. (Though it does introduce the extra memory overhead of one pointer per array element.)

This kind of approach is not unusual in programs where individual structs are significantly bigger than a pointer and where the number of structs stored varies quite a bit over the entire run of the program: giving us a smaller memory footprint on average.

In terms of revising the actual code, this requires us to make a variety of syntax changes across the functions that work with the structs and the array that holds (the pointers to) them.

An outline of the changes you'll need to make (compared to a correct lab6.cpp solution) is shown function-by-function here (and can be found in changes.cpp in your bonus repo):


// ====================================================================================
// ========== package definition and function prototypes ==============================
// ====================================================================================

struct Package {
   string sender;
   string recipient;
   string content;
   string address;
   float value;
};

// note that p is now a pointer to a package
void fillPkg(Package *p);

// note that p is now a pointer to a package
void printPkg(Package *p);

// ====================================================================================
// ========== queue definition and function prototypes ================================
// ====================================================================================

const int MaxPackages = 4;

struct Queue {
    Package* pkgArray[MaxPackages]; // now this is an array of pointers for packages
    int front;
    int back;
    int size;
};

void initQ(Queue &q);

int getSizeQ(Queue q);

// note the package parameter is now a pointer to a package
bool insertQ(Package *p, Queue &q);

// note the package parameter is now a pointer, passed by reference
bool removeQ(Package* &p, Queue &q);

void printQ(Queue q);

// ====================================================================================
// ========== command-handling definitions and function prototypes ====================
// ====================================================================================

const char Help = 'H';
const char Quit = 'Q';
const char Insert = 'I';
const char Remove = 'R';
const char Size = 'S';
const char Print = 'P';
const char Error = 'E';

void commandHelp();

char getCommand();

void processCommand(char command, Queue &Q);

// ====================================================================================
// ========== main routine ==========================================================
// ====================================================================================
int main()
{
   // no changes needed from lab6.cpp
}

// ====================================================================================
// ========== command-handling function implementations ===============================
// ====================================================================================

void commandHelp()
{
   // no changes needed from lab6.cpp
}

char getCommand()
{
   // no changes needed from lab6.cpp
}

void processCommand(char command, Queue &Q)
{
   // three changes needed:
   //   1. pkg declaration now needs to use *pkg, so it's a pointer
   //   2. before we actually call fillPkg during the insert
   //      we need to allocate memory for a new package, e.g.
   //         pkg = new Package
   //   3. after we've printed the package content in a successful remove
   //      we need to deallocate the package's memory, e.g.
   //         delete pkg
}


// ====================================================================================
// ========== package function implementations ======================================
// ====================================================================================

float getValue()
{
   // no changes needed from lab6.cpp
}

void fillPkg(Package *p)
{
   // like fillPkg from lab6.cpp, but
   //    1. print an error message and return if p == nullptr
   //    2. we use p-> instead of p.
}

void printPkg(Package *p)
{
   // like fillPkg from lab6.cpp, but
   //    1. print an error message and return if p == nullptr
   //    2. we use p-> instead of p.
}


// ====================================================================================
// ========== queue function implementations ========================================
// ====================================================================================

void initQ(Queue &q)
{
   // no changes needed from lab6.cpp
}


int getSizeQ(Queue q)
{
   // no changes needed from lab6.cpp
}


bool insertQ(Package *p, Queue &q)
{
   // no changes needed from lab6.cpp
   return true;
}


bool removeQ(Package* &p, Queue &q)
{
   // no changes needed from lab6.cpp
   return true;
}


void printQ(Queue q)
{
   // no changes needed from lab6.cpp
}