Your browser doesn't support JavaScript cpp Archives - Windows Programming

Structures

The C++ structures are similar to classes in C++ except that all members are public by default. A structure is defined in C++ using keyword structure followed by the class name with the body structure defined inside the curly brackets and terminated by a semicolon. Unlike structures in C structures in C++ can be initialised directly.

This code below creates a structure similar to the one in the class demonstration. Since all variables default to public, they can be accessed outside the class definition. Two objects of class box are instantiated and each member variable is initialised with a value. The total volume of the box is calculated by multiplying the individual box variables.

#include <iostream>
using namespace std;
struct box //class definition named box
{
int length;//declare public variable length
int height;//declare public variable height
int width;//declare public variable width
} box1;//instantiate class after class declaration (optional)
int main()
 {
box1.height=5,box1.length=30,box1.width=20;//set values of box1 member variables
cout << "Dimensions of box1 are - " << box1.height*box1.length*box1.width;//output box size
box box2;// instantiate class box 2
box2.height=5,box2.length=30,box2.width=20;//set values of box2 member variables
cout << "\nDimensions of box2 are - " << box2.height*box2.length*box2.width;//output box size
return 0;
}

Type Conversions

C++ supports two types of conversions

Implicit Type Conversion

Is an automatic type conversion by the compiler. Implicit type conversion happens automatically when a value is copied to a compatible data type.  It is possible for implicit conversions to lose information for instance when a signed is implicitly converted to unsigned and when a long is implicitly converted to float.

#include<stdio.h>
int main()
{
short a=50;
int b;
b=a; //implicit type casting
printf("%d\n",a);
printf("%d\n",b);
}

Explicit Type Conversion  

Also known as “type-casting” is a user-defined conversion with the programmer explicitly defining the casting.  The process is usually associated with information loss. 

Explicit conversion can be performed by using an assignment operator or by using a cast operator

Using the  Assignment Operator

The Assignment operator forces one data type to be converted into another and consists of the type name before an expression

#include <iostream>
using namespace std;
int main()
{ 
double x= 3.14159265359; 
int y = (int)x;  //using cast operator (int)
cout<<"x = "<<x <<"\n";
cout<<"y = "<<y;
return 0;
}

Using Cast Operator

C++ supports four types of casting using four specific casting operators: static_cast, dynamic_cast, reinterpret_cast,  and const_cast.

Static Cast – Used for implicit conversions between types such as int to float.  It also performs conversions between pointers of related classes by ‘upcasting’ from a derived to a base class and ‘downcasting’ from a base to a derived class.

#include <iostream>
using namespace std;
int main()
{     
double p = 3.14159265359; 
cout<<"Before casting: pi = "<<p<<endl;   
int total = static_cast<int>(p); 
cout <<"After static_cast:total = "<<total;
}

Dynamic Cast – Dynamic cast is a runtime cast performed only on class pointers and references. The most common use for dynamic casting is converting(downcasting) a base-class pointer into a derived class.

#include <iostream>
using namespace std;
class base {public: virtual void bmethod(){}};
class derived:public base{};
int main()
{  
base* b = new derived; 
derived* d = dynamic_cast<derived*>(b);    
if(d != NULL)      
cout<<"Dynamic cast successful"; 
else      
cout<<"Dynamic cast not successful";
}

Reinterpret Cast – reintepret_cast works on pointers and converts a pointer of any type to any other type of pointer without checking if the pointer or the data pointed to by the pointer is the same or not. 

#include <iostream>
using namespace std; 
int main()
{ 
int* ptr = new int(100); 
char* ch = reinterpret_cast<char*>(ptr);   
cout << *ptr << endl; 
cout << *ch << endl; 
return 0;
}

Const Cast – const_cast removes the constant attribute from references and pointers.  It is not permitted to const_cast variables that are const.

#include <iostream>
using namespace std;
int main(void)
{
const double x = 3.14159265359;
const double* y = &x;
cout << "old value is " << * y << "\n";
double* z=const_cast<double *>(y);
*z=3.14;
cout<<"new value is "<<*y;
}

File Input and Output

Creating and linking a stream to a disk file is called opening a file. When a file is opened, it is available to the OS for reading, writing or both.

Opening a file with fopen()

The fopen() library function is used to open a file:

FILE *fopen(const char *filename, const char *mode);

The fopen call will initialise a structure of type FILE, which contains all the information necessary to control the stream. If fopen() fails, it returns NULL. 

The parameter filename contains the name and address of the file to be opened. The filename argument can be a literal string enclosed in double quotation marks or a pointer to a string variable. The parameter mode specifies the mode in which to open the file. The file may be binary or text and may be opened for reading, writing, or both.  Values of mode for the fopen() function are listed below.

Sr.No. Mode & Description
r Opens an existing text file for reading.
w Opens a text file for writing. If it does not exist, then a new file is created. Here your program will start writing content from the beginning of the file.
a Opens a text file for writing in appending mode. If it does not exist, then a new file is created. Here your program will start appending content in the existing file content.
r+ Opens a text file for both reading and writing.
w+ Opens a text file for both reading and writing. It first truncates the file to zero length if it exists, otherwise creates a file if it does not exist.
a+ Opens a text file for both reading and writing. It creates the file if it does not exist. The reading will start from the beginning but writing can only be appended.

Closing a File

To close a file, use the fclose( ) function. The prototype of this function is −

int fclose( FILE *fp );

The fclose() function returns zero on success, or EOF if there is an error in closing the file. When a file is closed, the file’s buffer is flushed (written to the disk) and the memory is released.

Formatted V Unformatted Input/Output

Formatted input/output functions are for reading and writing data in a certain format. Format strings specify the type and format of this data. The format string contains placeholders or format specifiers, which start with the % character and are followed by a format specifier character representing the type of data being read or written. Unformatted input/output functions are for reading/writing character data without regard to its format.

Writing to a File.

Unformatted output with fputc

Writes the character value c to the output stream referenced by fp. The prototype is −

int fputc( int c, FILE *fp );

If successful it returns the written character written or EOF if there is an error.

Unformatted output with fputs

Writes a line of characters s to the output stream referenced by fp

int fputs( const char *s, FILE *fp );

It successful it returns a non-negative value otherwise EOF.

Unformatted output with putw

The putw() function writes an integer i to the output stream fp.

int putw( int i, FILE *fp );

If successful it returns a non-negative value otherwise EOF.

Formatted output using fprintf

