Classes and Dynamic Memory Allocation

Dynamic Memory and Classes



// strng1.h -- string class definition

#ifndef _STRNG1_H_
#define _STRNG1_H_
class String
{
private:
	char * str;				// pointer to string
	int len;				// length of string
	static int num_strings;		// number of objects
public:
	String(const char * s);		// constructor
	String();				// default constructor
	~String();				// destructor
// friend function
	friend ostream & operator<<(ostream & os, const String & st);
};
#endif


// strngs1.cpp -- String class methods

#include <iostream.h>
#include <string.h>
#include "strng1.h"

// initializing static class member
int String::num_strings = 0;

// class methods
String::String(const char * s)		// construct String from C string
{
	len = strlen(s);		// set size
	str = new char[len + 1];	// allot storage
	strcpy(str, s);		// initialize pointer
	num_strings++;			// set object count
	cout << num_strings << ": \"" << str
	       << "\" object created\n";	// For Your Information
}

String::String()				// default constructor
{
	static const char * s = "C++";
	len = strlen(s);
	str = new char[len + 1];
	strcpy(str, s);			// default string
	num_strings++;
	cout << num_strings << ": \"" << str
		<< "\" object created\n";	// FYI
}

String::~String()				// necessary destructor
{
	cout << "\"" << str << "\" object deleted, ";	// FYI
	--num_strings;	// required
	cout << num_strings << " left\n";        	// FYI
	delete [] str;                           	// required
}

ostream & operator<<(ostream & os, const String & st)
{
	os << st.str;
	return os;
}



// vegnews.cpp -- using new and delete with classes

// compile with strngs.cpp
#include <iostream.h>
#include "strng1.h"

String sports("Spinach Leaves Bowl for Dollars");
					// sports an external object
void callme1(void);		// creates local object
String * callme2(void);		// creates dynamic object

int main(void)
{
	cout << "Top of main()\n";
	String headlines[2] =	// local object array
	{
		String("Celery Stalks at Midnight"),     
		String("Lettuce Prey")
	};
	cout << headlines[0] << "\n";
	cout << headlines[1] << "\n";
	callme1();
	cout << "Middle of main()\n";
	String *pr = callme2();	// set pointer to object
	cout << sports << "\n";
	cout << *pr << "\n";		// invoke class method
	delete pr;			// delete object
	cout << "End of main()\n";
	return 0;
}

void callme1(void)
{
	cout << "Top of callme1()\n";
	String grub;                   // local object
	cout << grub << "\n";
	cout << "End of callme1()\n";
}

String * callme2(void)
{
	cout << "Top of callme2()\n";
	String *pveg = new String("Cabbage Heads Home");
			// dynamic object uses constructor
	cout << *pveg << "\n";
	cout << "End of callme2()\n";
	return pveg;			// pveg expires, object lives
}



Trouble in String City



// problem1.cpp -- uses a function with a String argument

// compile with strng1.cpp
#include <iostream.h>
#include "strng1.h"

void showit(String s, int n);
int main(void)
{
	String motto("Home Sweet Home");
	showit(motto, 3);
	return 0;
}

void showit(String s, int n)	// show String s n times
{
	for (int i = 0; i < n; i++)
		cout << s << "\n";
}



// problem2.cpp -- initializes one string to another

// compile with strng1.cpp
#include <iostream.h>
#include "strng1.h"

int main(void)
{
	String motto("Home Sweet Home");
	String ditto(motto);	// initialize ditto to motto

	cout << motto << "\n";
	cout << ditto << "\n";
	return 0;
}


// problem3.cpp -- assigns one object to another

// compile with strng1.cpp
#include <iostream.h>
#include "strng1.h"

int main(void)
{
	String motto("Home Sweet Home");
	String ditto;		// default constructor
	ditto = motto;		// object assignment
	cout << motto << "\n";
	cout << ditto << "\n";
	return 0;
}


