At the end of this chapter, you should be able to
Understand functions and function templates and how C++ handles function execution.
Understand the memory mapping adopted by C++ and storage classes.
Program C++ with the help of macros and preprocessor directives.
Understand the concepts and use array and string data structure.
It is common knowledge that experts who are dedicated to a particular job will perform the job better and faster. We approach architects for making functional and aesthetic housing. Similarly, we hand over control to doctors to take care of our health. In C++ language, we hand over jobs to functions specially written for the purpose. Similarly, if we can make a function perform more than one task depending on the requirements of the user, then such programs are not only efficient but are also versatile. We can use function templates, so that a single function can handle all types of data.
This chapter also introduces you to the C++ way of handling storage and memory. The variables are stored based on the storage specifiers we use while declaring the variable. These are called storage classes. The storage in turn decides the access times. Preprocessor directives are directives issued to compilers for efficient execution of programs. This chapter introduces the reader to concepts involved in these directives. Arrays and strings are derived data types and most widely used features of C++. Several problems are included in examples and exercise problems to fortify the concepts involved. From now on, we print line numbers only when we have something new to tell you.
The idea is to divide the main problem into smaller modules and write functions to implement the modules. The main function in C++ language is called: main(). Interestingly, it is also a function, albeit a main function. Main() function calls other functions. Calling function is one which calls a called function. The function prototype is declared before, void main(), in the global area, so that it is accessible by all other functions. The syntax is:
void main () calls the function FindMax() by supplying the arguments and receives the result through return type.
ans = FindMax ( a, b ) ; // a,b, and ans are all integer data types
Function Definition is given after main program as
int FindMax ( int a , int b , int c) // note the absence of semicolon
{// Function Code here}
Functions handle data. There are several intrinsic data types supported by C++ like int, float, double, etc. Suppose we need a function to sort the given data. The data could be data of integers or data of floats or data of double. Do we write a separate function for each of the data types or is there a tool or method wherein one function takes care of all data types. Function template is the solution provided by C++. The format for declaring function templates with type parameters is:
template <class identifier> function_declaration;
template <typename identifier> function_declaration;
For example, we could declare a function template for finding a maximum of two numbers as
Template<class T>
T FindMax( T a , T b);
Below the main function, we could define the template function as
Template <class T>
T FindMax(T a , T b) { return ( (a>b) ? a : b ) ; }
While at the time of declaration or definition, we do not know the data type of T, we can use it as data type T and forward data type as parameter. We would call the function as follows:
function_name <type> (parameters);
FindMax <int> (x,y); // x & y are data type integers
Example 8.1: A Template Function Based cpp for Computing the Maximum of Two Numbers. Function Template: FindMax.cpp
#include <iostream>
using namespace std;
//fn template definition
template <class T>
T FindMax (T a, T b);
void main ()
{ int i=50, j=70, k;
long int x=75000, y=98000, z;
k=FindMax<int>(i,j);
z=FindMax<long int>(x,y);
cout << «
Larger of the two integers : «<<i<<» & «<<j<<» : «<< k << endl;
cout << «
Larger of the two long integers : «<<x<<» & «<<y<<» : «<< z << endl;
}
//fn template definition
template <class T>
T FindMax (T a, T b)
{T max;
max = (a>b)? a : b;
return (max);
}
//Output :Larger of the two integers : 50 & 70 : 70
Larger of the two long integers: 75000 & 98000 : 98000*/
A function template can accept two parameters of different types and return value of any one of the parameters. Consider the declaration
long int a ; int b;
template< class S , class T>
T FindMax( S a , T b) { return ( ( a>b)?a:b );} . The compiler will do
necessary type conversions and return data type of T
Mode of data transfer between calling function and called function, by copying variables listed as arguments into called function stack area and, subsequently, returning the value by called function to calling function by copying the result into stack area of the main function is called Call by value. Note that as copying of the variables, both for forward transfer and return transactions, are involved, it is efficient only if values to be transferred are small in number and of basic data type.
Example 8.2: swap.cpp. A Program to Demonstrate Concepts of Functions So Far Discussed and also Bring Out Concept of Pass by Value
#include<iostream>
using namespace std;
// function prototype declarations
template<class T>
void Swap ( T x , T y); // to interchange values
void main() //Calling Function
{ float x=100.00; // x & y are local to main()
float y=1000.00;
int a=5 , b=10;
cout<<”
Before calling Swap function <x and y >”<< x<<” ”<<y<<endl;
cout<<”
Before calling Swap function <a and b >”<< a<<” ”<<b<<endl;
// call the function and pass arguments x & y
Swap(x,y); //Called Function
Swap(a,b); //Called Function
cout<<”
After return from Swap <x and y >”<<x<<” ”<<y<<endl;
cout<<”
After return Swap function <a and b >”<< a<<” ”<<b<<endl;
}//end of main
// function definition
template<class T>
void Swap ( T x , T y)
{ float temp ; // temp is local to Swap function
temp = x; // store x in temp
x=y; // store y in x
y=temp; // store temp in y
cout<<”
Inside Swap <x and y >”<<x<<” ”<<y<<endl;
} // end of Swap//
//output :Before calling Swap function <x and y >100 1000
Before calling Swap function <a and b >5 10
Inside Swap <x and y >1000 100
Inside Swap <x and y >10 5
After return from Swap <x and y >100 1000
After return Swap function <a and b >5 10*/
There are two important lessons to be learnt here. Firstly, notice that function template for Swap function has handled for two sets of data, i.e. x and y of float data type and a and b of integer data type. That is the power and utility of function template. Secondly, observe the output. While the function Swap has done its job of interchanging the values of x and y, as shown by cout statement inside Swap in the main program, the values did not interchange. What does this mean? The answer lies in the fact that variable values and operations you do on them are local to block, i.e. local to function Swap. It has no connection with variables x and y belonging to the main() function.
Indeed, main() function passes arguments by copying these values into stack area of the function Swap. It is like passing a xeroxed document and retaining the original. Obviously, the changes you make on the xerox copy will not be reflected on the original.
For large data items occupying large memory space like arrays, structures and unions, overheads like memory and access times become very high. Hence, we do not pass values as in call by value; instead, we pass the address to the function. Note that once function receives a data item by reference, it acts on data item and the changes made to the data item also reflect on the calling function. This is like passing address of original document and not a xerox copy. Therefore, changes made on the original document applies to the owner of the document as well. Let us see how our Swap program behaves when we pass the variable by reference, i.e. by passing address of variable, as we intended by reflecting the changes made in the function in the calling function as well.
Example 8.3: RefSwap.cpp to Demonstrate the Concept of Passing of Variable by Reference
#include<iostream>
using namespace std;
// function prototype declarations
template<class T>
void Swap ( T & x , T & y); // to interchange values by reference
void main() //Calling Function
{ float x=100.00; // x & y are local to main()
float y=1000.00;
int a=5 , b=10;
cout<<”
Before calling Swap function <x and y >”<< x<<” ”<<y<<endl;
cout<<”
Before calling Swap function <a and b >”<< a<<” ”<<b<<endl;
// call the function and pass arguments x & y
Swap(x,y); //Called Function
Swap(a,b); //Called Function
cout<<”
After return from Swap <x and y >”<<x<<” ”<<y<<endl;
cout<<”
After return Swap function <a and b >”<< a<<” ”<<b<<endl;
}//end of main
// function definition
template<class T>
void Swap ( T &x , T &y)
{ float temp ; // temp is local to Swap function
temp = x; // store x in temp
x=y; // store y in x
y=temp; // store temp in y
cout<<”
Inside Swap <x and y >”<<x<<” ”<<y<<endl;
} // end of Swap//
//output : Before calling Swap function <x and y >100 1000
Before calling Swap function <a and b >5 10
Inside Swap <x and y >1000 100
Inside Swap <x and y >10 5
After return from Swap <x and y >1000 100
After return Swap function <a and b >10 5*/
For group and user-defined data structures, like structures and unions, call by value method is inefficient. Instead, we will employ call by reference method to move large data items. Study the following example. Sort.cpp. A program to demonstrate passing of array by reference. In this example, we will pass the array of integers by reference to a function called intsort, which sorts the array in the ascending order.
Example 8.4: Sort.cpp. A Program to Demonstrate Passing of Array by Reference
#include<iostream>
using namespace std;
// function prototype declarations
template<class T>
void Sort( int n , T a[]); // receives number of items & array
void main()
{ int i,n=10;// number of items
int a[] ={ 67,87,56,23,100,19,789,117,6,1}; // array with 10 elements
double b[] = { 18.0,87.9,92.1,1.0,5.0,8.7,78.99,34.0,21.5,10.0};// array of double
cout<< “
Given integer array”<<endl;
for (i=0;i<n;i++)
cout<<” “<<a[i];
// we are passing array a. Note that array name is ‘a’ . Name is address.
Sort(n,a);
cout<<”
Sorted integer array
”;
for (i=0;i<n;i++)
cout<<” “<<a[i];
cout<< “
Given double array”<<endl;
for (i=0;i<n;i++)
cout<<” “<<b[i];
// we are passing array b. Note that array name is ‘b’ . Name is address.
Sort(n,b);
cout<<”
Sorted double array
”;
for (i=0;i<n;i++)
cout<<” “<<b[i];
}//end of main
// function definition
template<class T>
void Sort(int n , T a[])
{ for ( int i=0; i< n-1; i++) // last value need not be sorted
{ T temp;
// find the smallest of remaining numbers and exchange it with for ( int j=i+1; j< n; j++)
{ if (a[j] < a[i])
{ // swap
temp=a[i];
a[i]=a[j];
a[j]=temp;
}
}
}
}
//Output : Given integer array
67 87 56 23 100 19 789 117 6 1
Sorted integer array
1 6 19 23 56 67 87 100 117 789
Given double array
18 87.9 92.1 1 5 8.7 78.99 34 21.5 10
Sorted double array
1 5 8.7 10 18 21.5 34 78.99 87.9 92.1*/
As array is a data structure comprising several data types, compiler passes it as reference. Note that we have called Sort(n,a); 'a' means name of the array. Name means the address of the array. In effect, we have given the address of the array to Sort function. The algorithm we have used for sorting integers is simple, though not very efficient. We will learn more about call by reference through usage of pointers.
When you pass a variable by reference, because of its large size, there is a danger that receiving function can alter the value. If you want to prevent the function from changing the value, there is a provision to pass by constant reference.
Example 8.5: callbyconstref.cpp: Passing Constant Reference to a Function
#include<iostream>
using namespace std;
// function prototype declarations
void PrintNetPay(const float & BP , float & cr , float db); void main()
{ float bp=2000.00, cr = 0.60*bp, db = .25*bp;
// we are passing variables by value , by reference and by constant reference
PrintNetPay(bp,cr,db);
}//end of main
// function definition
void PrintNetPay(const float &bp, float & cr , float db)
{ float total = bp+cr-db;
//bp+=1000.00; // error . l-value specifies const object. constant reference .
//Hence cannot be altered. Hence commented out
cout<<”
Total Net Pay = “<< total<<endl;
}
//Output :Total Net Pay = 2700 */
Recursion is an advanced feature supported by C++ language. Recursion means a function calling itself. Consider the problem of finding a factorial of a number. In the example, we can clearly see that Fact(5) is calling Fact(4) and so on.
Fact(5) = 5 x 4 x 3 x 2 x 1
= 5 x Fact(4)
= 5 x 4 x Fact(3)
= 5 x 4 x 3x Fact(2)
= 5 x 4 x 3x 2 x Fact(1)
= 5 x 4 x 3x 2 x 1 x Fact(0)
= 5 x 4 x 3x 2 x 1 ( Fact(0) =1)
Example 8.6: factrecur.cpp A Program for Finding Factorial of a Number Using Recursion
#include<iostream>
using namespace std;
// function prototype
int fact(int a);
void main()
{ int x,ans;
cout<<»enter a number:»;
cin>>x; //input from the user*/
ans=fact(x); //function call*/
cout<<»
factorial=»<<ans<<endl;
} //end of main*/
int fact(int a) //function definition*/
{ int ans;
if(a<=0)
return(1); // fact(0) = 1 by definition
else
ans =a*fact(a-1); //function call with recursion*/
return(ans); //returns the value of fact to main*/
} //end of function fact*/
// Output: enter a number:7 factorial=5040*/
Each time a function is called there are some overheads like saving the current address, branching off to code area where function code area, passing arguments and returning to main function on completion of execution of function. For large functions, this process is justifiable, but for one or two line body functions, this lengthy and resource-consuming process is not justifiable. Hence, C++ has provided inline function.
template<class T>
inline void FindMax( T & a , T & b ){ return ( (a > b) ? a : b ) ; }
When compiler sees the keyword inline, it places the entire code for FindMax rather than resorting to its usual function-handling technique, thus saving the overheads associated with C++ way of handling functions. Caution: Using inline functions for large functions can be counterproductive as entire functions are reproduced for each call of the function. Therefore, use inline functions for one or two line functions with short codes. Functions declared and defined inside the class definition are inline functions automatically, though you might not have used the keyword inline.
When a single function can do more than one job, then again overheads of the compiler get reduced. For example, if one wants to compute the area of a circle, the surface area of a football as well as the surface area of a cylinder. How many functions does one have to write? Normally, three functions. But in C++ one function overloaded to perform all the three jobs is sufficient. Overloaded functions decide which version of the code is to be loaded into primary memory depending on the argument supplied by the user. Why is overloading important? Functions have to be compiled and loaded into primary memory. If a function is NOT overloaded, all the functions have to be loaded and linked at compile time itself. The user may or may not use all the functions loaded, thus wasting primary memory and making it unavailable to solve complex problems requiring more primary memory
// one argument area of circle
template<class T>
inline void FindArea( T & r ){ return ( 2*3.14158*r*r ) ; }
// two argument surface area of the cylinder
template<class T>
inline void FindArea( T & r , T &h ){ return ( 4*3.14158*r*h ) ;
}
Functions accept arguments and perform their job. But what happens if you do not supply the values for the arguments? There is a provision in C++ to specify the default option. If you supply the arguments, the function would adopt them; if you do not supply the values for the arguments the function will assume default options. You can specify the default option for all or only for part of the arguments, but specifying default options must commence from left to right. It is illegal (compiler error) to specify default values for right edge arguments.
float FindVolume( float l=10.0, float b=20.0 , float h=30.0); //
default for all . O.K.
float FindVolume( float l=10.0, float b=20.0 , float h); // default
only for l & b. O.K.
float FindVolume( T l=10.0, T b , T h); // default only for l . O.K.
float FindVolume( float l, float b , float h=30.0); // default only
for h . Not O.K.
We must supply default arguments from left to right. You cannot specify default value for h without specifying values for l and b. In the example program that follows, we will show the working of inline functions, function overloading and default functions. The problem is to find the area of different objects like circle, cylinder, etc. The function, FindArea() will be overloaded to achieve area of square or area of rectangle, depending on whether the user supplies one argument or two arguments. Of course, we will use inline function templates as usual for practice:
Example 8.7: fnoverload.cpp A Program to Show fn Overloading
#include<iostream>
using namespace std;
// function prototype declarations
template<class T>
inline T FindArea( T r ){ return ( r*r ) ; }
// two argument surface area of the cylinder
template<class T>
inline T FindArea( T r, T h ){ return ( r*h ) ; }
inline int FindSum( int a=10 , int b=20 , int c=30) { return a+b+c ;}
void main() //Calling Function
{cout<<”
Function overloading for Different Number and Different Types of Arguments”<<endl;
cout<<”
calling FindArea(r) function < r >-integer argument:”<<FindArea(10)<<endl;
cout<<”
calling FindArea( r , h ) function - float 2 arguments :”<<FindArea(10.5,20.5)<<endl;
cout<<”
calling FindArea( r , h ) function - integers 2 arguments :”<<FindArea(10,20)<<endl;
cout<<”
***********************”<<endl;
cout<<”
a and b and c values set as default values are :”<<10<<” ”<<20<<” ”<<30<<endl;
cout<<”
FindSum with no arguments supplied “ <<FindSum()<<endl;
cout<<”
FindSum with : a (one ) arguments supplied “<<100<<” ”<<FindSum(100)<<endl;
cout<<”
FindSum with : a and b (two ) arguments supplied”<<100<<” ”<<200<<” ” <<FindSum(100,200)<<endl;
cout<<”
FindSum with : a and b (two ) arguments supplied”<<100<<” ”<<200<<” ”<<300<<” ”<<FindSum(100,200,300)<<endl;
}
//Output: Function over loading for Different Number and Different Types of Arguments
calling FindArea(r) function < r >-integer argument:100
calling FindArea( r , h ) function - float 2 arguments :215.25
calling FindArea( r , h ) function - integers 2 arguments :200
a and b and c values set as default values are :10 20 30
FindSum with no arguments supplied 60
FindSum with : a (one ) arguments supplied 100 150
FindSum with : a and b (two ) arguments supplied100 200 330
FindSum with : a and b (two ) arguments supplied 100 200 300 600*/
The following table gives details of memory management of C++. It is important that you clearly understand the concept.
Memory can be broadly divided into data area or code area also called data segment and code segment. Based on the requirements of access times, scope and life of variables, the memory is divided into global, heap, code area, stack and static area, as shown in Table 8.1.
Table 8.1 Memory organization of C++ language
Global: Include section, function declarations, structures and global variables | All declarations and definitions are accessible to all the functions. |
Heap Memory: Access to heap memory is only through pointers i.e. through New and delete functions | Memory remaining after allocating space to global, code and stack/static variables |
Code Area: The C++ code, Functions etc. are stored in this section | Code for all functions is stored here |
Stack Variables: All variables you declare are stores on Stack. Also called Stack variables | Life of variable is till life of function in which it is declared, called local variables |
Static Variables: | Life of static variable is till of main (). Accessible to all Functions |
Global Variables: These are declarations such as include sections, define statements, function prototype declaration, and declarations of structures and unions, which have scope that extends to all functions. It means that any variable declared in global section can be accessed by all functions. This section appears before the main () function.
Code Area: All the functions and their codes are stored here.
Stack Area: All the variables declared in a function are automatically allocated space in the stack area of the memory. The scope of the variable is local. This means that a variable declared in a function is accessible only within the function. Further, the life of variables declared within the function is life of the function itself, i.e. within the brace brackets of the function. Hence, these variables are called local variables or automatic or autovariables. Consider the example given in Table 8.2 for local or autovariables.
Table 8.2 Storage classes with their location, scope and life span
Static Variables: In several situations, you will need accessibility of variables declared in a function for all function; we will declare such variables as static. For example,
Variables declared as static are stored in contiguous memory locations. The syntax is shown in Figure 8.1. The only special feature of static area is that the variables in this static area are not erased, even if function terminates. For example, we have declared times as static int to keep track of the number of times FindArea is called by main() function. We have also initialized times = 0. It is incremented when the first time function is called. Next time, when FindArea() is called it is incremented by 1 to 2.
Heap Memory or Free Space: After allocating mandatory spaces for all the above storage classes, the memory still free is called heap memory or free space. This is dynamic memory available to the programmer for requirements of memory at run-time. But access to this space is available only through pointers.
Storage classes supported by C language are shown in Table 8.2.
Note that while static global and external declarations have reach to all functions, there is one vital difference. Static global declarations and definitions are available only through a single main() function, whereas declarations and definitions using extern are available even to programs written separately with different file names but compiled and linked with the main() program. An example will make the concepts clear:
Example 8.8: stackstatic.cpp A Program to Demonstrate Usage of Static and Stack(auto) Variable
#include<iostream>
Using namespace std;
#include<conio.h>
float FindArea ( float x , float y); // function prototype declarations
void main()
{ int i;
float x=200, y=100, area=0,ans;
for (i=0;i<10;i++) // call function FindArea 10 times
{ ans = FindArea(x++,y++);cout<<”
area = “ << ans;}
cout<<»
Address of variable ans in the main function : “<<ans;
}// end of main
// function definition
float FindArea(float x, float y)
{ static int times=0; // static variable to keep track of number of times
// function is called.
float ans;
ans=x*y;
times++;
cout<<”
number of times we have called findArea function = “<<times;
if (times ==10)
cout<<»
Address of variable ans in the FindArea function : “<<ans;
return ans;
}// end of FindArea
/*Output : number of times we have called findArea function = 1
area =20000.00
number of times we have called findArea function = 2
area =20301.00
number of times we have called findArea function = 3
area =20604.00
number of times we have called findArea function = 4
area =20909.00
number of times we have called findArea function = 5
area =21216.00
number of times we have called findArea function = 6
area =21525.00
number of times we have called findArea function = 7
area =21836.00
number of times we have called findArea function = 8
area =22149.00
number of times we have called findArea function = 9
area =22464.00
number of times we have called findArea function = 10
Address of variable ans in the FindArea function : 12ff04
area =22781.00
Address of variable ans in the main function : 12ff6c*/
Example 8.9: reg.cpp. A Program to Demonstrate Usage of Register Storage Class usage.Stack(auto) Variable
Note that registers of CPU reside on the processor chip; the exact number depends on the hardware of the processor and is considered the primary memory and hence enjoy fastest access times. However, having limited memory, they have to be used sparingly. For example, variables which are most frequently used by CPU can be declared as register variables thus saving access times. In the following example, we would use register memory to store counter of control loop, square and square root of a number.
#include<iostrem>
using namespace std;
void main()
{register counter,square,sqroot;
for(counter=1;counter <=10; counter ++)
{ square= counter* counter;
cout<<”
number :”<<counter<< “ square : “<< square <<endl;
}
}
/*Output: number : 1 : square : 1
number : 2 : square : 4
number : 3 : square : 9
number : 4 : square : 16
number : 5 : square : 25
number : 6 : square : 36
number : 7 : square : 49
number : 8 : square : 64
number : 9 : square : 81
number : 10 : square : 100*/
Example 8.10: extern.cpp A Program to Demonstrate Usage of Extern Variable usage.usage.stack(auto) Variable
Variable declared out side void main() function comes under external storage class.
#include<iostream>
using namespace std;
#include<conio.h>
// external function
void FindArea();
float x=10;float y=10;float area;
void main()
{ extern float area; extern float x; extern float y;
area=0;
cout<<”
area before calling FindArea : “<<area<<endl;
FindArea ();
cout<<”
area after calling FindArea : “<<area<<endl;
getch();
}// end of main
void FindArea()// fn declaration
{extern float x; extern float y;extern float area;
area = x*y;
cout<<”
area inside FindArea : “<<area<<endl;}
/*Output:area before calling FindArea 0.000000
area inside FindArea 100.000000
area after return from FindArea 100.000000*/
Note that although FindArea did not return the value of the area, the main program has shown the correct value of area. Thus, we can use external declaration for avoiding passing of variable to and from functions. We can also use extern declarations and definitions to link variables declared in two different files. We will attempt to demonstrate the concept through our next example:
Example 8.11: externfile.cpp A Program to Demonstrate Usage of External Program usage.usage.stack(auto) Variable
External file is stored in another file. Write C++ code for void FindArea() and save it as findarea.h in the current directory.
#include<stdio.h>
void FindArea()
{ extern float x; extern float y;extern float area;
area = x*y;
cout<<“
area inside FindArea :”<<area;
}
Write C++ code for void main () and include it along with other include statements as shown below:
#include<iostream>
using namespace std;
#include<conio.h>
#include”findarea.h” // findarea.h is stored in the current working directory
void FindArea(); // external function
float x=10;float y=10;float area;
void main()
{ extern float area; extern float x; extern float y;
area=0;
cout<<”
area before calling FindArea : “<<area<<endl;
FindArea ();
cout<<”
area after calling FindArea : “<<area<<endl;
getch();
}// end of main
Note that you can use #include<findarea.h> if you copy the findarea.h
into directory c: cinclude/*
Output: area before calling FindArea 0.000000
area inside FindArea 100.000000
area after return from FindArea 100.000000
C++ language does not contain any built-in function. But it contains standard library provided by C++ supplier. The files stored in these library files, also called header files, contain all useful functions, their definitions, declaration of data types and constants. We have already used several of them like iostream and conio.h. A few of them are provided here:
iostream.h : contains basic stream IO files for c++
stdio.h : facilitates input output statements.
iomanip.h : Contains IO manipulators
conio.h : contains functions used in calling IO routines
math.h : Contains library functions. Note that x can be float or double. C language does not support expression of type x ^a. We need to use pow(x,a).
sqrt(x) : determines square root of x
pow(,x,a) : computes x^a
exp(x) : computes e^x
sin(x) and cos(x): computes sin and cosine
log(x) : computes natural log
log10(x) : computes log to base 10
stdlib.h : Contains standard library like search and sort routines, etc.
abs(x) : computes absolute value of integer x
atof(s) : converts a string s to a double
atoi(s) : converts to integer
malloc() : allocates memory and returns a pointer to the location.
calloc() : same as malloc() but initializes the memory with 0s.
free(x) : frees heap memory space pointed by x
rand() : generates a random number.
string.h : Contains string-related functions such as
strlen() : length of the char array
strcpy() : copies a string to another
strcat() : concatenates two strings
strcmp() : compares two strings .
strlwr() : converts from uppercase to lowercase
struper() : converts from uppercase to lowercase
strrev() : reverses a string
The preprocessor does some housekeeping function before submitting the source code to the C compiler. The jobs it performs are:
#define PI 3.14159, preprocessor searches for occurrence of symbol PI and replaces it with 3.141519.
The standard directives available in C++ language are:
#include include text from the specified file
#define define a macro
#undefine indefine a macro
#if test if a condition holds at compile time
#endif end of if (conditional preprocessor)
#elif if–else–if for multiple paths at compilation time
#line provides line number
Example 8.12: macro1.cpp A Program to Show Macro Expansion. A Program to Show fn Overloading
#include<iostream>
#include<conio.h>
using namespace std;
#define GETDATA cout << “Enter the value: “ <<endl
void main()
{int x , y;
GETDATA;
cin >> x ;
GETDATA;
cin >> y;
cout << endl << «values entered are « <<x << « « << y;
getch();
}
// Output: Enter the value: 35
Enter the value: 45
values entered are 35 45*/
Preprocessor directive like #define GETDATA cout << «Enter the value: « <<endl will simply substitutes all the occurrences of GETDATA with cout << «Enter the value: « <<endl
The general syntax of macro with arguments is #define macro-name (arg1,arg2, arg3,………..argn). Examples are shown below:
Example 8.13: macro2.cpp. A Program to Demonstrate the Usage of Preprocessor Directives. A Program to Show fn Overloading
#include<iostream>
#include<conio.h>
using namespace std;
// substitution & macro definition macros
#define GETDATA cout << “Enter the value: “ <<endl
#define WRITEDATA(ans) cout << ans
#define SUM(a,b) ((a)+(b))
#define PRODUCT(a,b) ((a)*(b))
#define MIN(a,b) ((a)>(b)?(a): (b))
void main()
{ int x , y , ans;
GETDATA;
cin >> x;
GETDATA;
cin >> y;
ans=PRODUCT(x,y);
cout <<endl << «product of numbers is: «;
WRITEDATA(ans);
ans=SUM(x,y);
cout << endl << «sum of numbers is: «;
WRITEDATA(ans);
getch();
}
// OUTPUT: Enter the value: 7
Enter the value: 5
product of numbers is: 35
sum of numbers is: 12*/
All include files are placed at directory c: cinclude for turbo C++ compiler or in c:program files [Microsoft Visual Studio folder]VCinclude for Microsoft VC++ compiler. Hence, if you copy any heard file written by you into this directory, you can include this file as #include <findarea.h>. If you have placed the file in the current directory, you can include such a file with preprocessor directive # include “findarea.h”.
Conditional Inclusion of some parts of source code is done using conditional inclusion macros. The syntax is
#if constant expression
statement sequence
#endif
or
#if constant expression
statement sequence
#else
statement sequence
#endif
Example 8.14: elseifmacro.cpp A Program to Demonstrate the Usage #if, #else and #Endif Preprocessor Directive. A Program to Show fn Overloading
#include<iostream>
#include<conio.h>
using namespace std;
#define UPPER 5000
#define BONUS1 1000
#define BONUS2 500
#define bp 1000
void main()
{ int netpay;
cout << ”The basic pay is: ” << bp ;
#if bp < UPPER
netpay=bp + BONUS1;
#else
netpay=bp+BONUS2;
#endif
cout <<endl << ”netpay = ” << netpay;
getch();
} // end of main
//Output: Enter the basic pay 1000
netpay = 2000*/
In order to prevent inclusion of macros more than once and leading to multiple declarations, we can use macro #ifdef and #ifndef to indicate if defined and if not defined. The general syntax is:
#ifdef macroname #ifndef
Statements or statements
#endif #endif
A macro must be undefined before it is redefined. Consider the macro definitions. In this module, we will also use conditional inclusion like #ifdef
Example 8.15: undef.cpp A Program to Show the Usage of Undefine
#include<iostream>
#include<conio.h>
using namespace std;
#define UPPER 100
#define LOWER 10
#define WRITEDATA cout << “answer = “ << ans << endl ;
void main()
{ int temp= 70,ans=10;
if (temp<UPPER && temp>LOWER)
WRITEDATA;
#ifdef UPPER
#undef UPPER
#endif
#ifdef LOWER
#undef LOWER
#endif
// now we can set new limits for UPPER & LOWER
#define UPPER 60
#define LOWER 50
if (temp<UPPER && temp > LOWER)
WRITEDATA;
getch();
}// end of main
//Output: Answer=10(printed from the 1st if statement, the second WRITEDATA is not executed as the 2nd if loop returns a false.)*/
#error macro usage is shown below. When #error macro is encountered, the compiler displays the error message. Note that error message is not in double quotes
#ifdef UPPER
#include<upper.h>
#elifdef // this macro is similar to if–else–if
#include<lower.h>
#else
#error Incorrect inclusion of Header files
#endif
In day-to-day life, there are several occasions wherein we have to store data of the same type in contiguous locations, like marks obtained by a student in six different subjects are shown in an array named marks in Figure 8.2. Elements of the array are referenced by array name followed by subscript. We have shown an array named marks; six subject marks scored by the student can be represented by marks[0]=80.0, marks[5]=70.0, etc.
Figure 8.2 Representation of an array
General syntax of array is: storage class data type array [expression]
Note that storage class is optional. Data type is data type of the array. Array is name and expression is a positive integer. Examples of valid declarations of array are:
float marks[6] = { 60.0 , 66.0, 70.0 , 80.0 , 90.0, 100};
float marks[] = { 60.0 , 66.0, 70.0 , 80.0 , 90.0, 100.0};// no need to declare dimension
char stg[]={ ‘g’,’o’,’o’,’d’};
Consider an array named x, declared as int x[]= {80,90,100,50,65,70};
The addresses shown above are dummy addresses. Using of size of operators would tell us the memory requirement of data type int on your hardware. Assuming that it is 2 bytes, the memory of the array element is shown in Figure 8.2.
Refer to Figure 8.3 and the values stored in the array: int x[6]. We can initialize and allocate the values shown above with the statement
int x[] = { 80,90,100,50,65,70;}
Alternatively, we can use cin and cout to obtain the values for array x as shown below:
cout<<”
Enter Number of Terms in the array :”;
cin>>n;
Example 8.16: array.cpp Write a Program to Display the Array Elements Along with their Address. Sizeof Operator Provide Size of Data Type in Bytes.
#include<iostream>
using namespace std;
void main()
{ int i,n; //number of elements of array x
int x[]={80,90,100,50,65,70};
n= sizeof(x)/sizeof(int);
cout<<”
size of data type <int>:”<< sizeof(int)<<endl;
cout<<”
Memory space allocated to x[6]:”<<sizeof(x)<<endl;
cout<<”
no of elements in array x = “<<n<<endl;
cout<<”
array elements address in hexa “;
for (i=0;i<n; i++)
cout<<”
”<<x[i]<<” ”<<&x[i]<<endl;
cout<<”
”;
}
//Output :size of data type <int>:4
Memory space allocated to x[6]:24
no of elements in array x = 6
array elements address in hexa
80 0012FF60
90 0012FF64
100 0012FF68
50 0012FF6
65 0012FF70
70 0012FF74*/
If your program exceeds at run time the space originally allocated when the array was declared, then array out of bounds error results .We can use cin to read into an array. In the following example, we will show use of cin.get() function when we reverse the string.
Example 8.17: revstg.cpp// revstg.cpp A Program to Read the Input String Character by Character from Keyboard and Reverse the String
// #include<iostream>
using namespace std;
// function prototype declarations
void main()
{ int count=0,i;
int len; // length of the string
char c;
char x[20]; // array of characters . string
cout<<”
Enter a word and press <enter> :”;
c=cin.get(); // // get a character
while ( c!=’
’) // ‘
’ is end of line character, i.e. pressing
enter key
{x[count]=c;
count++;
c=cin.get();
}
// we have reached end of line. Append ‘ ’ to the string
x[count]= ‘ ’;
len = count;
// Now display the string you have just read
cout<<”
String inputted : “<<x;
cout<<”
space allocated to single char(byte) :”<<sizeof(char) <<endl;
cout<<”
Memory space allocated to string x[] :”<< sizeof(x) <<endl;
cout<<”
No of characters in the string x [] : “<<len<<endl;
// now reverse the string
cout<<”
string X reversed : “;
for ( i=len-1;i>=0;i--)
cout<<x[i];
}//Output :Enter a word and press <enter> :HELLO
String inputted : HELLO
space allocated to single char(byte) :1
Memory space allocated to string x[] :20
No of characters in the string x [] : 5
string X reversed : OLLEH */
Arrays can have more than one-dimension. For example, a matrix is a two-dimensional array with a number of rows and a number of columns is shown in Figure 8.4.
Example 8.18: transpose.cpp. A Program to Find the Transpose of a Matrix
#include<iostream>
using namespace std;
// functional prototype declarations
void Transpose( int A[10][10], int n );// n is the order of square matrix
void ReadMatrix( int A[10][10], int n );
void PrintMatrix( int A[10][10], int n );
void main()
{ int n,A[10][10];
cout<<”Enter the order of square matrix <n>”;
cin>>n;
ReadMatrix(A,n);
cout<<”The elements of the Matrix are:”<<endl;
PrintMatrix(A,n);
cout<<”The elements of the Transpose Matrix are:
”<<endl;
Transpose(A,n); //function call. A is name of matrix. Name is address is
} //end of main
void Transpose(int A[10][10],int n) //function definition*/
{ for(int i=0;i<n;i++) //loop1. i=1 because you don’t have to touch
x[0][0]
{ int t;
for(int j=0;j<i;j++) //loop2
{t=A[i][j];
A[i][j]=A[j][i]; //swapping
A[j][i]=t;
} //end of loop2
}
PrintMatrix(A,n); // output the matrix
} //end of function transpose
void ReadMatrix( int A[10][10], int n)
{cout<<”Enter the elements :”<<endl;
for(int i=0;i<n;i++)
{for(int j=0;j<n;j++)
cin>>A[i][j]; //input elements*/
}
}//end of ReadMatrix
void PrintMatrix( int A[10][10], int n)
{for(int i=0;i<n;i++)
{ for(int j=0;j<n;j++)
{ cout<<” ”<<A[i][j]; }
cout<<”
”<<endl;
}
}//end of ReadMatrix
//output : Enter the order of square matrix <n>2
Enter the elements
1 2 3 4
The elements of the Matrix are:
1 2
3 4
The elements of the Transpose Matrix are:
1 3
2 4 */
An array of characters is called a string variable. A string variable will always be automatically terminated with ‘