Adventures in Functions

Inline Functions



// inline.cpp -- use an inline function

#include <iostream.h>

// an inline function must be defined before first use
inline double square(double x) { return x * x; }

int main(void)
{
	double a, b;
	double c = 13.0;

	a = square(5.0);
	b = square(4.5 + 7.5);   // can pass expressions
	cout << "a = " << a << ", b = " << b << "\n";
	cout << "c = " << c;
	cout << ", c squared = " << square(c++) << "\n";
	cout << "Now c = " << c << "\n";
	return 0;
}


Reference Variables



// firstref.cpp -- defining and using a reference

#include <iostream.h>
int main(void)
{
	int rats = 101;
	int & rodents = rats;   // rodents is a reference

	cout << "rats = " << rats;
	cout << ", rodents = " << rodents << "\n";
	rodents++;
	cout << "rats = " << rats;
	cout << ", rodents = " << rodents << "\n";

// some implementations require type casting the following
// addresses to type unsigned
	cout << "rats address = " << &rats;
	cout << ", rodents address = " << &rodents << "\n";
	return 0;
}



// secref.cpp -- defining and using a reference

#include <iostream.h>
int main(void)
{
	int rats = 101;
	int & rodents = rats;   // rodents is a reference

	cout << "rats = " << rats;
	cout << ", rodents = " << rodents << "\n";

// some implementations require type casting the following
// addresses to type unsigned
	cout << "rats address = " << &rats;
	cout << ", rodents address = " << &rodents << "\n";

	int bunnies = 50;
	rodents = bunnies;       // can we change the reference?
	cout << "bunnies = " << bunnies;
	cout << ", rats = " << rats;
	cout << ", rodents = " << rodents << "\n";

// some implementations require type casting the following
// addresses to type unsigned
	cout << "bunnies address = " << &bunnies;
	cout << ", rodents address = " << &rodents << "\n";
	return 0;
}



// swaps.cpp -- swapping with references and with pointers

#include <iostream.h>
void swapr(int & a, int & b);	// a, b are aliases for ints
void swapp(int * p, int * q);	// p, q are addresses of ints
void swapv(int a, int b);	// a, b are new variables
int main(void)
{
	int wallet1 = 300;
	int wallet2 = 350;

	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << "\n";

	cout << "Using references to swap contents:\n";
	swapr(wallet1, wallet2);   // pass variables
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << "\n";

	cout << "Using pointers to swap contents:\n";
	swapp(&wallet1, &wallet2); // pass addresses of variables
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << "\n";

	cout << "Trying to use passing by value:\n";
	swapv(wallet1, wallet2);   // pass values of variables
	cout << "wallet1 = $" << wallet1;
	cout << " wallet2 = $" << wallet2 << "\n";
	return 0;
}

void swapr(int & a, int & b) 	// use references
{
	int temp;

	temp = a;      // use a, b for values of variables
	a = b;
	b = temp;
}

void swapp(int * p, int * q)	// use pointers
{
	int temp;

	temp = *p;      // use *p, *q for values of variables
	*p = *q;
	*q = temp;
}

void swapv(int a, int b)		// try using values
{
	int temp;

	temp = a;      // use a, b for values of variables
	a = b;
	b = temp;
}



// cubes.cpp -- regular and reference arguments

#include <iostream.h>
double cube(double a);
double refcube(double &ra);
int main (void)
{
	double x = 3.0;

	cout << cube(x);
	cout << " = cube of " << x << "\n";
	cout << refcube(x);
	cout << " = cube of " << x << "\n";
	return 0;
}

double cube(double a)
{
	a *= a * a;
	return a;
}

double refcube(double &ra)
{
	ra *= ra * ra;
	return ra;
}


// strtref.cpp -- using structure references

#include <iostream.h>
struct sysop
{
	char name[26];
	char quote[64];
	int used;
};

sysop & use(sysop & sysopref);	// function with a reference return type

