Modular Programming with C++

Doing Business by Selling Classes

The development of Object Oriented Programming has enabled a new business in software development.

  • Develop different classes and sell to other people

These classes often provide functions that are popularly used in applications

  • E.g. the Java calculator used in some Web pages

Assume that you have designed some class and would like to sell it to a customer.

  • You do not want to give him the source code of the member functions since your customer may copy your code
  • They may modify it and re-sell it to somebody else

Therefore, It is better to give your customer executable code such that they cannot read or modify it.

Static Library

  • Rather than giving your customer the executable code, you can give him a (static) library
  • Inside a library, it does not contain the executable code, but the object code – machine code waiting for linking
  • Since object code can not be read directly (not readable by human), your customer cannot modify your codes
  • To enable your customer know how to use your class, give also your customer a header file that contains the definition of your class.

To Sell the library, only give the header file and the library. (Dont give out your source code!)

Create a Static Library with Visual C++

  1. Create the class required
  2. Implement the class
  3. Test the class
  4. Create the library with Visual C++
  5. Send the library and header file to the System Analyst
  6. Integrating into the Application

Modular Program Design

Besides doing business with classes, the use of static library also facilitates modular program design.

  • The system analyst analyses the requirement of a program and divides it into a number of modules
  • The specifications of each module, such as its functions, the calling methods, the parameters returned, are well defined
  • Based on the specifications, the development of each module will be done by different programmers.
  • Very useful to team work.

Steps:

  1. Obtain the requirements
  2. Design the program flow using flow chart
  3. Divide into modules
  4. Ask programmers to develop the modules
  5. Integrate the modules (write the Main Program and call all the modules)

Interface versus Implementation

A class stored in the header file is a contract between the system analyst and programmers, and between the developers and customers.

  • System Analyst who wants to use objects of this class should follow the rules defined in the class declaration
  • Class should be implemented by the programmer exactly the same way it is declared; otherwise, it will cause errors

In the language of OO programming, this contract is named as interface.

Create the library with Visual C++

Writing a Good Program

* - Value of

& - Address of

Pointers(Very Important Concept)

You need to be familarized with memory.

Memory is for storing executable code during executing.

How memory is used in C++?

The whole big piece of memory is divided into 4 areas:

  • Code Space - for the storage of program code

  • Stack - for the storage of local variables/objects, passed parameters.

  • Global Name Space - for the storage of global variables/objects

  • Free store - for the storage of dynamically created data

When a program start execute, the operation system will allocate a fixed memory for Code space, a fixed memory for Stack, a fixed memory for Global Name Space.

What is Free store / the Heap? - the memory remained unuse. Unused memory is dynamic.

to use the heap, you have to use pointer.

Only the Operating System know whether the particular memory is used in the free store or not.

What is the Address of a variable?

A variable uses a space in memory. Every variable has a memory address.

Each byte has an address, Each variable has the starting-byte address. All values written in hexadecimal but binary in reality.

Indicates Address using Reference (&)

In C++, use & ampersand to indicates the address of a variable.

Note Variable and address of a variable are different.

What is a Pointer?

In many situations, we want to store the address of a variable into a particular memory location.

  • The value of pointer must be the address value.

In C++, every address has 4 bytes.

size of pointer must be 4 bytes long.

e.g. short is 2 bytes, but it’s address is still 4 bytes.

In C++, each variable/object must have its type/class declared.

The type of a pointer variable is understood as where the address is stored in the variable.

If we want to declare the type of pa, which stores the address of a char variable a, how do we do it?

1
2
3
4
char *pa; // declaring pa (you get 4 bytes!);
char* pa; // declaring pa (you get 4 bytes!);
char * pa; // declaring pa (you get 4 bytes!);
// You can write in those 3 different styles.

char *pa states that the memory content of the address stored in pa is a character. pa is indirectly declared to be a variable storing an address of a character.

Purpose of Pointer : allow programmer be able to use the memory in the free store.

Dont touch the pointer until you assign it a address!

1
2
3
4
5
6
7
8
//Note: 0x30 is Understood in hex number
char *pa, a=0x30; // 48
cout << a; // a = '0'
pa = &a; // pa= 0100
cout << *pa; // *pa = '0'
*pa = 49; // a = '1'
cout << a << endl;