Writes a formatted string to a specified output stream. The first parameter is a pointer to the output stream. The second argument is a pointer to a char that contains the text to be written and may include format characters. Ellipses represent a variable number of additional arguments.

int fprintf ( FILE * stream, const char * format, ... );

If successful, the total number of characters written is returned. If a writing error occurs a negative number is returned.

When the code below is compiled and executed, it creates a new file test.txt  and writes two lines of text using the fprintf() and fputs() function.

#include <stdio.h>
main() {
   FILE *fp;
   fp = fopen("test.txt", "w+");
   fprintf(fp, "create output file...\n");
   fputs("Use fputs file...\n", fp);
   fclose(fp);
}

Direct output with fwrite

The fwrite() function is used to write records (a sequence of bytes)  to the output stream. The fwrite() function accepts four arguments.  
ptr points to the block of memory which contains the data items to be written.
size specifies the number of bytes of each item to be written.
n is the number of items to be written.
FILE* is a pointer to the file where data items will be written in binary mode.

fwrite( ptr, int size, int n, FILE *fp );

 If successful fwrite returns the number of items successfully written. If an error occurs, the return value may be less than total number of items written

When the code below is compiled and executed, it creates a new file file.txt  and writes the contents of the char array to the output stream using the fwrite() function.

#include<stdio.h>
int main () {
   FILE *fp;
   char str[] = "programming windows";
   fp = fopen( "file.txt" , "w" );
   fwrite(str , 1 , sizeof(str) , fp );
   fclose(fp); 
   return(0);
}

Reading from a file

Unformatted input with fgetc

The fgetc() function reads a character from the input file referenced by fp.  The prototype of fgetc() is-

int fgetc( FILE * fp );

Returns the character read or EOF is there is an error. 

Unformatted Input with fgets

The function fgets() reads up to n-1 characters from the input stream referenced by fp and stores it into the string pointed to by str.

char *fgets( char *str, int n, FILE *fp );

If successful the fgets() function returns a pointer to the string buffer. A NULL return value indicates an error or an end-of-file condition

Unformatted Input with getw

Reads binary data from a file. A pointer to the file stream is the only argument.

int getw(FILE *stream);  

If successful it returns a non-negative value otherwise EOF.

Formatted fscanf file input

The fscanf() function reads formatted input from a file. The parameter fp is a pointer to type FILE returned by fopen(). The parameter fmt is a pointer to the format string that specifies how fscanf() is to read the input. The ellipses ( … ) indicate one or more additional arguments.

int fscanf(FILE *fp, const char *fmt, ...);

On success, the function returns the number of items of the argument list successfully filled.  It returns zero or EOF, if unsuccessful.

When the code below is compiled and executed, it opens the file file.txt  and reads the file contents into the char array str.

#include <stdio.h> 
int main () 
{
char str[20];
FILE * fp;
fp = fopen ("file.txt", "r");
fscanf(fp, "%s", str);
printf("%s\n", str );
fclose(fp);
return(0);
}

Direct input with the fread() 

The fread() function is used to read binary data and is complementary to fwrite(). The fread() function accepts four arguments. 

ptr is the address of the memory block where data is stored after reading. 
size specifies the number of bytes of each item to be read. 
n is the number of items read from the file where each item occupies the number of bytes specified in the second argument.
FILE* is the file from where the data is read in binary mode.

fread( ptr, int size, int n, FILE *fp );

On success, it reads n items from the file and returns n. On error or end of the file, it returns a number less than n.

When the code below is compiled and executed, it opens the file file.txt and reads the contents into char array buffer.

#include<stdio.h>
int main () {
   FILE *fp;  
   char buffer[100];
   fp = fopen("file.txt", "r");
   fread(buffer, 20, 1, fp);
   printf("%s\n", buffer);
   fclose(fp);
   return(0);
}

Sequential Versus Random File Access

Every file IO operation has a position indicator indicating where data is read from and written to. The position is always given in terms of bytes from the beginning of the file.   When the data in a file is read or written sequentially the file indicator position is taken care of automatically.

Manual control over the file position indicator is known as random file access. This means that the programmer can read data from or write data to any position in a file without reading or writing all the preceding data. 

ftell() and rewind() 

To move the position indicator to the beginning of a file, use the function rewind(). The prototype  is

void rewind(FILE *fp);

The parameter fp is the FILE pointer associated with the stream. After calling rewind() the file’s position indicator is set to the beginning of the file (byte 0). 

To determine the value of a file’s position indicator, use function ftell(). The prototype is

long ftell(FILE *fp);

The argument fp is the FILE pointer returned by fopen(). ftell() returns a type long that gives the current file position in bytes from the start of the file (the first byte is at position 0). If an error occurs, ftell() returns -1L

fseek()  

fseek()  sets the position of file indicator to anywhere in the file. The function prototype is

int fseek(FILE *fp, long offset, int origin);

The argument fp is the FILE pointer associated with the file. The distance to move the position indicator is given by offset in bytes, the argument origin specifies the move’s relative starting point.

There can be three values for origin. The symbolic constants are defined in io.h

SEEK_SET 0 – Moves the indicator offset bytes from the beginning of the file.
SEEK_CUR 1 – Moves the indicator offset bytes from its current position.
SEEK_END 2 – Moves the indicator offset bytes from the end of the file.

#include <stdlib.h>
#include <stdio.h>
#define BUFLEN 6
char readdate[] = "abcdefghijklmnopqrstuvwxyz";
int main( void )
{
FILE *fp;
char buf[2];
if ( (fp = fopen("random.TXT", "w")) == NULL)
{
fprintf(stderr, "Error opening file.");
exit(1);
}
if (fputs(readdate, fp) == EOF)
{
fprintf(stderr, "Error writing to file.");
exit(1);
}
fclose(fp);
if ( (fp = fopen("random.TXT", "r")) == NULL)
{
fprintf(stderr, "Error opening file.");
exit(1);
}
printf("\nAfter opening the file the file pointer is at position = %ld", ftell(fp));
fgets(buf,2, fp);//read first character
printf("\nThe character at position zero is %s",buf);
printf("\nNow the file pointer is at position = %ld", ftell(fp));
fseek(fp, 10, 0);//move to pointer to position 10
printf("\nMove position marker to position 10");
fgets(buf,2, fp);
printf("\nThe character at position 5 is %s",buf);
printf("\nMove position marker to start of file");
rewind(fp);//move file pointer to start of file
printf("\nNow the file pointer is at the start of the file = %ld", ftell(fp));
fgets(buf,2, fp);
printf("\nThe current character is = %s", buf);
fclose(fp);
return 0;
}

