Subprograms General Syntax <Subprogram-Header> <Body-of-Subprogram> Example 1 C++ subprograms: void swapper (int &num1, int &num2) { int temp; temp = num1; num1 = num2; num2 = temp; } int computeAvge ( void ) { int total = 0, value; for (int j = 0 ; j < 10 ; j++) { cin >> value; total += value; } return (total /10); } There are two types of subprograms: procedures and functions. A procedure corresponds to a void function in C/C++. A function corresponds to a C/C++ function that returns a value. A subprogram may either have (formal) parameters or not. A subprogram that does not have parameters uses global variables to exchange values with the calling program in some programming languages. ©2011 Gilbert Ndjatou Page 1 Example 2 In C++ we have the following: int max, average; // to hold the number of values to read // to hold their average void computeAvge ( void ) // read values and compute their average { int total = 0, value; for (int j = 0 ; j < max ; j++) { cin >> value; total += value; } average = total / max; } int main( ) { /*-------------------- read ten values and compute their average -----------------------------*/ max = 10; computeAvge ( ); cout << endl << “the average of those values is:\t” << average; return 0; } Local Variables Variables defined in the body of a subprogram are called local variables. In most contemporary programming languages, local variables are by default stack dynamic. In C/C++, a function’s local variable may be specifically declared to be static. However, Ada subprograms, and the (class) methods of C++, Java, and C# have only stack dynamic local variables. ©2011 Gilbert Ndjatou Page 2 Using (Formal) Parameters in C++ In C++, there are two types of (formal) parameters: value parameters, and reference parameters. A value parameter is used by a function to receive a value from the calling function. A reference parameter is used by a function to supply and/or receive a value from the calling function. When a function is called, the arguments (or actual parameters) must be specified as follows: - For a value parameter, you must specify a value (or an expression): A memory location is created for each value parameter, and it is initialized with that value. - For a reference parameter, you must specify a variable name: This variable name replaces the reference parameter in the body of the function. - The data types of the arguments and the parameters must be compatible. Example 3 using value and reference parameters void funct1 (int vnum , int & rnum1 , int & rnum2) { vnum += 7; rnum1 += 4; rnum2 = vnum + rnum1; } int main( ) { int num1 = 5, num2 = 16 , num3; funct1 (num1 , num2 , num3); cout << endl << “num1=” << num1 << “\tnum2=” << num2 << “\tnum3=” << num3; return 0; } The output of this program is: Exercise 1) 2) 3) 4) num1= 5 num2= 20 num3 = 32 Which of the following call statements are invalid? Explain. funct1(num1 +9, num1, num2); funct1(2, num1); funct1(num1, num2 + 5, num3); funct1( 9, num1, num2 , num3); ©2011 Gilbert Ndjatou Page 3 Example 4 using value and pointer parameters void funct1 (int vnum , int * pt1 , int * pt2) { vnum += 7; *pt1 += 4; *pt2 = vnum + *pt1; } int main( ) { int num1 = 5, num2 = 16 , num3; funct1 (num1 , &num2 , &num3); cout << endl << “num1=” << num1 << “\tnum2=” << num2 << “\tnum3=” << num3; return 0; } The output of this program is: Example 5 num1= 5 num2= 20 num3 = 32 One-dimensional arrays as parameters void funct3 (int list1[ ] , int list2[ ] , int num , int size) { for (int j = 0; j < size, j++) list2[ j ] = list1[ j ] + num; } int main( ) { int vala [ 5 ] = { 3, 9, 4, 6, 8}, valb[ 5 ]; funct3 (vala , valb , 7, 5); return 0; } ©2011 Gilbert Ndjatou Page 4 Example 6 Two-dimensional arrays as parameters void funct4 (int list[ ] [5] , int num , int size) { for (int r = 0; r < size, r++) for (int c = 0 ; c < 5 ; c++) list[ r ][ c ] = list[ r ][ c ] + num; } int main( ) { int table [6][ 5 ] = {{3, 9, 4, 6, 8}, {2, 3, 4, 5, 6}, {3, 2, 5, 6, 3}, { 9, 6, 5, 2, 8}, {2, 4, 3, 6, 7}, {4, 6, 5, 7, 8}}; funct4 (table , 10 , 6); return 0; } Specifying Default Arguments In C++, FORTRAN 95, Ada, and PHP (but not in Java), formal parameters may have default values: A default value is used if no actual parameter (argument) is passed for that formal parameter. Example Function header: float compute_pay (float income, float tax_rate, int exemptions = 1) Function calls: pay = compute_pay (20000.0, 0.15); pay = compute_pay (25000.0, 0.18, 4); Note: In C++, parameters with default arguments must appear last in the argument list. ©2011 Gilbert Ndjatou Page 5 Subprogram Declarations: Function Prototypes Example 7 1. void swapper (int &num1, int &num2); or void swapper (int &, int &); 2. int readvalue ( void ); 3. void funct1 (int vnum , int & rnum1 , int & rnum2); or void funct1 (int , int & , int &); 4. void funct1 (int vnum , int * pt1 , int * pt2); or void funct1 (int , int * , int * ); 5. void funct3 (int list1[ ] , int list2[ ] , int num , int size); or void funct3 (int [ ] , int [ ] , int , int ); 6. void funct4 (int list[ ] [5] , int num , int size); or void funct4 (int [ ] [5] , int , int ); Java and C# do not have function prototypes. ©2011 Gilbert Ndjatou Page 6 Parameter Passing Methods Formal parameters are used to do one of the following: - Receive a value from the corresponding argument (actual parameter). Semantic model: in mode. Example: value parameter in C++. - Transmit data to the corresponding argument. Semantic model: out mode. - Or to receive and transmit data to the corresponding argument. Semantic model: In-Out mode. Example: reference parameter in C++. Implementation Models of Parameter Passing Pass-by-value is an implementation of the in-mode parameters. The value of the argument is used to initialize the corresponding formal parameter. Pass-by-result is an implementation of the out-mode parameters. The formal parameter acts as a local variable. But just before the control returns to the calling program, its value is copied to the corresponding argument (which must be a variable). Pass-by-value-result and pass-by-result. is an implementation of in-out mode parameters. It is a combination of pass-by-value Pass-by-reference is another implementation of in-out mode parameters. Overloading Subprograms Very often, two or more functions of a program conceptually perform the same task, but the number and/or the data types of some of their arguments are different. For example, you may have a function to compute the average of three integer values, and another one to compute the average of three double precision floating-point values. You may also have a function to compute the average of two integer values, and another one to compute the average of three integer values. Giving the same name to these functions can make the program easier to read and understand In C++ two or more functions may have the same name, as long as there is a way to distinguish them based on their parameters. This feature is called function overloading. The compiler determines the right version of the function to call from a set of overloaded functions by inspecting the arguments specified in the function call. The example in Figure 14 illustrates the use of overloaded function names in a source module. ©2011 Gilbert Ndjatou Page 7 Function Name Overloading Line Number 1 /**************************************************************** 2 Program to compute the average of two integer values, the average 3 of three integer values and the average of two double precision 4 floating-point values. 5 ***************************************************************/ 6 #include <iostream> 7 using namespace std; 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 31 32 33 34 int ComputeAverage( int, int); // to compute the average of two integer values int ComputeAverage( int, int, int); // to compute the average of three integer values double ComputeAverage(double, double); //to compute the average of two floating-point values int main() { int result1, result2; double result3; // the average of two integer values // the average of three integer values //the average of two floating-point values result1 = ComputeAverage(4, 5); // call to function defined in line 35 result2 = ComputeAverage(5, 4, 6); // call to function defined in line 40 result3 = ComputeAverage(4.0, 5.0); // call to function defined in line 45 cout << “\n\nresult1=\t” << result1 << << result2 << “\n\nresult3=\t” return 0; “\n\nresult2=\t” << result3; } ©2011 Gilbert Ndjatou Page 8 35 36 37 38 39 40 41 42 43 44 45 46 47 48 int ComputeAverage(int value1, int value2) { return (value1 + value2) / 2; } int ComputeAverage(int value1, int value2, int value3) { return (value1 + value2 + value3) / 3; } double ComputeAverage(double value1, double value2) { return (value1 + value2) / 2; } OUTPUT result1= 4 result2= 5 result3= 4.5 ©2011 Gilbert Ndjatou Page 9 Generic Subprograms Function Templates A function template is an alternative way to overloading a function name when all the functions have the same number of parameters but with different data types. For example, suppose that in a program we have to write three functions: The first interchanges the values of two character variables, the second one interchanges the values of two integer variables, and the last one interchanges the values of two double precision variables. Instead of writing the three separate functions, we can write a template function that can be used in any of the above three situations. C++ automatically generates separate function template specializations to handle each type of call appropriately. A template function definition begins with the keyword template followed by a template parameter list specified in angle brackets as follows: template < class T1, class T2, . . . , class Tn > or template < typename T1, typename T2, . . . , typename Tn > Where: T1, T2, . . . , Tn are the type parameters that represent the different data types that will be used in the definition of the function template. Example Function template of functions to interchange the values of two variables template <class T> void swapValues( T & var1 , T & var2) { T temp; temp = var1; var1 = var2; var2 = temp; } ©2011 Gilbert Ndjatou Page 10 Example Function template that receives variables in two data types and output the maximum size of those variables/ data types. Note: C++ provides a compile-time unary operator named sizeof with the following syntax: sizeof <variable> returns the number of bytes used to represent <variable>. sizeof ( <variable>) returns the number of bytes used to represent <variable>. sizeof <array-name> returns the number of bytes in the array with name <array-name>. sizeof ( <array-name>) returns the number of bytes in the array with name <array-name>. sizeof ( <data-type>) returns the number of bytes used to represent a variable with the data type <data-type>. Examples int inum, list[ 10 ]; double dnum; cout << “\n size of inum is:\t” << sizeof inum; cout << “\n size of int is:\t” << sizeof (int); cout << “\n size of list is:\t” << sizeof (list); cout << “\n size of dnum is:\t” << sizeof dnum; cout << “\n size of double is:\t” << sizeof (double); Output size of inum is: 4 size of int is: 4 size of list is: 40 size of dnum is: 8 size of double is: 8 Note that since the operator sizeof is a compiler-time operator, it cannot be used in a function to determine the size of an array passed to that function as an argument as follows: ©2011 Gilbert Ndjatou Page 11 void funct( int list[ ] ) { int size = sizeof ( list )/ sizeof( int ); . . . } template <class T1, class T2> int largest( T1 &var1, T2 &var2 ) { int max; if ( sizeof( var1 ) > sizeof(var2) ) max = sizeof(var1); else max = sizeof(var2); return max; } Notes Functions templates do not have function prototypes: they must therefore be included in any source module in which they are called. One way to use functions templates in a program is to place them in a header file and to include that header file in any program where the function template is called. ©2011 Gilbert Ndjatou Page 12 Example /*-- Program to read two values and to compute the difference of the largest value minus the smallest -*/ template <class T> void swapValues( T & var1 , T & var2) { T temp; temp = var1; var1 = var2; var2 = temp; } int main( ) { int inum1, inum2; double dnum1, dnum2; /*------ read two integer values and compute the difference of the largest minus the smallest -----*/ cin >> inum1 >> inum2; if(inum1 < inum2) swapValues( inum1, inum2); cout << inum1 – inum2; /*- read two double precision values and compute the difference of the largest minus the smallest */ cin >> dnum1 >> dnum2; if(dnum1 < dnum2) swapValues( dnum1, dnum2); cout << dnum1 – dnum2; return 0; } Exercise Write the function template of functions to find the maximum of three values. ©2011 Gilbert Ndjatou Page 13 Other Issues Nested subprograms. Implementing Subprograms with Stack-Dynamic Local Variables Activation Record Local variables Parameters Dynamic link: (Pointer to the base of the activation record instance of the caller ) Return address Top of the stack ©2011 Gilbert Ndjatou Page 14