More examples:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
using namespace std;
typedef unsigned short int USHORT; //I am lazy to type "unsigned short int" everytime
int main()
{
USHORT myAge; // a variable
USHORT * pAge = 0;// a null pointer, pAge=0, not *pAge=0
// Note ONLY assign address to the pointer!!!
// Don’t let it become wild pointer (point to unknown)
myAge = 5;
cout << "myAge: " << myAge << "\n";
pAge = &myAge; // assign address of myAge to pAge
cout << "*pAge: " << *pAge << "\n\n";
cout << "*pAge = 7\n";
*pAge = 7; // *pAge=7, not pAge=7, sets myAge to 7
cout << "*pAge: " << *pAge << "\n";
cout << "myAge: " << myAge << "\n\n";
cout << "myAge = 9\n";
myAge = 9;
cout << "myAge: " << myAge << "\n";
cout << "*pAge: " << *pAge << "\n";
return 0;
}

/*
Results:

myAge: 5
*pAge: 5

*pAge = 7
*pAge: 7
myAge: 7

myAge = 9
myAge: 9
*pAge: 9
*/

Why Pointer? - Using Free Store

Like we mentioned, Pointer allows us to handle memory in Free Store.

  • The Free Store is opened to all functions

Pointer helps us to identify the part of memory in Free Store that is being used by a particular function or object.

To use the memory in Free Store:


  1. Claim to the system how much memory is required
  2. System allocates a memory space with size big enough
  3. System returns a pointer value which is the starting address of that memory space. (A pointer needs to store this value.)
  4. When the memory space is not required, release it back to the system for other functions.

new and delete

The keywords new and delete help us claim and release memory in Free Store.

Note: The number of new and number of delete must be same.

Example:

Part1

1
2
3
4
5
6
7
8
9
10
11
12
13
unsigned short int * pPointer; //Local Pointer
// pointer is declared (allocated 4 byte). You don't know the value yet.
// Only give space, no number

pPointer = new unsigned short int; // "new" tell the computer to take memory from heap
//a space for short int is mapped to pPointer (a short int - allocated 2 byte)
// I created a number space "short int" and mapped it to the address space "pPointer".

//Now we claimed a piece of memory in Free Store with size that
//is equal to an unsigned short integer.

// after using the memory space, you need to release the memory.
delete pPointer; // "delete" tell the computer this memory can be released to system

Part2

1
2
3
4
5
6
7
8
9
int * pPointer2;
pPointer2 = new int[2]; // We claim memory with size equals to 2 integers.
// 4 byte for first element, 4 byte for second element. (consecutively)
// pPointer2 now points to the starting address of this memory space

// after using the memory space, you need to release the memory.

delete [] pPointer2; // return it to system
// Note: Results unpredictable if no [] .

The address of array is the address of first element in the array.

short int is only 2 byte

Note: delete remove a pointer, it still exists

Stray (Wild or Dangling) Pointers

If one deletes a pointer, the associated memory will be given back to system.

  • If one tries to use that pointer again without reassigning it, the result is unpredictable
  • To ensure one will not use the deleted heap memory again, always assign the pointer with 0 after delete

A stray (or wild, dangling) pointer is one that has been deleted but without assigning to NULL .

NULL pointer is safe, according to Operation System.

1
2
3
4
int *pNum = new int(5); // Initialize *pNum to 5 
delete pNum;
pNum = 0; // To ensure the program will CRASH rather
// than unpredictable if one reuses it

Memory Leaks

The program below will introduce the problem of memory leaks (the system cannot get back the memory allocated to the program) and execution error. Build the program and step over each line of code using the Run- time Debugger.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream>
using namespace std;
int main()
{
int localVar = 7;
int * pHeap = new int; //line 5
int * pStack = &localVar;
cout << "localVar: " << localVar << "\n";
cout << "*pStack: " << *pStack << "\n";
*pHeap = 777;
cout << "*pHeap: " << *pHeap << "\n";
pHeap = new int; //line 11
*pHeap = 77777;
delete pHeap;
cout << "*pHeap: " << *pHeap << "\n";
delete pHeap;
return 0;
}

  1. What is the address of localVar? (Use Visual Studio Debug mode to check)
  2. What is the value of pHeap after executing line 5? (0)
  3. What is the value of pHeap after executing line 11? (0)
  4. Assume that you can finish executing the program. Do you think you can free the memory claimed by the new statement in line 5? If no, why not?