Detecting the End of a File

There are two ways to detect end-of-file.

Detecting EOF character –  When a character input function reads the EOF this indicates the end of the file

Checking FEOF character –  The function feof() returns 0 if the end of file fp hasn’t been reached, or a nonzero value if end-of-file has been reached. 

File Management Functions

Deleting a File

To delete a file use the function remove(). The prototype is  

int remove( const char *filename );

The variable *filename is a pointer to the file name to be deleted. If the file exists, it is deleted and the remove function returns 0. If the user does not have sufficient access rights, or the file does not exist or is already open then the delete operation will fail returning -1. 

Renaming a File

The rename() function changes the name of an existing disk file. The prototype is

int rename( const char *oldname, const char *newname );

The function returns 0 on success, or -1 if an error occurs. For the function to work the old filename must exist and the new filename must not exist. Both files must be on the same disk.

Temporary file names

A temporary file is a file that is created and used by the program during program execution and then deleted before the program terminates.  The function tmpnam() returns a string containing a unique file name suitable to safely use without risking overwriting any existing files. The prototype is as follows:

char *tmpnam(char *f);

The parameter f must be a pointer to a buffer large enough to hold the filename. A null pointer ( NULL ), means the temporary name is stored in the tmpnam() buffer.  The function returns a pointer to that buffer.

#include <stdlib.h>
#include <stdio.h>
int main()
{
char temp[20]; 
tmpnam(temp);// create temporary name and store in temp buffer 
printf("Temporary name: %s", temp);
return 0;
}

Standard Template Library (STL)

The standard template library (STL) is a set of template classes and functions that supply the programmer with common data structures and functions such as lists, stacks, arrays, sorting, etc utilised through templates.

The STL is comprised of the following components:

  • Containers for storing information.
  • Iterators for accessing the information stored.
  • Algorithms for manipulating the content of the containers.

Containers

Containers are STL classes that are used to store data. Each container class defines a set of functions that may be applied to the container. For example, a list container includes functions that insert, delete, and merge elements. A stack includes functions that push and pop values.

STL supplies provide the following container classes:

  • Sequential containers
  • Associative containers
  • Container Adapters

Sequential Containers

These are ordered collections used to hold data sequentially. Each element holds a position that depends on the time and place of insertion. Adding any object to the end of a vector means that the object will appear in the order that was inserted. Sequential containers are characterised by a fast insertion time but are relatively slow in find operations.

The STL provides five sequence container classes:

std::vector – The vector class implements a dynamic array and thus can grow as needed. Although a vector is dynamic, it still uses the standard array subscript notation to access its elements. Compared to the other dynamic sequence containers, vectors are very efficient at accessing elements and relatively efficient in adding or removing elements from their end. For operations that involve inserting or removing elements at positions other than the end, they perform worse than the other sequence container classes

std::deque – Similar to std::vector except that it allows for new elements to be inserted or removed at the beginning. Unlike vectors, deques are not guaranteed to store all elements in contiguous storage locations. Attempting to access elements by offsetting a pointer to another element will result in undefined behaviour. For operations that involve frequent insertion or removals of elements at positions other than the beginning or the end, deques are less efficient than lists and forward lists.

std::list – These are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions. Compared to other standard sequence containers, lists generally perform better in inserting, extracting, and moving elements in any position within the container. The main drawback of lists and forward_lists compared to these other sequence containers is that they lack direct access to the elements by their position and searching can take extra time. They also consume some extra memory to keep the linking information associated with each element.

std::forward_list – Similar to a std::list except that it is a singly linked list of elements that allows iteration only in one direction. Compared to other base standard sequence containers forward_list generally performs better in inserting, extracting, and moving elements in any position within the container. The main drawback of forward_lists is that like the standard list, they lack direct access to the elements by their position and consume extra resources to keep the linking information current.

std::array class – This is a templated class that provides many benefits over built-in arrays, such as maintaining the array size preventing automatic decay into a pointer, providing bounds checking, and allowing the use of C++ container operations.

Associative Containers

Associative containers utilise sorted data structures that can be quickly searched using keys. This results in slower insertion times but offers significant advantages when searching.

The associative containers supplied by STL are –

std::set 
std::unordered_set
std::map 
std::unordered_map
std::multiset 
std::unordered_multiset
std::multimap
std::unordered_multimap

Container Adapters

Container Adapters offer limited functionality oriented toward a particular container class and provide a more relevant set of functionality. The main adapter classes are:

std::stack — Stores elements in a LIFO (last-in-first-out) fashion, allowing elements to be inserted (pushed) and removed (popped) at the top.

std::queue — Stores elements in FIFO (first-in-first-out) fashion, allowing the first element to be removed in the order they’re inserted.

std::priority_queue — Stores elements in sorted order, such that the one whose value is evaluated to be the highest is always first in the queue.

Iterators

Iterators are template classes that act like pointers. They provide the means to cycle and manipulate the contents of a container in much the same way that you would use a pointer to cycle through an array. There are five types of iterators:

Bidirectional iterator – Store and retrieve values. Moves forward and backward.
Forward iterator – Store and retrieve values. Forward moving only.
Input iterator – Retrieve, but not store values. Forward moving only.
Output iterator – Store, but not retrieve values. Forward moving only.
Random access iterator – Store and retrieve values. Elements may be accessed randomly.

STL Algorithms

Algorithms act on containers. Each container supports its basic operations however the standard algorithms header provides a more extensive range of functionality. One algorithm function can be used on any container type. Algorithms from STL are tried and tested saving time & effort when manipulating data. The algorithm library covers sorting, searching, modifying, non-modifying, and Minimum and Maximum operations.

Vector examples

The following code sample uses vectors to create and manipulate an int vector

#include  <iostream>