// strng2.h -- String class definition

#ifndef _STRNG2_H_
#define _STRNG2_H_
#include <iostream.h>
#include "booly.h"  // our definitions of Bool, False, and True
class String
{
private:
   char * str;                   // pointer to string
   int len;                      // length of string
public:
   String(const char * s);       // constructor
   String();                     // default constructor
   String(const String & st);
   ~String();                    // destructor
   int length () { return len; }
// overloaded operators
   String & operator=(const String & st); // Assignment operator
   String & operator=(const char * s); // Assignment operator #2
// friend functions
   friend Bool operator>(const String &st1, const String &st2);
   friend Bool operator<(const String &st, const String &st2);
   friend Bool operator==(const String &st, const String &st2);
   friend ostream & operator<<(ostream & os, const String & st);
   friend istream & operator>>(istream & is, String & st);
};
#endif


// strng2.cpp -- String class methods

#include <iostream.h>
#include <string.h>
#include "strng2.h"

// class methods

String::String(const char * s)	// make String from C string
{
   len = strlen(s);
   str = new char[len + 1];        // allot storage
   strcpy(str, s);                 // initialize pointer
}

String::String()				// default constructor
{
   len = 0;
   str = new char[1];
   str[0] = '\0';               // default string
}

String::String(const String & st)	// copy constructor
{
	len = st.len;
	str = new char[len + 1];
	strcpy(str, st.str);
}

String::~String()				// destructor
{
   delete [] str;               // required
}

	// assign a String to a String
String & String::operator=(const String & st)
{
	if (this == &st)
		return *this;
	delete [] str;
	len = st.len;
	str = new char[len + 1];
	strcpy(str, st.str);
	return *this;
}

	// assign a C string to a String
String & String::operator=(const char * s)
{
	delete [] str;
	len = strlen(s);
	str = new char[len + 1];
	strcpy(str, s);
	return *this;
}

	// true if st1 follows st2 in collating sequence
Bool operator>(const String &st1, const String &st2)
{
	if (strcmp(st1.str, st2.str) > 0)
		return True;
	else
		return False;
}

	// true if st1 precedes st2 in collating sequence
Bool operator<(const String &st1, const String &st2)
{
	if (strcmp(st1.str, st2.str) < 0)
		return True;
	else
		return False;
}

	// true if st1 is the same as st2
Bool operator==(const String &st1, const String &st2)
{
	if (strcmp(st1.str, st2.str) == 0)
		return True;
	else
		return False;
}

	// display string
ostream & operator<<(ostream & os, const String & st)
{
	os << st.str;
	return os;
}

	// quick and dirty String input
istream & operator>>(istream & is, String & st)
{
	char temp[80];
	is.getline(temp, 80);
	if (is)
		st = temp;
	return is;
}



// sayings1.cpp -- uses expanded string class

// compile with strng2.cpp
#include <iostream.h>
#include "strng2.h"
const ArSize = 10;
const MaxLen = 81;
int main(void)
{
	String name;
	cout <<"Hi, what's your name?\n>> ";
	cin >> name;
	
	cout << name << ", please enter up to " << ArSize
		<< " short sayings :\n";
	String sayings[ArSize];		// array of objects
	char temp[MaxLen];		// temporary string storage
	for (int i = 0; i < ArSize; i++)
	{
		cout << i+1 << ": ";
		cin.getline(temp, MaxLen);
		if (temp[0] == '\0')	// empty line?
			break; 				// i not incremented
		else
			sayings[i] = temp;	// overloaded assignment
	}
	int total = i;				// total # of lines read

	cout << "Here are your sayings:\n";
	for (i = 0; i < total; i++)
		cout << sayings[i] << "\n";

	int shortest = 0;
	int first = 0;
	for (i = 1; i < total; i++)
	{
		if (sayings[i].length() < sayings[shortest].length())
			shortest = i;
		if (sayings[i] < sayings[first])
			first = i;
	}
	cout << "Shortest saying:\n" << sayings[shortest] << "\n";
	cout << "First alphabetically:\n" << sayings[first] << "\n";
	return 0;
}