Modify the program such that we can free the memory claimed by both new statements in line 5 and line 11.

Ans:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
using namespace std;
int main(){
int localVar = 7;
int * pHeap = new int; //line 5
int * pStack = &localVar;
cout << "localVar: " << localVar << "\n";
cout << "*pStack: " << *pStack << "\n";
*pHeap = 777;
cout << "*pHeap: " << *pHeap << "\n";
delete pHeap;
pHeap = new int; //line 11
*pHeap = 77777;
cout << "*pHeap: " << *pHeap << "\n";
delete pHeap;
return 0;
}

Creating Objects in the Free Store

We can also create objects in the Free Store.

1
CAT *pCat = new CAT;

pCat stores the starting address of the memory allocated.

When the object is created, its constructor is called.

Object identified by a pointer.

Note: Size of Class = All the member variable size (consecutively)

Deleting Objects

Objects in the Free Store can also be deleted.

1
2
3
4
5
 CAT *pCat = new CAT; //pCat becomes an identifier of the object created

// after using the memory space

delete pCat; //If an object is deleted, its destructor will be called

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <iostream>
using namespace std;
class SimpleCat
{
public:
SimpleCat();
~SimpleCat();
int GetAge() const {return itsAge;}
void SetAge(int age) {itsAge = age;}
private:
int itsAge;
};
SimpleCat::SimpleCat() //Constructor
{
cout << "Constructor called.\n";
itsAge = 1;
}
SimpleCat::~SimpleCat() //Destructor
{
cout << "Destructor called.\n";
}
1
2
3
4
5
6
7
8
9
10
int main(){
cout << "SimpleCat Frisky...\n";
SimpleCat Frisky;
cout << "SimpleCat *pRags = new SimpleCat...\n";
SimpleCat * pRags = new SimpleCat;
cout << "delete pRags...\n";
delete pRags;
cout << "Exiting, watch Frisky go...\n";
return 0;
}

Result:

1
2
3
4
5
6
7
8
SimpleCat Frisky...
Constructor called.
SimpleCat *pRags = new SimpleCat...
Constructor called.
delete pRags...
Destructor called.
Exiting, watch Frisky go...
Destructor called.

Accessing Members of Objects

To access members of an object, the operator (.) is used

1
2
3
SimpleCat *pCat = new SimpleCat;
(*pCat).SetAge(2);
// (The object pointed by pCat).(The member function of the object).(Input parameter of the member function)

In C++, a shorthand is provided for such member access.

1
2
SimpleCat *pCat = new SimpleCat; 
pCat->SetAge(2); // The same as before

Pointers Arithmetic

Pointers can be added or subtracted from one another if they are of the same type.

1
2
3
4
5
6
7
8
9
10
11
12
13
short int *a, *b, x=0x100A;
a = &x;
cout << "a = " << a << endl; // Assume a = 00F3FB08
b = a + 1;
cout << "b = " << b << endl; // b = 00F3FB0A
cout << "b - a = " << b - a << endl;
return 0;

/*
a = 00F3FB08
b = 00F3FB0A
b - a = 1
*/

The same applies to objects.

You must not DIRECTLY assign a value to a pointer, e.g. int *p=0x00110110;

1
2
3
4
5
6
Cat *a = new Cat;
Cat *b;
cout << "a = " << a << endl; // Assume a = 001
b = a + 1; // Don't touch *b as the memory is not from new
cout << "b = " << b << endl; // b = 007
cout << "b - a = " << b-a << endl; // b - a = 1

Arrays and Strings

What Is an Array?

An array consists of a collection of data storage locations, each holds the variables/objects of the same type/class.

An array can be easily declared as follows:

1
short shortArray[25];

It states that there is a sequence of 25 short integer data. The whole sequence is named as shortArray.

Note: In consecutive memory.