#include <vector>
#include <algorithm> 
using namespace std;
int main()
{
vector <int> v; // create zero-length vector
unsigned int i;
cout << "initial size of vector v = " << v.size() << endl;// display original size of v
for(i=0; i<20; i++) v.push_back(i);
cout << "new size of vector v = " << v.size() << endl; // display new size of vector v
cout << "Current contents of vector v:\n";
for(i=0; i<v.size(); i++) cout << v[i] << " ";// display contents of vector v
cout << endl;
cout << "add 5 elements to vector v:\n";
for(i=0; i<5; i++) v.push_back(i+10);//add 5 more values to vector
cout << "new size of vector = " << v.size() << endl;// display current size of v
cout << "Current contents of vector v:\n";
for(i=0; i<v.size(); i++) cout << v[i] << " ";// display contents of vector v
cout << endl;
sort(v.begin(), 
v.end());//sort contents of vector v
cout << "Sort contents of vector v and list\n";
for(i=0; i<v.size(); i++) cout << v[i] << " "; // display contents of sorted vector
cout << endl;
vector <int> v1(10,5);//create new int vector v1 and initialise elements to 5
cout << "create new int vector v1. Initialise elements to 5. Merge with vector v\n";
for(i=0; i < v1.size();i++)
v.push_back(v1[i]);// merged vector v and v1 
for(i=0; i < v.size(); i++)
cout << v[i] << " ";//display contents of v1
cout << endl;
cout << "Clear contents of vector v\n"; v.clear();// clear contents of vector
cout << "new size of vector = " << v.size() << endl;
return 0;
}

The following code sample uses template lists to create and manipulate an int vector

#include <iostream>
#include <list>
using namespace std;
int main()
{
list <int> lst;// create an empty list lst
list <int> lst1; // create an empty list lst1
cout << "create random integer lists: " << endl;
int rn;
for(int a=10;a>0;a=a-1) 
{
lst.push_back(rand()); //add random number to lst
lst.push_back(rand()); //add random number to lst1
}
list<int>::iterator p = lst.begin();//create pointer p and set to start of lst
cout << "output contents of lst: " << endl;
while(p != lst.end()) 
{ //iterate through entire lst 
cout << *p << " "; //output lst value
cout << endl;
p++;
}
lst.sort();
cout << "sort lst: " << endl;
p = lst.begin();
while(p != lst.end()) 
{
cout << *p << " ";//output lst element
cout << endl;
p++;
}
cout << "merge and sort" << endl;
lst.merge(lst1);//merge lst and lst
lst.sort();//sort lst
p = lst.begin();
while(p != lst.end()) 
{
cout << *p << " ";//output lst
cout << endl;
p++;
}
}
 

Memory Map and Free Store

The memory that a program uses is typically divided into a few different areas:

• Global namespace – contains global variables
• The free store (heap) – contains dynamically allocated variables 
• Registers – are used for internal housekeeping functions, such as keeping track of the stack and the instruction pointer.
• Code space – contains the program.
• The stack – is used for storing function parameters, local variables, and other function-related information.

The Free Store

The free store is a large pool of unallocated memory for dynamic allocation during the program execution.  Objects allocated on the free store are manipulated indirectly through pointers. Free store memory is allocated through the new operator and deallocated through the delete operator.  The advantage of the free store is that reserved memory is available until explicitly released. Memory allocated on the free store while in a function will still be available when the function returns.  The disadvantage of the free store is that the reserved memory remains unavailable until explicitly released. Failure to free this memory can build up over time resulting in a memory leak which can result in performance issues and a possible system crash. 

Allocating Space with the New Keyword

Memory is allocated on the free store by using the new keyword followed by the type of object to be created. This tells the compiler how much memory to set aside.  To request new memory for a variable type int using the following –

int *ptr = NULL;//creates a pointer ptr and assigns NULL ptr = new int;// allocated space for an int on the heap and assign is address to pointer ptr

or

int *p = new int

Deallocating Space with the Delete Keyword

When an area of the free store is no longer required, it must be released back to the system. This is done by calling delete on the pointer.  If a pointer variable points to the free store memory and the pointer goes out of scope, the memory is not automatically returned to the free store and becomes unavailable. This is called a memory leak. To release memory back to the free store use the keyword delete – 

delete pPointer;

The code section below illustrates the allocating and deleting of a pointer

#include <iostream>
using namespace std;
int main()
{
int * pInt= new int;//create pointer pInt 
*pInt=7;//assign value 7
cout << "*pInt: " << *pInt << endl;//output value of pInt
delete pInt;//delete pointer
cout << "*pInt after deleting: " << *pInt << endl;//output pointer value
return 0;
}

If there is insufficient space on the heap the request to allocate memory will fail. The new request will be in the form of an exception of type std::bad_alloc.  If “nothrow” is used with the new operator, it will return a NULL pointer. To add a free store request fail exception to the above code segment –

int *pInt = new(nothrow) int; if (!pInt) cout << "allocation of memory failed\n";

Exception Handling

An exception is an error that occurs at run time. External factors, such as insufficient resources, or internal factors such as an invalid pointer can cause exceptions. C++’s exception handling handles run-time errors in a structured and controlled manner. When an exception occurs a program can automatically invoke an error-handling routine to deal with the problem.

C++ exception handling uses the three keywords: try, catch, and throw. Program statements can be monitored for exceptions in a try block. If an exception or error occurs within that try block, it is said to be ‘thrown’. This thrown exception is caught by the appropriate catch statement, which then processes the exception. There can be more than one catch statement associated with any try. C++ provides a list of standard exceptions in addition the user can define their exceptions by overriding exception class functionality. Exceptions can be generated anywhere within a code block using the throw statement.

In the sample code below the user is requested to enter an age value. Entering a value lower than 18 throws a “too young” exception. Entering a non-numeric value results in a “Not correct format” exception.

#include <iostream>
using namespace std;

int main()
{
int iAge;
cout << "Enter Age: ";
cin >> iAge;
try {
if (!cin)                
throw(!cin);         
if(iAge < 18)
throw(iAge);
cout << "\nCorrect Age: " << iAge << "\n\n";
}
catch(int age)
{
cout << "too young";
}
catch(...)
{
cout << "Not correct format \n";
}
cout << "\n";
return 0;
}

C++ Standard Exceptions

-C++ provides a list of standard exceptions defined in the header file. A small sample of these is listed below

ExceptionDescription
std::exceptionbase class for exceptions thrown by the standard library components.
std::bad_allocThrown after a failure to allocate the requested storage space by the operator new.
std::bad_castException is thrown by dynamic_cast when it fails the run-time check
std::bad_exceptionHandles unexpected exceptions in a C++ program.
std::logic_errorreports errors that are a consequence of faulty logic within the program.
std::length_errorThrown when a std::string is too large when created.
std::out_of_rangeAn exception is thrown by dynamic_cast when it fails the run-time check
std::overflow_errorThrown in the event of a mathematical overflow.
std::underflow_errorThrown in the event of a mathematical underflow.

Creating a User-Defined exception class

User-defined exceptions can be created by inheriting and overriding the base exception class found in the <exception> header. Using the std::exception class ensures that all existing exception handlers will automatically scale up to catch your new exception class because they share the same base class.