// sayings2.cpp -- uses pointers to objects

// compile with strng2.cpp
#include <iostream.h>
#include <stdlib.h>	// for rand(), srand()
#include <time.h>		// for time()
#include "strng2.h"
const ArSize = 10;
const MaxLen = 81;
int main(void)
{
	String name;
	cout <<"Hi, what's your name?\n>> ";
	cin >> name;
	
	cout << name << ", please enter up to " << ArSize
		<< " short sayings :\n";
	String sayings[ArSize];
	char temp[MaxLen];		// temporary string storage
	for (int i = 0; i < ArSize; i++)
	{
		cout << i+1 << ": ";
		cin.getline(temp, MaxLen);
		if (temp[0] == '\0')	// empty line?
			break; 				// i not incremented
		else
			sayings[i] = temp;	// overloaded assignment
	}
	int total = i;				// total # of lines read

	cout << "Here are your sayings:\n";
	for (i = 0; i < total; i++)
		cout << sayings[i] << "\n";

// use pointers to keep track of shortest, first strings
	String * shortest = &sayings[0];  // initialize to first object
	String * first = &sayings[0];
	for (i = 1; i < total; i++)
	{
		if (sayings[i].length() < shortest->length())
			shortest = &sayings[i];
		if (sayings[i] < *first)	// compare values
			first = &sayings[i];	// assign address
	}
	cout << "Shortest saying:\n" << * shortest << "\n";
	cout << "First alphabetically:\n" << * first << "\n";

	srand(time(0));
	int choice = rand() % total;	// pick index at random
// use new to create, initialize new String object
	String * favorite = new String(sayings[choice]);
	cout << "My favorite saying:\n" << *favorite << "\n";
	delete favorite;
	return 0;
}



A Queue Simulation



// queue.h -- interface for a queue

#ifndef _QUEUE_H_
#define _QUEUE_H_
#include "booly.h"  // our definitions of Bool, False, and True
// This queue will contain Customer items
class Customer
{
private:
	long arrive;		// arrival time for customer
	int processtime;	// processing time for customer
public:
	Customer() { arrive = processtime = 0; }
	void set(long when);
	long when() const { return arrive; }
	int ptime() const { return processtime; }
};

typedef Customer Item;

class Queue
{
// class scope definitions
	// Node is a nested structure definition local to this class
	struct Node { Item item; struct Node * next;};
	enum {Q_SIZE = 10};
private:
	Node * front;		// pointer to front of Queue
	Node * rear;		// pointer to rear of Queue
	int items;		// current number of items in Queue
	const int qsize;	// maximum number of items in Queue
	Queue(const Queue & q) : qsize(0) { }	// preemptive definition
	Queue & operator=(const Queue & q) { return *this;}
public:
	Queue(int qs = Q_SIZE);	// create queue with a qs limit
	~Queue();
	Bool isempty() const;
	Bool isfull() const;
	int queuecount() const;
	Bool enqueue(const Item &item);	// add item to end
	Bool dequeue(Item &item);		// remove item from front
};
#endif



// queue.cpp -- Queue and Customer methods

#include "queue.h"
#include <stdlib.h> 		// for rand()

// Queue methods
Queue::Queue(int qs) : qsize(qs)
{
	front = rear = NULL;
	items = 0;
}

Queue::~Queue()
{
	Node * temp;
	while (front != NULL)	// while queue is not yet empty
	{
		temp = front;		// save address of front item
		front = front->next;// reset pointer to next item
		delete temp;		// delete former front
	}
}

Bool Queue::isempty() const
{
	return items == 0 ? True : False;
}

Bool Queue::isfull() const
{
	return items == qsize ? True : False;
}

int Queue::queuecount() const
{
	return items;
}