Array Element

  • In an array, an array element is referred to by indicating its index
  • The first element has index 0, and then 1, …
  • In our previous example, shortArray[0] is the first element and shortArray[24] is the last element.
  • Do not try to use shortArray[25], result unpredictable.

Initializing Arrays

An array can be initialized during declaration

1
2
3
4
5
6
7
8
int IntegerArray[5] = {10,20,30,40,50};
//IntegerArray declares itself to have 5 integers
int AnotherArray[] = {50,40,30,20,10};
// AnotherArray takes the memory space in stack
// just enough to hold the data defined in the list
int BiggerArray[5] = {10,20};
// BiggerArray declares itself to have 5 integers
// but only the first 2 of them are initialized. The others are 0.

Wrong example:

1
int IncorrectArray[2] = {10,20,30}; //ERROR

Note: int a[5]; NOT the same as int a[5]={}; .

Array of Objects

Any object can be stored in an array.

Accessing member data in an array of objects is a two-step process.

  • Identify the member of array by []
  • Access the member by .
1
2
3
4
5
CAT Litter[5]; //Litter[0] - Litter[4] are 5 objects 
int i;
for (i=0; i<5; i++)
cout << Litter[i].GetAge() << endl;
// (To find out which CAT object).(Call GetAge() of that CAT object)

Multidimensional Array

It is possible to have an array of more than 1 dimension.

1
2
3
4
int SomeArray[5][2] = { {0,0},{1,2},{4,6},{7,2},{4,4}}; 
int AnotherArray[5][2] = {0,0,1,2,4,6,7,2,4,4};
//Note:
//SomeArray[2][1] = AnotherArray[2][1] = 6

Array and Pointer

C++ allows the flexibility for user to use Array and Pointer interchangeably.

An array’s name can be regarded as a constant pointer pointing to the first element of the array.

1
2
3
4
5
 int a, b; //accquire 4x2 bytes in stack
int SomeArray[5] = {10,20,30,40,50}; //accquire 4x5 bytes in stack
a = *SomeArray;// a=10 as SomeArray is address of 1st element
b = *(SomeArray+1); // b = 20, pointer arithmetic
cout<<SomeArray<<' '<<&SomeArray[0]<<endl;

Compiler does all the calculation.

SomeArray+1 does not add 1 to SomeArray but add 4 (1 integer needs 4 bytes for storage), and points to the next element in the array.

More about Pointers and Arrays

another example:

1
2
3
4
5
6
7
8
int SomeArray[5]={10,20,30,40,50}; //accquire 4x5 bytes in stack
int x, *px; //accquire 4x2 bytes in stack
x = *SomeArray; //x's value becomes 10
// will be internally converted to
// x = SomeArray[0]; i.e. x = 10
px = SomeArray; // px is a pointer variable
// will be internally converted to
// px = &(SomeArray[0]);

Note in the above example, px = &SomeArray; is incorrect.

Because there is NOT any memory location to store the pointer SomeArray. Everything is done by an internal conversion

another example:

1
2
3
4
5
6
7
8
9
int SomeArray[5] = {10,11,12,13,14};
int *pSomePointer = SomeArray; // It is a pointer but used
// as array name as pSomePointer stores address of whole array
// Note pSomePointer only store the first address of the whole array. (Why?)
cout << pSomePointer[0] << endl; // number 10 will be shown
cout << pSomePointer[1] << endl; // number 11 will be shown
cout << pSomePointer[2] << endl; // number 12 will be shown
cout << pSomePointer[3] << endl; // number 13 will be shown
cout << pSomePointer[4] << endl; // number 14 will be shown

Those above examples are just demostration to let you realize the thing. This isn’t the propose of using pointer.

Directly Assign Value into a pointer array

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;

int main()
{
int SomeArray[5] = {10,11,12,13,14};
int *pSomePointer = SomeArray; // It is a pointer but used
// as array name as pSomePointer stores address of whole array
// Note pSomePointer only store the first address of the whole array. (Why?)

//Using Pointers Arithmetic
*(pSomePointer) = 0;
*(pSomePointer+1) = 0;
*(pSomePointer+2) = 0;
*(pSomePointer+3) = 0;
*(pSomePointer+4) = 0;

cout << pSomePointer[0] << endl; // number 0 will be shown
cout << pSomePointer[1] << endl; // number 0 will be shown
cout << pSomePointer[2] << endl; // number 0 will be shown
cout << pSomePointer[3] << endl; // number 0 will be shown
cout << pSomePointer[4] << endl; // number 0 will be shown

return 0;
}


