8

Functions, Storage Class Preprocessor Directives, and Arrays and Strings

LEARNING OBJECTIVES

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.

8.1 Introduction

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.

8.2 Why Use Function Templates?

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:

 

image

 

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

8.3 Call by Value

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.

8.4 Call by Reference

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.

8.5 Call by Constant Reference

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 */

8.6 Recursion

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*/

8.7 Inline Functions

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.

8.8 Function Overloading

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 ) ;
}

8.9 Default Arguments

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*/

8.10 Memory Management of C++

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

image

 

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,

 

image

 

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.

 

Syntax for static variables

 

Figure 8.1 Syntax for static variables

 

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.

8.10.1 Types of Storage Classes

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

8.11 Header Files and Standard Libraries

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

8.12 C++ Preprocessor

The preprocessor does some housekeeping function before submitting the source code to the C compiler. The jobs it performs are:

  1. Inclusion of all include section files. For example, it fetches and appends stdio.h from tcinclude directory and includes in source file.
  2. Macro expansion. Actually preprocessor carries out substitution for declarations given in Macro statement. For example, in the statement

    #define PI 3.14159, preprocessor searches for occurrence of symbol PI and replaces it with 3.141519.

  3. Conditional inclusion. To prevent inclusion second and multiple number of times, we can employ conditional inclusion.
  4. String replacements.

    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

8.12.1 Macro Expansion

 

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

8.12.2 Macro Definition with Arguments

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*/

8.12.3 File Inclusion

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”.

8.12.4 Conditional Inclusion

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*/

8.12.5 Conditional Compilation #ifdef and #ifndef Statements

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

8.12.6 #undef

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.)*/

8.12.7 #error Macros

#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

8.13 Arrays

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.

 

Representation of an array

 

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’};

8.13.1 How are Arrays Stored in the Memory?

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.

8.13.2 Array Initialization

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

 

Representation arrays with memory locations shown

 

Figure 8.3 Representation arrays with memory locations shown

 

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 */

8.13.3 Multi-dimensional Arrays

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.

 

A two-dimensional matrix

 

Figure 8.4 A two-dimensional matrix

 

 

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 */

8.13.4 Character Array – String Handling in C++ Language

An array of characters is called a string variable. A string variable will always be automatically terminated with ‘’ (NULL) character. C++ compiler treats occurrence of NULL character to mean the end of string. In the following program, we would check for occurrence of ‘’ to indicate the end of strings. Consider string declaration shown below and decide which type of declaration is best for C++ language.

char city[6] =”Mumbai”;  // incorrect as no space for adding ‘’ (NULL) character.
char city[7] =”Mumbai”;  // correct . ‘’ (NULL) character is added automatically.
char city[] =”Mumbai”;   // correct . ‘’ (NULL) character is added automatically.
                         // This is the preferred mode and we will be using this mode.

 

Example 8.19:    concat.cpp A Program to Concatenate Two Strings

#include<iostream>
using namespace std;
// Fn Prototypes
void Concat ( char x[],char y[]);
void main()
{ char x[20],y[20]; // x & y are two strings
  cout<<»enter any 2 strings
»;
  cin>>x>>y; //input 2 strings from the user*/
  Concat(x,y); //function call*/
}//end of main*/
void Concat(char a[],char b[]) //function definition*/
{ for(int i=0;a[i]!=’’;i++) // check for ‘’ occurrence
       cout<<a[i];
  cout<<» «;
  for(i=0;b[i]!=’’;i++)
        cout<<b[i];
} //end of function concat*/
// output :enter any 2 strings HELLO BROTHER : HELLO BROTHER*/

The best way to learn programming is to write programs. Let us write our own code for achieving the above functionality. The problems and solutions are in the worked example section at the end of this chapter.

8.14 Summary

  1. Functions help the main task to be decomposed into smaller modules. Calling function is one which calls a called function.
  2. The function prototype is declared before, void main (), in the global area, so that it is accessible by all other functions.
  3. Function takes care of all data types. One function executes for all data types depending on the arguments supplied at run time.
  4. 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.
  5. In call by reference, we pass the address to the function. Once the function receives a data item by reference, it acts on the data item and the changes made to the data item also reflect on the calling function.
  6. Call by constant reference is used when we want to prevent values being changed by the receiving function.
  7. Recursion means a function calling itself.
  8. Inline functions mean C++ replaces the entire function code rather than resorts to the usual function-handling mechanisms.
  9. Function overloading means one function performing more than one task depending on the arguments supplied at run time.
  10. If values for the arguments function are not supplied, then function will assume default options. We must supply default arguments from left to right.
  11. Variables declared as static are stored in contiguous memory locations. The only special feature of static area is that the variables in this static area are not erased, even if the function terminates.
  12. After allocating mandatory spaces for all the above storage classes, the memory still free, is called heap memory or free space. But access to this space is available only through pointers.
  13. Declarations and definitions using extern are available even to programs written separately with different file names but compiled and linked with the main() program.
  14. The preprocessor does some housekeeping function before submitting the source code to the C compiler like inclusion of all include section files, macro expansion, conditional inclusion and string replacements.
  15. Arrays store data of the same type in contiguous locations.
  16. An array of characters is called a string variable. A string variable will always be automatically terminated with ‘’ (NULL) character.
  17. C++ has implemented all the functionality of C language string-based functions, compiler provides a full-fledged class called string. You can use #include <string> to realize the functionality.