// Add item to queue
Bool Queue::enqueue(const Item & item)
{
	if (isfull())
		return False;
	Node * add = new Node;	// create node
	if (add == NULL)
		return False;		// quit if none available
	add->item = item;		// set node pointers
	add->next = NULL;
	items++;
	if (front == NULL)		// if queue is empty,
		front = add;		// place item at front
	else
		rear->next = add;	// else place at rear
	rear = add; 			// have rear point to new node
	return True;
}

// Place front item into item variable and remove from queue
Bool Queue::dequeue(Item & item)
{
	if (front == NULL)
		return False;
	item = front->item;		// set item to first item in queue
	items--;
	Node * temp = front;		// save location of first item
	front = front->next;		// reset front to next item
	delete temp;			// delete former first item
	if (items == 0)
		rear = NULL;
	return True;
}

// customer method

// when is the time at which the customer arrives
// the arrival time is set to when and the processing
// time set to a random value in the range 1 - 3
void Customer::set(long when)
{
	processtime = rand() % 3 + 1;
	arrive = when;
}



// bank.cpp -- use the Queue interface

#include <iostream.h>
#include <stdlib.h>	// for rand() and srand()
#include <time.h>	// for time()
#include "queue.h"
const int MIN_PER_HR = 60;

Bool newcustomer(double x);		// is there a new customer?

int main(void)
{
// setting things up
	srand(time(0));			//  random initializing of rand()

	cout << "Case Study: Bank of Heather Automatic Teller\n";
	cout << "Enter maximum size of queue: ";
	int qs;
	cin >> qs;
	Queue line(qs);			// line queue holds up to qs people

	cout << "Enter the number of simulation hours: ";
	int hours;				//  hours of simulation
	cin >> hours;
    // simulation will run 1 cycle per minute
	long cyclelimit = MIN_PER_HR * hours; // # of cycles

	cout << "Enter the average number of customers per hour: ";
	double perhour;         //  average # of arrival per hour
	cin >> perhour;
	double min_per_cust;	//  average time between arrivals
	min_per_cust = MIN_PER_HR / perhour;

	Item temp;			//  new customer data
	long turnaways = 0;		//  turned away by full queue
	long customers = 0; 		//  joined the queue
	long served = 0;		//  served during the simulation
	long sum_line = 0;		//  cumulative line length
	int wait_time = 0;		//  time until autoteller is free
	long line_wait = 0;		//  cumulative time in line


// running the simulation
	for (int cycle = 0; cycle < cyclelimit; cycle++)
	{
		if (newcustomer(min_per_cust))	// have newcomer
		{
			if (line.isfull())
				turnaways++;
			else
			{
				customers++;
				temp.set(cycle);	// cycle = time of arrival
				line.enqueue(temp);	// add newcomer to line
			}
		}
		if (wait_time <= 0 && !line.isempty())
		{
			line.dequeue (temp);	  // attend next customer
			wait_time = temp.ptime(); // for wait_time minutes
			line_wait += cycle - temp.when();
			served++;
		}
		if (wait_time > 0)
			wait_time--;
		sum_line += line.queuecount();
	}

// reporting results
	if (customers > 0)
	{
		cout << "customers accepted: " << customers << '\n';
		cout << "  customers served: " << served << '\n';
		cout << "         turnaways: " << turnaways << '\n';
		cout << "average queue size: ";
		cout.precision(2);
		cout.setf(ios::fixed, ios::floatfield);
		cout.setf(ios::showpoint);
		cout << (double) sum_line / cyclelimit << '\n';
		cout << " average wait time: "
			 << (double) line_wait / served << " minutes\n";
	}
	else
		cout << "No customers!\n";

	return 0;
}

//  x = average time, in minutes, between customers
//  return value is True if customer shows up this minut
Bool newcustomer(double x)
{
	if (rand() * x / RAND_MAX < 1)
		return True;
	else
		return False;
}