Array of Pointers

So far the arrays are declared to store data in the stack.

Usually the memory space of stack is small

If a large array is required, it is better to store the elements of arrays in the Free Store (Heap).

In this case,for every element in an array, a pointer is assigned to indicate its location in the Free Store. This becomes an array of pointers.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;
class CAT //12 byte
{
public:
CAT() {itsAge = 1; b = 1;}
~CAT() {}
int GetAge() const {return itsAge;}
void SetAge(int age) {itsAge = age;}

private:
int itsAge; double b; //
};

//Creating 500 CAT objects may use up all memory in the stack.
int main()
{
//Hence only an array of 500 pointers of CAT objects are created in the stack.
CAT *Family[500]; //
//^ accquire 4x500 byte in the stack
int i;
for (i=0; i<500; i++)
Family[i] = new CAT; //Each CAT object is located in the Free Store by "new"
//^ 12x500 byte in the heap

// To access the member of a particular CAT object, use the
//corresponding pointer in the array
Family[255]->SetAge(3);
for (i=0; i<500; i++)
delete Family[i];
return 0;
}

Pointer of Array

If one feels that 500 pointers in the previous example are still too many, we can put the whole array into the Free Store

  • Hence one pointer is enough to point to the array itself but not the individual element
  • It becomes a pointer of array.
1
2
3
4
5
6
7
8
CAT *Family = new CAT[500]; // 4 byte in stack, 500xobject byte in heap
//Family is the pointer of array and points to Family[0] in Free Store

/*
Same as:
CAT *Family; // 4 byte in stack
Family = new CAT[500]; //500xobject byte in heap
*/
1
2
3
4
5
6
7
8
int a = 0, b=0;
//Individual element of the array of the
//CAT objects can also be accessed by pointer arithmetic
(Family+255)->SetAge(10); //address of the object setage
a = (Family+255)->GetAge();// a = 10
b = Family[255].GetAge(); // b = 10 //object getage
delete [] Family;
// The [] symbol after delete lets the system know the whole array is to be deleted

String - char Array

A string is stored in an array of characters.

A string can be simply initialized as follows,

1
2
char Greeting[] = {'H','e','l','l','o',' ','W','o','r','l','d','\0'};
//The size of array is 12

Note: \0 The null character represents the end of string; it must be added.

However, this method can easily introduce errors.

C++ provides a shorthand that makes use of the double quote " ".

1
2
3
char Greeting[] = {"Hello World"};
//Totally 12 bytes are allocated for Greeting.
//Null character is automatically added.

Do Not mix up string size with character array size!

string is the content stored in a character array.

Copying String


strcpy() and strncpy()

C++ inherits from C a library of functions for tackling strings

Two most common ones are strcpy() and strncpy()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#define _CRT_SECURE_NO_WARNINGS 1 //Ignore warning.
#include <iostream>
#include <string.h> // State the definition of strcpy()
//In Windows, you may omit this line as it is already included by iostream

using namespace std;
int main()
{
char Str1[] = {"123456789"};
char Str2[80];//BIG enough
strcpy(Str2,Str1); // Copy Str1 to Str2
cout << "Str1: " << Str1 << endl;//Unlike int array, NOT address
cout << "Str2: " << Str2 << endl;
return 0;
}

strcpy() will overwrite past the end of the destination if the source were larger than the destination, damaging other data.

  • To reduce the problem, strncpy() can be used
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
const int MaxLength = 79; //MaxLength > strlen(String1) = 9
char String1[] = "123456789";
char String2[MaxLength+1]; //Initialize String2 if MaxLength<=9
strncpy(String2,String1,MaxLength); //String2 big enough
cout << "String1: " << String1 << endl;
cout << "String2: " << String2 << endl;
return 0;
}

Strncpy() needs another parameter MaxLength which specifies the maximum no. of characters to be copied (NOT counting the null character).