int main(void)
{
// NOTE: some implementations require using the keyword static
// in the two structure declarations to enable initialization
	sysop looper =
	{
		"Rick \"Fortran\" Looper",
		"I'm a goto kind of guy.",
		0
	};

	use(looper);			// looper is type sysop
	cout << looper.used << " use(s)\n";

	use (use(looper)); 		// use(looper) is type sysop
	cout << looper.used << " use(s)\n";

	sysop morf =
	{
		"Polly Morf",
		"Polly's not a hacker.",
		0
	};
	use(looper) = morf;            	// can assign to function!
	cout << looper.name << " says:\n" << looper.quote << '\n';
	return 0;
}

// use() returns the reference passed to it
sysop & use(sysop & sysopref)
{
	cout << sysopref.name << " says:\n";
	cout << sysopref.quote << "\n";
	sysopref.used++;
	return sysopref;
}



Default Arguments



// left.cpp -- string function with a default argument

#include <iostream.h>
const int ArSize = 80;
char * left(const char * str, int n = 1);
int main(void)
{
	char sample[ArSize];
	cout << "Enter a string:\n";
	cin.get(sample,ArSize);
	char *ps = left(sample, 4);
	cout << ps << "\n";
	delete [] ps;		// free old string
	ps = left(sample);
	cout << ps << "\n";
	return 0;
}

// This function returns a pointer to a new string
// consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
	if(n < 0) 
		n = 0;
	char * p = new char[n+1];
	for (int i = 0; i < n && str[i]; i++)
		p[i] = str[i];      // copy characters
	while (i <= n)
		p[i++] = '\0';      // set rest of string to '\0'
	return p;
}



Function Polymorphism
(Function Overloading)



// leftover.cpp -- overloading the left() function

#include <iostream.h>
unsigned long left(unsigned long num, unsigned ct);
char * left(const char * str, int n = 1);

int main(void)
{
	 char * trip = "Hawaii!!";		// test value
	 unsigned long n = 12345678;		// test value
     int i;

	 for (i = 1; i < 10; i++)
     {
		cout << left(n, i) << "\n";
		cout << left(trip, i) << "\n";
     }
     return 0;

}

// This function returns the first ct digits of the number num.
unsigned long left(unsigned long num, unsigned ct)
{
    unsigned digits = 1;
    unsigned long n = num;
 
    if (ct == 0 || num == 0)
        return 0;		 	// return 0 if no digits  
    while (n /= 10)
        digits++;
	if (digits > ct)
    {
	ct = digits - ct;
	while (ct--)
        		num /= 10;
	return num;		// return left ct digits
	}
    else				// if ct >= number of digits
        return num;			// return the whole number
}

// This function returns a pointer to a new string
// consisting of the first n characters in the str string.
char * left(const char * str, int n)
{
	if(n < 0)
		n = 0;
	char * p = new char[n+1];
	for (int i = 0; i < n && str[i]; i++)
		p[i] = str[i];	// copy characters
	while (i <= n)
		p[i++] = '\0';	// set rest of string to '\0'
	return p;
}



Function Templates



// funtemp.cpp -- using a function template

#include <iostream.h>
// function template prototype
template 
void swap(Any &a, Any &b);

int main(void)
{
	int i = 10, j = 20;
	cout << "i, j = " << i << ", " << j << ".\n";
	cout << "Using compiler-generated int swapper:\n";
	swap(i,j);	// generates void swap(int &, int &)
	cout << "Now i, j = " << i << ", " << j << ".\n";
	
	double x = 24.5, y = 81.7;
	cout << "x, y = " << x << ", " << y << ".\n";
	cout << "Using compiler-generated double swapper:\n";
	swap(x,y);	// generates void swap(double &, double &)
	cout << "Now x, y = " << x << ", " << y << ".\n";
	
	return 0;
}

// function prototype definition
template 
void swap(Any &a, Any &b)
{
	Any temp;
	temp = a;
	a = b;
	b = temp;
};



// twotemps.cpp -- using overloaded template functions

#include <iostream.h>
template 		// original template
void swap(Any &a, Any &b);

template 		// new template
void swap(Any *a, Any *b, int n);