In the sample code below the user is asked to enter a positive integer value. The input is checked in the try block first for values equal to and then lower than zero. Any unacceptable data will trigger an exception. What() is a public method provided by the exception class. It is used to return the cause of an exception.

#include <iostream>
#include <exception> 
using namespace std;
class checkValue : public exception {
public:
    int initialvalue = 0;

    const char* what() const throw () {
        cout << "Incorrect value";
    }
};
int main() {
    int initialValue = 0;
    cout << "Enter integer value greater than zero ";
    try {
        cin >> initialValue;
        cout << initialValue;
        if (initialValue == 0) throw checkValue();
        if (initialValue < 0) throw checkValue();
        cout << "your value is " << initialValue;
    }    catch (checkValue ex) {
        ex.what();
        cout << ex.initialvalue;
    }
    return 0;
}

Terminating program execution

exit()

This causes an immediate and orderly program termination without performing any regular cleanup tasks. It has the following prototype:

void exit(int status);

The status value is returned as an exit code to the calling code. If this exit code is 0 or EXIT_SUCCESS, a successful termination status is returned to the host environment. Any other value indicates that program termination is due to an error. The constant EXIT_FAILURE can also be used to indicate an unsuccessful termination.

In the code sample below an attempt is made to open a file. If that file does not exist the program execution is terminated

#include <stdio.h>      /* for printf, fopen */
#include <stdlib.h>     /* for exit, EXIT_FAILURE */
void test(){
 printf ("Error opening file");
    exit (EXIT_FAILURE);
}
int main ()
{
  FILE * pFileName;
  pFileName = fopen ("somefile.txt","r");
  if (pFileName ==NULL)
  {
   test();
  }
  else
  {
      printf ("File opened successfully:\n");
  }
  printf ("the end");
  return 0;
}

quick_exit

Call functions registered using at_quick_exit and then terminate the process normally by returning control to the host environment after calling all.

#include <stdio.h>      /* needed for printf */
#include <stdlib.h>     /*needed for at_quick_exit, quick_exit, EXIT_SUCCESS */
void fexit (void)
{
  printf ("Quick exit function.\n");
}
int main ()
{
    at_quick_exit (fexit);
    printf ("Start executions\n");
  quick_exit (EXIT_SUCCESS);
  printf ("Main function block");  // this is never executed
  return 0;
}

atexit

Automatically calls a function when a program terminates normally.

abort()

Causes immediate and abnormal program termination. It does not return any status information to the host environment or perform any orderly shutdown of your program.

assert()

Evaluates an Expression. If this expression evaluates to 0, this causes an assertion failure that terminates the program. It is normally used during debugging to capture programming errors and is disabled after the debugging phase.

#include <stdio.h>    
#include <assert.h>     /* assert */

void fnAssert(int value) {
     printf ("exiting\n");
  assert (value!=1);
 }
int main ()
{
    printf ("start \n");
    fnAssert(1);
    printf ("terminate");
    return 0;
}

The C++ Preprocessor

The preprocessor runs before the compiler examining the code for preprocessing directives. Preprocessor directives operate outside of the scope of the application instructing the compiler to perform certain actions at compile time, such as to ignore certain platform-specific code or include other source files. The result of preprocessing is a single file which is then passed to the compiler. Each directive occupies one line and is characterised by the fact that they all start with a # sign.

The C++ preprocessor contains the following directives: #define, #error, #include, #if, #else, #elif,#endif,#ifdef,#ifndef,#undef,#line,#pragma

#define

#define allows constant values to be declared for use throughout your code that will be substituted for the identifier each time it is encountered in the source file.-

#define MVALUE 1
#define WEBNAME "webaddress.com"

Macros Function when the macro name is encountered, the arguments associated with it are replaced by the actual arguments found in the program –

#include <iostream>
using namespace std;
#define MAX(x,y)(((x)>(y)) ? x : y)
int main()
{
int v1, v2;
v1 = 5;
v2 = 15;
cout << "The maximum value is " << MAX(v1, v2);
return 0;
}

When this program is compiled, the expression MAX(a,b) will be substituted, except that v1 and v2 will be used as the operands.

#include

#include instructs the compiler to include either a standard header or another source file. The standard header’s name is enclosed between angled brackets such as <iostream>. When including another source file, the source file name is enclosed between double quotes such as “sapi.h”.

If the filename is enclosed between angle brackets, the preprocessor searches for it in one or more implementation-defined directories pre-designated by the compiler/IDE. If the filename is enclosed between quotes, the compiler typically searches for it in the same directory as the file containing the directive. If the file is not found in this directory, the search is restarted as if the filename had been enclosed between angle brackets. Since the search path is implementation-defined, it will be necessary to check the compiler’s documentation to check for further details.

Conditional Compilation Directives

These directives allow the selective compilation of a program’s source code. The conditional directives are #if, #else, #elif, #endif, #ifdef and #ifndef.

The #if directive evaluates an expression and then compiles the code based on the evaluation outcome #endif and marks the end of the #if block. The #else and #elif (else if) are used to test for multiple compilation options.

#include <iostream>
using namespace std; 
#define diskspace 40
int main() 
{ 
#if diskspace<=50 
cout << "disk space is lower that 50.\n"; 
#elif diskspace<=100 
cout << "disk space is between 50 and 100.\n"; 
#elif diskspace<=150 
cout << "disk space is between 100 and 150.\n"; 
#else diskspace>150 
cout << "disk space>150\n"; 
#endif 
// ... 
return 0; 
}

#ifdef and #ifndef

refer to whether a macro is defined or not defined-

#include <iostream>
using namespace std;
#define PAUL
int main()
{
#ifdef PAUL
cout << "Paul is defined.\n";
#endif
#ifndef PAUL
cout << "Paul is not defined.\n";
#endif
#ifdef SIMON
cout << "Simon is defined.\n";
#endif
#ifndef SIMON
cout << "Simon is not defined.\n";
#endif
return 0;
}

defined directive – the #if directive used with the defined operator can also be used to determine whether a macro name is defined. in the above code, replacing #ifdef with #if defined PAUL would also work

#undef

The #undef directive is used to remove a previously defined definition of a macro name allowing compartmentalisation of code-

#define VALUE 100
#undef VALUE

#error

The #error directive terminates compilation and outputs the text following the directive. This directive is used primarily for debugging. The declaration syntax is

#error error-message