A few more library functions

  • To measure the length of a string, the function strlen() is useful
  • To combine two strings into one, we can use the function strcat()
  • _itoa() converts an integer into a string itoa() in older VS version)
  • int atoi(char *) converts a string to an integer
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;
int main()
{
char String1[100];
cout << "Please enter a word: ";
cin >> String1;
char String2[] = " has ";
char String3[5];
char String4[] = " characters.";
_itoa(strlen(String1),String3,10);
strcat(String1,String2);//ret String1
strcat(String1,String3);
strcat(String1,String4);
cout << String1 << endl;
return 0;
}

Command-Line Processing

In many operating systems, command-line options are allowed to input parameters to the program.

1
$ SomeProgram Param1 Param2 Param3

To achieve this, main() allows two input parameters to hold the command-line options.

1
2
3
4
5
6
//main() is inside the project SomeProgram
int main(int argc, char *argv[]) //*argv[] can be written as **argv
{
// function statements here
return 0;
}

The values of argc, argv[] are assigned automatically.

argc stores the no. of strings entered by the user (other label can be used instead of argc.)

argv is an array. Each element of the array is a character pointer

How this acutually work?

1
$ SomeProgram Param1 Param2 Param3

In this case:

argc = 4

argv[0] points to “SomeProgram” : Note argv[0][0] is ‘S’

argv[1] points to “Param1”

argv[2] points to “Param2”

argv[3] points to “Param3”

Look at this example:

1
2
3
4
5
6
7
8
9
10
//cliprocessing.exe
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
cout << "Received " << argc << " arguments." << endl;
for (int i = 0; i<argc; i++)
cout << "argument " << i << ": " << argv[i] << endl;
return 0;
}

When you call the program through command prompt:

1
$ cliprocessing a1 a2 b

it should give you this result:

1
2
3
4
5
Received 4 arguments.
argument 0: cliprocessing
argument 1: a1
argument 2: a2
argument 3: b

Parameter passing using pointers

Pass Parameters - Pass by Value

Look at this example “badswap”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
//badswap.cpp
#include <iostream>
using namespace std;
void swap(int x, int y)
{
//swapping x and y
int temp;
temp = x;
x=y;
y=temp;
}
// x and y are swapped only in swap() but not in main()
int main()
{
int x = 5, y = 10;
cout << "Main. Before swap, x: " << x << " y: " << y << "\n";
swap(x,y);
cout << "Main. After swap, x: "
<< x << " y: " << y << "\n";
return 0;
}

/*
Therefore the result is:
Main. Before swap, x: 5 y: 10
Main. After swap, x: 5 y: 10
*/

To pass parameters to functions, we may pass parameters by value, i.e. pass copies of the parameter values to functions.

Pass by Reference

Look at this example “goodswap”.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
//goodswap.cpp
#include <iostream>
using namespace std;
void swap(int *px, int *py)
{
int temp;
temp = *px;
*px=*py;
*py=temp;
}
int main()
{
int x = 5, y = 10;
cout << "Main. Before swap, x: "
<< x << " y: " << y << "\n";
swap(&x,&y); //The addresses of x and y in main() are passed to swap()
cout << "Main. After swap, x: "
<< x << " y: " << y << "\n";
return 0;
}

/*
Therefore the result is:
Main. Before swap, x: 5 y: 10
Main. After swap, x: 10 y: 5
*/

Pointer allows pass parameters by reference.

Return Multiple Values

Normal function can only return ONE value.

If more than 1 value are to be returned, it can be done by passing 2 or more parameters to a function by reference.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
void opt(int, int *, int *); //prototype
int main()
{
int num, sqr, cub;
cout << "Input a number: ";
cin >> num;
opt(num, &sqr, &cub);
cout << "Square = " << sqr << endl;
cout << "Cube = " << cub << endl;
return 0;
}
void opt(int n, int *pS, int *pC)
{
*pS = n*n;
*pC = n*n*n;
}

Passing an array of parameters to a function

To save effort from separately passing a number of parameters to a function, they may be passed as an array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string.h>
using namespace std;
void opt(char *);

int main()
{
char str[] =
{"This is a string"};
cout << str << endl;
opt(str);
cout << str << endl;
return 0;
}
void opt(char * stringP) //str[] is a character array, so str is a character pointer
{
strcpy(stringP,"New String");
}