void show(int a[]);
const int Lim = 8;
int main(void)
{
	int i = 10, j = 20;
	cout << "i, j = " << i << ", " << j << ".\n";
	cout << "Using compiler-generated int swapper:\n";
	swap(i,j);		// matches original template
	cout << "Now i, j = " << i << ", " << j << ".\n";
	
	int d1[Lim] = {0,7,0,4,1,7,7,6};
	int d2[Lim] = {0,6,2,0,1,9,6,9};
	cout << "Original arrays:\n";
	show(d1);
	show(d2);
	swap(d1,d2,int(Lim));	// matches new template
	cout << "Swapped arrays:\n";
	show(d1);
	show(d2);	
	
	return 0;
}

template 
void swap(Any &a, Any &b)
{
	Any temp;
	temp = a;
	a = b;
	b = temp;
};

template 
void swap(Any a[], Any b[], int n)
{
	Any temp;
	for (int i = 0; i < n; i++)
	{
		temp = a[i];
		a[i] = b[i];
		b[i] = temp;
	}
};

void show(int a[])
{
	cout << a[0] << a[1] << "/";
	cout << a[2] << a[3] << "/";
	for (int i = 4; i < Lim; i++)
		cout << a[i];
	cout << "\n";
}



// twoswap.cpp -- function overrides a template

#include <iostream.h>
template 
void swap(Any &a, Any &b);

struct job
{
	char name[40];
	double salary;
	int floor;
};
void swap(job &j1, job &j2);
// void swap(job &j1, job &j2);	// new form
void show(job &j);

int main(void)
{
	cout.precision(2);
	cout.setf(ios::fixed, ios::floatfield);
	int i = 10, j = 20;
	cout << "i, j = " << i << ", " << j << ".\n";
	cout << "Using compiler-generated int swapper:\n";
	swap(i,j);	// generates void swap(int &, int &)
	cout << "Now i, j = " << i << ", " << j << ".\n";
	
	job sue = {"Susan Yaffee", 56235.99, 5};
	job sunny = {"Sunny Yazzi", 58309.54, 7};
	cout << "Before job swapping:\n";
	show(sue);
	show(sunny);
	swap(sue, sunny);	// uses void swap(job &, job &)
	cout << "After job swapping:\n";
	show(sue);
	show(sunny);
	
	return 0;
}

template 
void swap(Any &a, Any &b)	// general version
{
	Any temp;
	temp = a;
	a = b;
	b = temp;
};

void swap(job &j1, job &j2)	// specialized version
// void swap(job &j1, job &j2)	// new form
// swaps just the salary and floor fields of a job structure
{
	double t1;
	int t2;
	t1 = j1.salary;
	j1.salary = j2.salary;
	j2.salary = t1;
	t2 = j1.floor;
	j1.floor = j2.floor;
	j2.floor = t2;
}

void show(job &j)
{
	cout << j.name << ": $" << j.salary
		 << " on floor " << j.floor << "\n";
}



Separate Compilation



// coordin.h -- structure templates and function prototypes

// structure templates
struct polar
{
	double distance;	// distance from origin
	double angle;		// direction from origin
};
struct rect
{
	double x;		// horizontal distance from origin
	double y;		// vertical distance from origin
};

// prototypes
polar rect_to_polar(rect xypos);
void show_polar(polar dapos);




// file1.cpp -- example of a two-file program
#include <iostream.h>
#include "coordin.h" // structure templates, function prototypes
int main(void)
{
	rect rplace;
	polar pplace;

	cout << "Enter the x and y values: ";
	while (cin >> rplace.x >> rplace.y)  // slick use of cin
	{
		pplace = rect_to_polar(rplace);
		show_polar(pplace);
		cout << "Next two numbers (q to quit): ";
	}
	return 0;
}



// file2.cpp -- contains functions called in file1.cpp

#include <iostream.h>
#include <math.h>
#include "coordin.h" // structure templates, function prototypes

// convert rectangular to polar coordinates
polar rect_to_polar(rect xypos)
{
	polar answer;

	answer.distance =
		sqrt( xypos.x * xypos.x + xypos.y * xypos.y);
	answer.angle = atan2(xypos.y, xypos.x);
	return answer;      // returns a polar structure
}

// show polar coordinates, converting angle to degrees
void show_polar (polar dapos)
{
	const double Rad_to_deg = 57.29577951;

	cout << "distance = " << dapos.distance;
	cout << ", angle = " << dapos.angle * Rad_to_deg;
	cout << " degrees\n";
}