Double quotes are not used to display the error message. When the compiler encounters this directive, the error message is displayed and then the compilation is terminated.

#line

The #line command changes the value of the __LINE__ and the __FILE__ variable. The variables represent the current line numbers and file respectively

#line 100 "main.cpp"

The above command changes the current line number to 100, and the current file to “main.cpp”.

cout << __LINE__ would print the value 100 and cout << __FILE__ would display the value main.cpp

#pragma

The #pragma directive is a compiler-specific directive that allows various compiler-specific instructions to be given to the compiler.

The # and ## Preprocessor Operators

The # operator causes a replacement-text token to be converted to a string surrounded by quotes-

#include <iostream>
using namespace std;
#define MAKESTRING( x ) #x
int main () {
cout << MAKESTRING(HELLO WORLD) << endl;
return 0;
}

The ## operator is used to concatenate two tokens.

#include <iostream>
using namespace std;
#define combine(x, y) x ## y
int main()
{
int ab = 10;

cout << combine(a,b);
return 0;
}

The preprocessor transforms cout << combine(a, b) into cout << ab;

Predefined Macro Names

C++ specifies a range of predefined macro names. Some of the macros come as standard others are compiler or system-specific –

__LINE__  contains the current line number of the program when it is being compiled.
__FILE__   contains the current file name of the program when it is being compiled.
__DATE__ contains the date of the translation of the source file into object code. This data is represented by a string in the format month/day/year.
__TIME__   contains the time at which the program was compiled. The time is represented in a string in the format hour:minute:second
__STDC__n if defined to 1, the implementation conforms to standard C/C++ code and does not contain any non-standard extensions.
__cplusplus will be defined as a value containing at least 6 digits is the compiler conforms to ANSI/ISO Standard C++. Non-conforming compilers will use a value with 5 or less digits.

When checking the value of non-standard predefined macros check that the macro exists before checking its value-

#include <iostream>
using namespace std;
int main()
{
#ifdef __linux__ //code specific to linux platform
cout << "value __linux__ is ";
cout << __linux__<< endl;
#endif
#  if defined(_WIN32) //code specific to windows 32 bit platform
cout << "value _WIN32 is ";
cout << _WIN32 << endl; 
#endif 
#if defined(_MSC_VER) //code specific to MS Visual Studio
cout << "value _MSC_VER is ";
cout << _MSC_VER << endl; 
#endif    
#if defined(__MINGW64__) //code specific to MS Visual Studio
cout << "value __MINGW64__ is ";
cout << __MINGW64__<< endl; 
#endif 
#if defined(__GNUC__) //code specific to GNUC compiler
cout << "value __GNUC__ is ";
cout << __GNUC__<< endl; 
#endif
#if defined(_WIN64) //code specific to windows 64 bit platform
cout << "value _WIN64 is ";
cout << _WIN32 << endl; 
#endif 
return 0;
}

Input and Output Streams

Like C, the C++ language does not have input/output access built into the language. IO is achieved by using external library functions. A library is a collection of object files that can be linked to a program to provide additional functionality.

C++ IO is based on streams, which encapsulate the data flow in and out of input and output devices. With input operations, data bytes flow from an input source such as a keyboard or file into the program. In output operations, data flows from the program to an output destination such as a console or file.

Some of the more common stream classes included in C++ are

fstream – Stream class to both read and write from/to files..Inherits from ofstream and ifstream.
cout – Standard output stream. Typically redirected to the console.
cin – Standard input stream. Typically used to read data from the console
ofstream – Stream output class typically used to write to files
ifstream – Stream input class typically used to read files
cerr – standard output stream for errors

cin

The global object cin is an object is used to handle input. It is found in the iostream header file. The cin object is used with the extraction operator (>>) to receive a stream of characters. The general syntax is:

cin >> varName;

The extraction operator can be used more than once to accept multiple inputs as:

cin >> var1 >> var2 >> var3;

Inputting Strings

Cin can also accept character pointer ( char* ) arguments by creating and filling a character buffer –

char userName[50]
cout << “Enter name: “;
cin >> userName;

The username in the above example will contain the characters entered at the keyboard terminated by the null character (\0) which signals the end of the string. The buffer must have enough room for the entire string plus the null. A space or new line, signifies the end of the input, and a null character is inserted.

Some additional member functions of cin

cin.get() – returns the first value of the character in an input sequence
cin.get( pCharArray, StreamSize, TermChar ) – is used to fill a character array. the first parameter is a pointer to that character array, the second parameter is the maximum of characters that can be read, and the 3rd is the termination character
cin.ignore(nCount,delim) – extracts and discards up to nCount characters. Extraction stops if the delimiter delim is extracted or the end of the file is reached.
cin.peek() – returns the next character in the input sequence, without extracting it.
cin.putback() – puts the last character extracted from the input stream by the get() function back into the input stream.

The code sample below demonstrates different ways of using the cin function.

#include <iostream>
using namespace std;
int main()
{
char YourName[50];
int age;
cout << "Enter your name and age separated by a space ";
cin >> YourName>>age;//Separating input using a space has the same effect as using return
cin.ignore(256, '\n');//used to clear input stream
cout << "Your name is "<< YourName << " and you age is " << age << std::endl;
char a,b,c;
cout << "Enter 3 letters ";
cin.get(a).get(b).get(c);//reads in 3 characters
cin.ignore(256, '\n');
cout << a << endl << b << endl << c << endl;
cout << "Enter your favourite colour (max 20 characters)";
char word[20];
cin.get(word, 20);//reads first 20 characters in input stream
cout << "you favourite colour is " << word << endl;
return 0;
}

cout

The global object cout is an object of class ostream and with the overloaded insertion operator ( << ) is used to handle the output. It is found in the iostream header file. The general syntax is:

cout << value;

Or

cout << "string value";

The extraction operator can be used more than once with a combination of values:

cout << value1 << "String" << value2 << endl;

Some Additional Member Functions of cout

cout.put(char c) – used to write a single character to the output device.
cout.write(const *char, int n) – works similarly to the insertion operator ( << ) except that the parameter n tells the function the number of characters to write
cout.setf(option) – sets a format flag.
cout.unsetf(option) – clears a format flag.
cout.precision(int n): – sets the decimal precision to n while displaying floating-point values

The code sample below demonstrates different ways of using the cout function.