/*
Result:
This is a string
New String
*/

Note that in the previous example, the string in str[] is modified inside the function opt()

  • It is because passing the name of an array has made the array elements to be passed by reference
  • When copying the string “NewString” to stringP[] in opt(), it is just the same as copying to the original str[].

str and stringP are the same by value.

Stream I/O

Input and Output

The input and output (I/O) are handled by the standard C++ library (such as iostream).

  • A library is a collection of object code to be linked to the C++ program to provide additional functionality
  • For different platforms, different libraries (that may use the same name) can be used for I/O functions

Buffering

  • iostream classes view the flow of data as being a stream of data, one byte following another
  • Buffer is provided in some cases to the stream

Standard I/O Objects

When a C++ program that includes the iostream classes starts, four objects are created and initialized.

Object Usage
cin handle input from the standard input, i.e. keyboard
cout handle output to the standard output, i.e. display
cerr handle unbuffered output to the standard error device, i.e. display in a PC
clog handle buffered error messages that are output to the standard error device, i.e. display in a PC.

Buffered: Display only when a flush command is sent from the library code

Input using cin

cin has been generally used for input data from keyboard

The operator >> is overloaded such that different type of data can be read into the buffer of cin and then to some variable.

Member functions

Function Usage
cin.get() Helps to obtain the input data in a more flexible way.
cin.getline() allows the whole line of data to be input to a character array

Example of cin.get()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
int main()
{
int c;

// cin.get() returns an integer of code value of the character in standard input
while ((c = cin.get()) != EOF)
//EOF : The loop will stop if end-of-file (crtl-z) is input
//EOF : 0xFF is a symbolic constant defined in <iostream>
{
cout << "c: " << (char)c << endl;
}
cout << "\nDone!\n";
return 0;
}

//If we press crtl-z, it becomes End-of-file (EOF) condition.

Why do we use cin.getline()?

cin >> abc will stop to read in data if it sees, e.g. a space or a tab key.

cin.getline() can only read in string, but not value of other types;

However, it will not stop when encountering spaces or tabs.

Small Example :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <iostream> 
using namespace std;
int main()
{
char stringOne[256];
char stringTwo[256];
char stringThree[256];
cout << "Enter string one: ";
cin.getline(stringOne,256);
cout << "stringOne: " << stringOne << endl;
cout << "Enter string two: ";
cin >> stringTwo; //The >> operator reads until a new-line or a space character is seen.
cout << "stringTwo: " << stringTwo << endl;
cout << "Enter string three: ";
cin.getline(stringThree,256);
cout << "stringThree: " << stringThree << endl; return 0;
}

//Try with this program.

Note that since cin>> leaves the newline character (\n) in the iostream. If getline is used after cin>>, the getline sees this newline character as leading whitespace, thinks it is finished and stops reading any further. To fix the problem, one of the solutions is to add cin.ignore() after cin.

1
cin.ignore(100,'\n');  // skips up to 100 characters

Another solution is to use cin.getline() to assure the keyboard buffer is empty. Then call cin.getline() the second time to do the job you want.

1
2
cin.getline(dummy, 20); //Clear buffer
cin.getline(job, 100); //Do the job you want

Output with cout

Just as cin, cout is also an object created when the iostream header file is compiled

  • The operator << is overloaded such that different types of data can be sent out.

Member functions

Function Usage
cout.put(char a) Put the character ato output, and return cout
cout.write(char *buf,int length) Write length characters in buf[] to output device , and return cout.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <string>
using namespace std;
int main()
{
char One[] = "One if by land";
int fullLength = strlen(One);
int tooShort = fullLength - 3;
int tooLong = fullLength + 6;
cout.write(One,fullLength) << "\n";
// fullLength=14,return cout after write
cout.write(One,tooShort) << "\n";
cout.write(One,tooLong) << "\n";
return 0;
}

Other Member functions

Function Usage
cout.width(int a) Set the width of the next output field to a’s value
cout.fill(char b) Fill the empty field of the output by b’s value
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
using namespace std;
int main()
{
cout << "Start >";
cout.width(6); //width(6) defines the total width of the field to be 6 char.
cout << 123 << "<End\n";
cout << "Start >";
cout.width(6);
cout.fill('*'); //fill('*') fills the empty field with *
cout << 123 << "<End\n";
}