Storage Classes, Scope, and Linkage



// auto.cpp -- illustrating scope of automatic variables

#include <iostream.h>
void oil(int x);
int main(void)
{
// NOTE: some implementations require that you type cast the
// addresses in this program to type unsigned

	int texas = 31;
	int year = 1992;
	cout << "In main(), texas = " << texas << ", &texas =";
	cout << &texas << "\n";
	cout << "In main(), year = " << year << ", &year =";
	cout << &year << "\n";
	oil(texas);
	cout << "In main(), texas = " << texas << ", &texas =";
	cout << &texas << "\n";
	cout << "In main(), year = " << year << ", &year =";
	cout << &year << "\n";
	return 0;
}

void oil(int x)
{
	int texas = 5;

	cout << "In oil(), texas = " << texas << ", &texas =";
	cout << &texas << "\n";
	cout << "In oil(), x = " << x << ", &x =";
	cout << &x << "\n";
	{				// start a block
		int texas = 113;
		cout << "In block, texas = " << texas;
		cout << ", &texas = " << &texas << "\n";
        		cout << "In block, x = " << x << ", &x =";
		cout << &x << "\n";
	}                				// end a block
	cout << "Post-block texas = " << texas;
	cout << ", &texas = " << &texas << "\n";
}



// external.cpp -- external variables

#include <iostream.h>
// external variable
double warming = 0.3;

// function prototypes
void update(double dt);
void local(void);

int main(void)			// uses global variable
{
	cout << "Global warming is " << warming << " degrees.\n";
	update(0.1);			// call function to change warming
	cout << "Global warming is " << warming << " degrees.\n";
	local();			// call function with local warming
	cout << "Global warming is " << warming << " degrees.\n";
	return 0;
}

void update(double dt)		// modifies global variable
{
	extern double warming;	// optional redeclaration
	warming += dt;
	cout << "Updating global warming to " << warming;
	cout << " degrees.\n";
}

void local(void)			// uses local variable
{
	double warming = 0.8;	// new variable hides external one

	cout << "Local warming = " << warming << " degrees.\n";
		// Access global variable with the 
		// scope resolution operator
	cout << "But global warming = " << ::warming;
	cout << " degrees.\n";
}



// static.cpp -- using a static local variable

#include <iostream.h>
// constants
const int ArSize = 80;

// function prototype
void strcount(char *str);

int main(void)
{
	char input[ArSize];

	cout << "Enter a line:\n";
// NOTE: if your implementation doesn't support getline(), you'll
// have to rewrite the program using get(char *, int) and
// get(char)

	cin.getline(input, ArSize);
	while (input[0] != '\0')
	{
		strcount(input);
		cout << "Enter next line (empty line to quit):\n";
		cin.getline(input, ArSize);
	}
	cout << "Bye\n";
	return 0;
}

void strcount(char * str)
{
	static int total = 0;		// static local variable
	int count = 0;			// automatic local variable

	while (*str++) 		// go to end of string
		count++;
	total += count;
	cout << count << " characters in this string\n";
	cout << total << " characters total\n";
}



// twofile1.cpp -- external and static external variables

#include <iostream.h>	// to be compiled with two file2.cpp
int tom = 3;		// external variable definition
int dick = 30;		// external variable definition
static int harry = 300;	// static external variable definition

// function prototype
void remote_access(void);

int main(void)
{
// NOTE: some implementations require that you type cast
// the addresses to type unsigned

	cout << "main() reports the following addresses:\n";
	cout << &tom << " = &tom, " << &dick << " = &dick, ";
	cout << &harry << " = &harry\n";
	remote_access();
	return 0;
}



// twofile2.cpp -- external and static external variables

#include <iostream.h>
extern int tom;		// tom defined elsewhere
static int dick = 10;	// overrides external dick
int harry = 200;		// external variable definition,
				// no conflict with twofile1 harry

void remote_access(void)
{
// NOTE: some implementations require that you type cast
// the addresses to type unsigned

	cout << "remote_access() reports the following addresses:\n";
	cout << &tom << " = &tom, " << &dick << " = &dick, ";
	cout << &harry << " = &harry\n";
}