#include <iostream>
using namespace std;
int main()
{
cout.put('H').put('e').put('l').put('l').put('o').put('\n');
char message[]="Hello world";
cout.write(message, 11) << "\n";
cout << "position 1";
cout.width(30);
cout  << "position 2";
cout.width(30);
cout  << "position 3";
cout << "\n";
cout.setf(ios::showpos);
float value=22;
cout.precision(3);
cout << "the value of pi to 2dp="<< value/7 << endl;
int hexvalue=10;
cout.setf(ios_base::hex|ios_base::uppercase) ;
cout <<"the value of 10 in hex is " << hex << hexvalue;
return 0;
}

File Input and Output

C++ provides the following classes to perform input and output to and from files:

ofstream: Stream class to write on files
ifstream: Stream class to read from files
fstream: Stream class to both read and write from/to files.

Before any file ofstream or ifstream object is created, the stream must be associated with a particular file. The iostream objects maintain various flags that report on the status of the file operations.

Opening Files for Input and Output

To open a file for output with the ofstream object, declare an instance of an ofstream object and pass in the filename as a parameter –

ofstream fout(“filename.cpp”);

To open a file for input with the ifstream object, declare an instance of an ifstream object and pass in the filename as a parameter –

#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char fileName[80]="myfile";
char filebuffer[255];
ofstream fout(fileName); // open for file writing data
cout << "Enter some text to store in the file: ";
cin.getline(filebuffer,255); // get the user input
fout << filebuffer << "\n";// write input to the file
fout.close(); // close the file, ready for reopen
ifstream fin(fileName); // reopen for reading
cout << "The contents of your file are:\n";
char ch;
while (fin.get(ch))
cout << ch;
fin.close();
return 0;
}

File Opening Modes

A file can be opened in different modes to perform read and write operations.
These are –

ModeExplanation
ios :: inOpen a file for reading
ios :: outOpen a file for writing
ios :: appAppends data to the end of the file
ios :: ateFile pointer moves to the end of the file but allows data to be written to any location in the file
ios :: binaryBinary File
ios :: truncDeletes the contents of the file before opening

The default behaviour when using ofstream to open a file is to create a file if it does not exist and to delete or truncate all its contents.

In the sample code below the program first checks for the existence of ‘myfile’. If the file does not exist the user is asked to enter some data. If the file exists the user is asked whether they want to replace or amend the contents. The contents are then output to the console.

#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char fileName[80]="myfile";
char filebuffer[255]="";
char response='y';
ifstream fin(fileName); // open for file writing data
if (fin) // check if file already exists?
{
cout << "File already exists. Do you wish to replace file contents y/n";
cin >> response;
fin.close();
}
if (response=='y')
{
ofstream fout(fileName,ios::trunc); // open for file writing data.replace contents  
cout << "Enter some text to store in the file: ";
cin.ignore();
cin.getline(filebuffer,255);
fout << filebuffer<< endl;// write input to the file
fout.close();
}
else
{
ofstream fout(fileName,ios_base::out|ios::app); //open file and append data
cout << "Enter some text to add to the file: ";
cin.ignore();
cin.getline(filebuffer,255); // get the user input
fout << filebuffer << endl;// write input to the file
fout.close();   
}
fin.open(fileName); // reopen for reading
cout << "The contents of your file are:\n ";
char ch;
while (fin.get(ch))
{
cout << ch;
}
fin.close();
return 0;
}

Checking I/O state flags

The following member functions exist to check for specific states of a stream. All return bool value:

bad() – returns true if a reading or writing operation fails. For example, trying to write to a file that is not open.
fail() – detects whether the value entered fits the value defined in the variable.
eof() – returns true if a file open for reading has reached the end.
good() – checks whether the state of the stream is good. Returns true if none of the stream’s error state flags are set
clear() – used to reset the state flags.

Binary files

Text files store everything as text in a human-readable format. This can be inefficient but has the advantage that the text can be read using programs such as simple text editors. A binary file contains a sequence of bytes not in a human-readable format. The process of writing to a binary file is similar to writing to a text file with the exception that the file I/O object must stipulate ios_base::binary flag as a mask when opening the file.

A binary file stream object can be opened as follows

ifstream myFile (“myfile.bin”, ios::in | ios::binary);
or by call to its open methods after the file stream object has been instantiated
ofstream myFile;
myFile.open (“myfile.bin”, ios::out | ios::binary);

Writing to and reading from a binary file

In general, there are two ways to write and read unformatted binary data to or from a file. Data can be written to a file using the member function put(), and read using the member function get(). Alternatively, a program can read and write to a binary file using the block access I/O functions: read() and write()

The code section below indicates how the get() function can be overloaded in several different ways to read data-

#include <fstream>
#include <iostream>
using namespace std;
int main()
{
char *message = "hello world";
char ch;
char buffer[12]="buffer";
//create file test
ofstream out("test", ios::out | ios::binary);
if(!out) {
cout << "Cannot open file.\n";
return 1;
}
//write contents of message to file
while(*message) out.put(*message++);
out.close();
ifstream in("test", ios::in | ios::binary);
if(!in) {
cout << "Cannot open file.\n";
return 1;
}
//read in file contents and write out to screen
while(in) { //false when eof is reached
in.get(ch);
if(in) cout << ch;
}
in.clear();
in.seekg(0);//move pointer to start of file
in.get(buffer,12);//get first 12 characters in file 
cout << endl << buffer << endl;
in.clear();
in.seekg(0);
in.get(buffer,12,' ');//read in characters after space
cout << buffer << endl;
in.clear();
in.seekg(6);//move pointer to position 6 in file
in.getline(buffer,12,'\n');//read in character upto new line
cout << buffer << endl;
return 0;
}

The code function below illustrates reading and writing to a binary file using the block access I/O functions: read( ) and write( )

#include <fstream>
#include <iostream>
using namespace std;

int main()
{
int array[5] = {10, 20, 30, 40, 50};
int i;
ofstream out("myfile", ios::out | ios::binary);
if(!out) {
cout << "Cannot open file.\n";
return 1;
}
out.write((char *) &array, sizeof array);
out.close();
for(i=0; i<5; i++) // clear array
array[i] = 0;
ifstream in("myfile", ios::in | ios::binary);
if(!in) {
cout << "Cannot open file.\n";
return 1;
}
in.read((char *) &array, sizeof array);
for(i=0; i<5; i++) // show values read from file
cout << array[i] << " ";
in.close();
return 0;
}

Random Access