/*
Results:
Start > 123<End
Start >***123<End
*/

File Input and Output (Read or Write Files)

File access is usually done with steps as follows:

Step 1: Open file (To claim from the system the access of a particular file)

Step 2: Read data from file / Write data to file

Step 3: Close file (To indicate to the system the file access is finished (closed))

We use ofstream and ifstream to deal with files.

First you need to include the fstream header file in your program.

1
#include <fstream>

To open a file for writing or reading, first create an ofstream or ifstream object respectively with the filename as the input parameter.

1
2
ofstream fout("myfile.cpp"); 
ifstream fin("myfile.cpp");

After opening files, reading or writing files can be done in a similar way as cin or cout respectively.

After writing/reading, close the file using the member function close() of the ofstream/ifstream objects.

Example Here:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std; //A MUST for fstream
#include <fstream>
int main() {
ofstream fout("myfile.cpp");
fout<<"This line is written to file.\n";
fout.close();
ifstream fin("myfile.cpp");
char ch;
while (fin.get(ch)) //NULL if end of file
cout << ch;
fin.close();
return 0;
}

Changing Default Behavior

Default behavior of opening a file by ofstream is to create it if it doesn’t yet exist.

  • If exists, it deletes all its contents and overwrite on it (truncate)

Use a second parameter to change the behavior.

1
2
ofstream fout2("myfile.cpp",ios::app);
//File will be opened for appending data to the end of the existing file
Second Parameter Usage
ios::trunc Default for ofstream; truncates if it exists
ios::app Append: File will be opened for appending data to the end of the existing file
ios::ate Place the position at the end of the file (either input or output), but write data at the start position like trunc
ios::in Overwrite: The file (if it exists) will NOT be truncated, the read/write cursor is positioned at the start of the file.

Appending to the End of file

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <fstream>
#include <iostream>
using namespace std;

int main()
{
ofstream f1("myfile.cpp"); //Default trunc
f1 << "This line is writter to file. \n";
f1.close();
char fname[]="myfile.cpp"; // File name can be supplied by a variable
ofstream fout2(fname, ios::app);
// To avoid redeclaring variable f1,
//a different name should be provided even for opening the same file
fout2 << "This line is appended to the end of prev line\n";
fout2.close();
ifstream fin("myfile.cpp")
char ch;
while (fin.get(ch))
cout << ch;
fin.close();
return 0;
}

extra:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 .
.
.
//Assume myfile.cpp contains "This line is written to file.\n"
ofstream fout2("myfile.cpp", ios::in);
fout2 << "Beginning of file";
fout2.close();


ifstream fin("myfile.cpp");
// A good practice to check if anything goes wrong when opening a file
if (!fin) {cout << "File opening error!\n"; return 0;}
//If the file "myfile.cpp" cannot be opened,fin becomes NULL.
/* The operator ! is defined for stream object,
if the stream is bad, return NULL, i.e. false */
char ch;
while (fin.get(ch))
cout << ch;
fin.close();
return 0;
.
.
.

Editing File

It is often that we need to modify a particular part of a file - editing a file

ofstream and ifstream offers 4 member functions that set the current position of an opened file.

For ofstream of ifstream? Function Usage
ofstream seepkp(long pos) sets the current position. pos is a byte offset from the file beginning
ofstream tellp() tells the current position. Return a byte offset from the file beginning
ifstream seepkp(long pos) sets the current position. pos is a byte offset from the file beginning
ifstream tellg() tells the current position. Return a byte offset from the file beginning

Example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <fstream>
#include <iostream>
using namespace std;
int main()
{
ofstream test1file("test1");
cout << "Text written: \n";
cout << "This text is written to file!\n"; //write to screen
test1file << "This text is written to file!\n";
test1file.close();
ifstream tin("test1");
tin.seekg(10); //Change the current position to 10
cout << "\nCurrent position: " << tin.tellg() << "\n";
cout << "\nContent of the file after an offset of 10:\n"; char ch;
while (tin.get(ch))
{ cout << ch;
} //display file
tin.close();
return 0;
}