Exercise Questions

Objective Questions

  1. What is the value of y = floor(35.5 )?
    1. 35
    2. 35.5
    3. 36
    4. 35.0
  2. What is the value of y = ceil(35.5 )?
    1. 35
    2. 35.5
    3. 36
    4. 35.0
  3. sizeof() operator in C++ is a Library function     TRUE/FALSE
  4. getch() and getche() perform the same operation     TRUE/FALSE
  5. In #include<iostream.h> statement , stdio.h, under turbo C++, is available at
    1. current directory
    2. tcinclude
    3. tcin
    4. none
  6. In #include “circle.h” statement, circle.h is available at
    1. current directory
    2. tcinclude
    3. tcin
    4. none
  7. What will be output for cout<< 65?
    1. a
    2. A
    3. 10
    4. B
  8. When two strings are equal strcmp(stg1,stg2) returns
    1. −1
    2. 0
    3. 1
    4. true
  9. Call by reference is a default mode of transferring values to a function     TRUE/FALSE
  10. For recursive procedures, we can use the following storage allocations:
    1. static
    2. heap
    3. stack
    4. global
  11. The following copies the value of an argument into the formal parameters of the subroutine:
    1. call by value
    2. call by reference
    3. call by name
    4. none
  12. The following copies the value of an argument into the formal parameters of the subroutine:
    1. call by value
    2. call by reference
    3. call by name
    4. none
  13. Character array must be terminated with
    1. a
  14. An array without initial values contains
    1. all zeros
    2. all 1s
    3. garbage value
    4. none of the above
  15. Array can be initialized at the time of declaration itself using
    1. [ ]
    2. { }
    3. ( and )
    4. single quotes
  16. The number in a square bracket of an array is called
    1. superscript
    2. subscript
    3. dimension
    4. range
  17. Array declared as array A[m] the elements are subscripted between
    1. 0….m
    2. 0….m+1
    3. 1……m
    4. 0…..m−1
  18. An array is always passed
    1. using pass by value to a function
    2. using pass by reference to a function
    3. left to programs
    4. pass by name
  19. If int A[6] is a one-dimensional array of integers, which of the following refers to the value of the fourth element in the array:
    1. A[4]
    2. A[2]
    3. A[3]
    4. none

    Short-answer Questions

  20. Distinguish the switch and if–else statements.
  21. When do you use for statement and while statements? State the situation when for statement is better than while statement.
  22. Explain the differences of do-while and while statements.
  23. Why is goto statement not preferred?
  24. Explain the continue and break statements with examples.
  25. Explain call by reference call by value.
  26. Explain the need to declare function prototype before main() function.
  27. What are the storage classes?
  28. Explain the difference between static and stack storage.
  29. Distinguish global and external declarations.
  30. What is the role of preprocessors?
  31. What are macros? Explain the #ifdef and #ifndef statements with examples.
  32. What is a function template?
  33. Distinguish call by value and call by reference.
  34. What is call by constant reference?
  35. What is function overloading?
  36. What hat are preprocessor directives?
  37. Why are inclusion directives important?
  38. List a few important functions contained in String header file.

    Long-answer Questions

  39. Write in detail about one-dimensional and multi-dimensional arrays. Also write about how initial values can be specified for each type of array.
    1. In what way is array different from ordinary variable?
    2. What conditions must be satisfied by all the elements of any given array?
    3. What are subscripts? How are they written? What restrictions apply to the values that can be assigned to subscripts?
    4. What are the advantages in defining an array size in terms of a symbolic constant rather than a fixed integer quantity?
  40. How are multi-dimensional arrays defined? Compare with the manner in which one-dimensional arrays are defined.
  41. Explain memory mapping of C++ language.
  42. What are storage classes? Explain with suitable examples.
  43. What are macros and preprocessor directives? Explain with suitable examples.

    Assignment Questions

  44. Write a function template that returns position of a given value in an array.
  45. Write a function template program to find sum of n natural numbers using recursion.
  46. Write a macros in C++ for displaying error message using #error directive. Also program using macros to find the largest of the two numbers.
  47. Write a function template to sort an array. Test your code for array of strings also by including string header in your program.
  48. Write a function template to merge two sorted arrays.
  49. Write a program to print the ASCII table for range 30 to 122.
  50. Write a file named mystring.h, comprising all the above function modules at problem 12. Include the header file in your driver program and test all the modules.
  51. Write a program to find the largest element in an array.

Solutions to Objective Questions

  1. a
  2. c
  3. True
  4. False
  5. b
  6. a
  7. b
  8. b
  9. False
  10. c
  11. a
  12. b
  13. a
  14. c
  15. b
  16. b
  17. d
  18. b
  19. c
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.35.247