In addition to reading or writing files sequentially, file data can be accessed in random order using the seekg( ) and seekp( ) functions. The C++ I/O system manages two pointers associated with a file. One is the get pointer and the other is the put pointer. The put pointer specifies where the next file input operation will occur. The get pointer specifies where the next file output operation will occur. Each time an input or an output operation occurs, the appropriate pointer is automatically adjusted. Using the seekg( ) and seekp( ) functions, it is possible to adjust these pointer values in a non-sequential fashion. The seekg( ) function moves the file’s get pointer and the seekp( ) function moves the file’s put pointer.

In the sample code below a file is created and text added. The position of the put and get pointers is reported using the seekg and seekp method.

#include <fstream>
#include <iostream>
using namespace std;
int main() {
    char buffer[40] = "";
    fstream data;
    data.open ("myfile", ios::in | ios::out );//open fstream for input and output
    int newpos=data.tellp();//get position of put pointer at start
    cout << buffer <<"position of put pointer at start " << newpos << endl;
    data.write("hello world", 11);//write data to file
    newpos = data.tellp();//get position of put pointer 
    cout << buffer <<"position of put pointer of first write " << newpos << endl;
    data.seekg(0); //reposition get pointer to start of file
    newpos = data.tellp();//get position of put pointer after adding text
    cout << buffer <<"position get pointer at start of file " << newpos << endl;
    data.read(buffer, 11);//read file data to buffer
    cout <<"file contents - " << buffer << endl;
    newpos = data.tellp();//get position of put pointer
    cout <<"position of get pointer after reading from file " << newpos << endl;
    data.write(" from me", 9);//add new string to end of file
    newpos = data.tellp();//get position of put pointer
    cout <<"position of put pointer after 2nd write " << newpos << endl;
    data.seekg(0); //reposition get pointer to start of file
    data.read(buffer, 19);//read file data to buffer
    cout << buffer;
    return 0;
}

Namespace

Namespaces organise identifiers such as variables, functions, and classes into logical groups. This allows the global namespace to be arranged into different scopes preventing any naming collisions when the codebase includes multiple libraries. Inside a namespace, identifiers declared within that namespace can be referred to directly, without any namespace qualification. To refer to objects from outside the namespace scope use the scope resolution operator preceded by the name of the namespace. It’s possible to declare more than one namespace with the same name thus allowing a namespace to be split over several files, or even separated within the same file.

A namespace definition begins with the keyword namespace followed by the namespace name and the list of identifiers enclosed within curly brackets.

#include <iostream>
namespace ns //creates namespace ns 
{ 
int x=1, y=5; 
double value() 
{ 
return x+y; 
} 
} 
using namespace std; 
int main () 
{ 
cout << "x after call: " << ns::value(); //call function value in namespace ns 
cout << endl; 
return 0; 
}

The Using Directive

To avoid the perpetual use of the scope resolution operator when referring to the members of the namespace, the using directive tells the compiler that the subsequent code is using names in the specified namespace defined by the using directive.

#include <iostream>
using namespace std;
namespace first_nspace {// define 1st name space 
void func() 
{
cout << "first name space" << endl;
}
}
namespace second_nspace { // define 2nd name space
void func() 
{
cout << "second name space" << endl;
}
}
using namespace first_nspace; //set first_nspace as default 
int main () 
{
func(); //Calls func() from first and default name space.
second_nspace::func();//Calls func() from 2nd name space using scope resolution.
return 0;
}

Unnamed Namespaces

Unnamed namespaces allow the creation of unique identifiers that are known only within the scope of a single file. Members of that namespace may be used directly, without qualification however outside the file, the identifiers will not be recognised.

If a file contains the following declaration-

namespace {
int v=10;
}
void f1( ) {
cout << v; 
}

The same variable v will not be recognised outside that file-

extern int v;
void f2( ) {
cout << v; // error
}

The std Namespace

The standard C++ library is contained within a namespace called std. The directive using namespace std allows this standard library to be brought into the current namespace without having to qualify each reference with the prefix std::. If a program is only making limited use of the standard C++ library it may make more sense to use the define statement on an individual basis –

#include <iostream>
using std::cout; //allows cout to be used in current namespace
using std::cin;  //allows cin to be used in current namespace
int main()
{
double val;
cout << "Enter a number: ";
cin >> val;
cout << "This is your number: ";
cout << val;
return 0;
}

Nested Namespaces

Namespaces can be defined inside another namespace. To access members of nested namespace use the resolution operator

#include <iostream>
using namespace std;
namespace first_nspace {// first name space
void func() 
{
cout << "first name space" << endl;
}
namespace nested_nspace {//nested name space
void func() 
{
cout << "nested second_space" << endl;
}
}
}
//include nested scope within current scope
using namespace first_nspace;
int main () 
{
func();//call func() from with existing scope 
first_nspace::nested_nspace::func();//call func() using scope resolution operator
return 0;
}

The STL String Class

The standard C++ library provides a string class type that supports string operations and manipulations. Unlike a standard character array, the string class can dynamically resize itself and offers methods that help manipulate the string.

To instantiate and initialise a standard string object –

std::string str2 ("Hello String!");

or

const char* cStyleConstString = "This is a string";
std::string newString (cStyleConstString);

Instantiating a string object does not require the programmer to stipulate the length of the string or the memory allocation details because the constructor of the STL string class automatically does this.

Accessing Character Contents of a std::string

The contents of an STL string can be accessed via iterators or an array-like syntax using the subscript operator [] and offset.  The following code lists all the characters in string mystring.

#include <string>
#include <iostream>
int main ()
{
using namespace std;
string myString ("Hello World"); // declare and initialise the string mystring
cout << "list elements in string using array-syntax: " << endl;
for (int charCounter = 0; charCounter < myString.length();++ charCounter) {
cout << "Character " << charCounter << " =";
cout << myString [charCounter] << endl;
}
cout << endl;
return 0;
}

A further demonstration of some string class methods

#include <string>
#include <iostream>
#include <algorithm>
int main ()
{
using namespace std;
string word="hello world";//create and initialise string word
cout << "Original sting-" << word<< endl;
transform(word.begin(), word.end(), word.begin(), ::toupper);//transform string word to upper case
cout << "uppercase sting-" << word << endl;
reverse (word.begin (), word.end ());//reverse characters in string word
cout << "reverse sting-" << word << endl;
reverse (word.begin (), word.end ());//reverse characters in string word 
word.erase (5, 6);//erase final 6 letters in string word
cout << "erase first 5 characters-" << word << endl;
cout << "enter you name" << endl;
string usr_name;
cin >> usr_name;//input string value
word += " ";
word += usr_name;//add user name to word
cout  << word <<endl;
return 0;
}