CHAPTER 6
FUNCTION: ORGANIZING THE PROGRAM
As problems grow they become more difficult to solve. One problem solving strategy is to break a problem into smaller problems (sub-problems) then solve each of the sub-problems separately. This idea of breaking a big problem into smaller ones is reminiscent of the old expression divide and conquer. Similarly, a big program can be broken into subprograms that can be written and tested independently. Each of these subprograms is known as a function (unit) with a specific action (task) to perform. Normally, an application program (software) consists of thousands of lines of code (instructions). Without an organization (function), it is almost impossible to write, test, use, maintain, or reuse a large program. Can you imagine a team of programmers trying to write and manage a program without using functions? TWO KINDS OF FUNCTIONS There are two kinds of functions: built-in functions and user-defined functions. A built-in function is pre-constructed and is available for use in your program. A user-defined function must be built by the programmer. C/C++ BUILT-IN FUNCTIONS C/C++ comes with a library of functions that are pre-programmed and ready for use in your program. You are already familiar with the C built-in functions scanf(...), and printf (...), andthe C++ function eof (...). BUILT-IN FUNCTIONS: EXAMPLE There are hundreds of built-in functions in C/C++. Some are used often and some are rarely used. Several important built-in functions and their include header files (directives ) are listed in Table 6.1.
HOW TO USE A BUILT-IN FUNCTION It is very simple to use a built-in function; just place the function name in your program where you need to perform the task. Instead of writing your own function, call the built-in function to do the job. Remember to include the proper header file (directives) that contains the function definition. BUILT-IN FUNCTION pow():EXAMPLE The program of Figure 6.1a illustrates how to raise a number to a different power. For example, the built-in function pow( 3, 4 ) takes two values 3 and 4 and returns 81 as the result. Figure 6.1a shows the use of pow( ) using four different ways. #include <iostream> #include <cmath> using namespace std; main(){ int i, m, n; for( i = 1; i <= 5 ; i++ ) cout << "pow("<< i <<",2) = " << pow( i, 2 ) << endl; cout << endl; for( i = 1; i <= 5 ; i++ ) cout << "pow(2," << i <<") = " << pow( 2, i ) << endl; cout << endl; for( i = 1; i <= 5 ; i++ ){ cout << "pow("<< i << "," << i << ") = " << pow( i, i ) << endl; }//FOR cout << endl; for( i = 1; i <= 5 ; i++){ cout << "ENTER TWO INTEGERS: "; cin >> m >> n; cout << "pow(" << m << "," << n << ") = " << pow( m, n ) << endl; }//FOR return 0; }//MAINFigure 6.1a - Various ways of using built-in pow( ) function. pow(1,2) = 1 pow(2,2) = 4 pow(3,2) = 9 pow(4,2) = 16 pow(5,2) = 25 pow(2,1) = 2 pow(2,2) = 4 pow(2,3) = 8 pow(2,4) = 16 pow(2,5) = 32 pow(1,1) = 1 pow(2,2) = 4 pow(3,3) = 27 pow(4,4) = 256 pow(5,5) = 3125 ENTER TWO INTEGERS: 2 6 pow(2,6) = 64 ENTER TWO INTEGERS: 4 3 pow(4,3) = 64 ENTER TWO INTEGERS: 8 2 pow(8,2) = 64 ENTER TWO INTEGERS: 7 3 pow(7,3) = 343 ENTER TWO INTEGERS: 3 7 pow(3,7) = 2187 Figure 6.1b - Output to the pow( ) program of figure 6.1a. USER-DEFINED FUNCTIONS VERSUS BUILT-IN FUNCTIONS Not everything you want to accomplish is pre-programmed (a built-in function). There are times when you must write your own functions. In addition, you may want to know how the built-in functions are programmed. Suppose you want to write a program to find the square, cube or power of a number. How would you proceed? In order to make your own function, you have to name it and program it. You can then use the function name in your main program as if it was a built-in function. Figure 6.2a contains a program with the user defined functions mysquare( x ) and mycube( x ). These functions are used to differentiate and emphasize the user-defined functions versus built-in functions. 1. #include <iostream> 2. using namespace std; 3. int mysquare( int ); // function declaration - prototype 4. int mycube( int ); // function declaration - prototype 5. main(){ 6. cout<<"The square of 5 is " << mysquare( 5 ) << endl; // function call 7. cout<<"The cube of 5 is " << mycube( 5 ) << endl; // function call 8. return 0; 9. }//MAIN 10. int mysquare(int x ){ // function definition 11. return x * x; // return the value to the function originally called 12. }//MYSQUARE 13. int mycube(int x ){ // function definition 14. return x * x * x; // return the value to the function originally called 15. }//MYCUBEFigure 6.2a - User defined functions to find the square and the cube of numbers. The square of 5 is 25 The cube of 5 is 125 Figure 6.2b - Output of mycube and mysquare user defined functions of figure 6.2a. The function mycube( x ) can also be written with the use of the function mysquare( x ) , as illustrated in the following code fragment: int mycube(int x){ return x * mysquare( x ); }//MYCUBEWHERE DO YOU PLACE A USER FUNCTION? After you have written a function, where do you place it? There are four answers:
IDENTIFYING A FUNCTION There are three identifying elements to a function:
In C, if the function definition is before the main program there is no need to declare (prototype) the function; however, in C++ prototyping is always needed. There are some compilers that skip the rule when the function is defined before the main. HOW TO PROTOTYPE A FUNCTION A function prototype is similar to the declaration of a variable. To prototype a function, you specify the kind of data the function will return (passes out) as well as the kind of data the function will communicate (passes in). There are instances when data is not passed into or out of a function. THE MAIN PROGRAM IS A FUNCTION TOO! You have been using the main program for quite a while but you probably did not realize that the main program is a function. If you look at the main program, it possesses the same form as a function. It has parentheses, braces, and a return value (return 0 is used most of the time). The main program is the main function that calls other functions. The main function can only be called by the operating system. USING A FUNCTION TO CALCULATE OVERTIME PAY The overtime pay programs of Figures 6.3a and 6.3b provide the same result. Figure 6.3a does not use a function while Figure 6.3b does. Even though it looks like more work and overhead when using a function, it is beneficial to use a function rather than writing the code directly into the main program. 1. #include <iostream> 2. using namespace std; 3. main(){ 4. int employeeid, hoursworked; 5. float hourlyrate, overtimepay; 6. cout << "Enter: employee ID, hours worked, hourly rate: "; 7. cin >> employeeid >> hoursworked >> hourlyrate; 8. if( hoursworked > 40 ) 9. overtimepay = ( hoursworked - 40 ) * hourlyrate * 1.5; 10. else 11. overtimepay=0; 12. cout << " OVERTIME PAY IS " << overtimepay << endl; 13. return 0; 14. }//MAINFigure 6.3a - Condensed version of the Payroll Program calculating overtime pay without the use of a function. 1. #include <iostream> 2. using namespace std; 3. float overtimepay( int hw, float hr ){ 4. if( hw > 40 ) 5. return ( hw - 40 ) * hr * 1.5; 6. else 7. return 0; 8. }//OVERTIMEPAY 9. main( ){ 10. int employeeid, hoursworked; 11. float hourlyrate; 15. cout << "Enter: employee ID, hours worked, hourly rate: "; 12. cin >> employeeid >> hoursworked >> hourlyrate; 13. cout << "OVERTIME PAY IS " << overtimepay( hoursworked, hourlyrate ) 14. << endl; 15. return 0; 16. }//MAINFigure 6.3b - Condensed version of the Payroll Program calculating overtime pay using a function named overtimepay( ) . Enter: employee ID, hours worked, hourly rate: 1234 50 20.50 OVERTIME PAY IS 307.5Figure 6.3c - The output of both Figure 6.3a and 6.3b is the same WHY FUNCTIONS ARE IMPORTANT There are six specific reasons why functions are important:
Whenever you write a program, divide the program into as many functions as possible, even if doing so causes more coding. The use of functions avoids problems. It is important to think of functions rather than writing the whole program as one large unit. Instead of writing the code within the main program, make a function call in main and code the function separately. For example, in the Payroll Program you can use a function to compute overtime pay and another function to find the tax rate. As programs become larger, more functions are added to the program. As you become more familiar with programming, the idea of the function becomes more interesting and useful. FUNCTIONS AND THE PROGRAM To use a function in a program you need to follow three steps: Function Declaration - ( also known as known as the function prototype ). You must indicate the return type and the number and type of parameters the function accepts. In the following example the function findmaximum takes three parameters of type integer and returns an integer. int findmaximum( int x, int y, int z );or int findmaximum(int, int, int );Function Definition - The function definition provides the actions the function performs. The function header and the body of the function are written here. In Figure 6.4, the function header is shown with the return type as well as the list of input parameters and their respective types. The opening and closing braces indicate the beginning and the end of the function. The return will send the maximum value of the integer input parameters named x, y, and z back to the calling function. int findmaximum( int x, int y, int z ){ if( x > y ) if( x > z ) return x; else if( y > z ) return y; else return z; }//FINDMAXIMUMFigure 6.4 - The function named findmaximum takes three integer input parameters and returns an integer value to the calling function as described in Step 3 of creating a function. Function Call - In order to use a function, the function must be called. To call a function, the name of the function and the correct parameters( if any) must be sent to the function definition. In the example of Figure 6.5a, the main program calls the function named findmaximum. The function finds the maximum of the three integer variables x, y, and z and displays the result. The complete program, including the code from Figure 6.4 is shown below. Figure 6.5b shows sample output of the program. 1. #include <iostream> 2. using namespace std; 3. // function prototype 4. int findmaximum( int, int, int ); 5. main(){ 6. int x, y, z; 7. cout << "Enter three numbers: "; 8. cin >> x >> y >> z; 9. cout << "THE MAXIMUM OF THREE NUMBERS IS " 10. << findmaximum( x, y, z ) << endl; //function call 11. return 0; 12. }//MAIN 13. // function definition 14. int findmaximum( int x, int y, int z ){ 15. if( x > y ) { 16. if( x > z ) return x; 17. }//IF 18. else if( y > z ) return y; 19. else return z; 20. }//FINDMAXIMUMFigure 6.5a - The complete program to find the maximum number of three different integers using the findmaximum function. The program illustrates the function prototype, function definition, and the function call. Enter three numbers: 30 50 10 THE MAXIMUM OF THREE NUMBERS IS 50Figure 6.5b - Sample output of figure 6.5a. PASSING OF PARAMETERS TO FUNCTIONS Each function performs a task on the data passed into the function known as a parameter or argument. It is important to provide the information a function needs to perform the task. One way to provide data to a function is to pass parameters (by listing name(s) and/or value(s)) in the parentheses of the function. In the example: findmaximum( x, y, z ), the function findmaximum takes three parameters or arguments and finds the maximum of the three. MATCHING THE PARAMETERS: ACTUAL WITH FORMAL It is important for the parameters of the calling function to match the parameters of the function definition. When calling a function, the type of parameter and the order of its appearance must be the same as in the function definition. In Figure 6.5a, the function findmaximum passes three parameters, each as an integer value. In the calling function (main program), x, y and z are declared as integers. In the function header, the receiving values are placed in the variable x, y, and z respectively. The arguments or parameters in the calling function (main program) are known as actual arguments. The arguments in the called function are known as formal or dummy arguments. For simplicity, we have chosen the same name as the actual parameters. However, the formal parameter usually has a different name than the actual parameter. Variable names may be different. Notice that the formal variables x, y, and z are declared in the function findmaximum and this sets a separate memory location for x, y, and z. FUNCTION WITH RETURN VALUE A function is expected to perform a task and return a result. In the findmaximum function, the function is expected to return the maximum value to the calling function. Figure 6.5a once again illustrates the process. FUNCTIONS WITHOUT PARAMETERS AND WITHOUT A RETURN VALUE Sometimes functions do not pass any parameters or return any value. Figure 6.6a illustrates such a program. The program has three functions named readdata, computedata, and printdata. Notice, these three function calls do not send any parameters and do not receive a value in return. You may be wondering if they are built-in system functions or user defined functions. 1. #include <iostream> 2. using namespace std; 3. // prototypes go here… 4. • 5. • 6. • 7. main( ){ 8. readdata( ); // ← readdata function call 9. computedata( ); // ← computedata function call 10. printdata( ); // ← printdata function call 11. return 0; 12. }//MAIN 13. 14. // function definitions go here… 15. • 16. • 17. • 18. // end source codeFigure 6.6a - Starting shell of a program using function calls that do not send parameters or return any value. The two sections listed above and below the function main tell you that these are user- defined functions. These functions need to have source code written by the user that provides functionality when called. In order to develop the code for these three functions, let us define the actions these functions provide.
Now that we understand what needs to be accomplished, we can start the process of writing the code to accomplish these tasks. The code for readdata is listed in figure 6.6b. Note the function asks the user to enter three numbers. This task is accomplished by using a cout statement asking the user for input. Then a cin statement is used to acquire and store the information provided by the user in the appropriate variables. Also note the use of the keyword void signifies no data is expected; therefore, no parameters are sent to the function and no data is returned from the function. When using the void keyword as a return type, the keyword return is not required at the end of the function definition. 1. void readdata( void ){ 2. cout << "Enter three separate numbers: "; 3. cin >> firstnumber >> secondnumber >> thirdnumber; 4. }//READDATAFigure 6.6b - The readdata function. The function named computedata takes all three numbers entered by the readdata function and adds them together. After the addition process, the sum is stored in a variable named sum. Figure 6.6c illustrates the function. Notice the use of the void keyword. 1. void computedata( void ){ 2. sum = firstnumber + secondnumber + thirdnumber; 3. }//COMPUTEDATAFigure 6.6c - The computedata function adds all three entered numbers from readdata and stores the result in a variable named sum. The last function of our program, named printdata, prints to the screen the numbers entered by the user as well as the sum of the inputted three numbers. The program is shown in figure 6.6d. 1. void printdata( void ){ 2. cout << "First number is " << firstnumber<<endl; 3. cout << "Second number is " << secondnumber <<endl; 4. cout << "Third number is " << thirdnumber <<endl; 5. cout << "The sum is " << sum << endl; 6. }//PRINTDATAFigure 6.6d - The printdata function displays the inputted data and the sum of the inputted data. The next task is to piece the program together by integrating the main program with our user defined functions. How do we link the functions and the main program together? There are two methodologies:
After looking over Figure 6.6e, several questions may arise, such as:
A good exercise would be to move the variables declared above the function main into the function main and see the result. We will discuss global and local variables in more detail in the next few sections. MISSING Figure 6.6e - The complete program shows how function prototypes, function calls, and function definitions interact with the function main. Enter three separate numbers: 4 5 6 First number is 4 Second number is 5 Third number is 6 The sum is 15Figure 6.6f - Sample output of the complete program listed in Figure 6.6e. 1. #include<iostream> 2. using namespace std; 3. // function prototypes 4. void readdata( void ); 5. void computedata( void ); 6. void printdata( void ); 7. 8. // global variables 9. int firstnumber, secondnumber, thirdnumber, sum = 0; 10. 11. main( ){ 12. readdata( ); // ← readdata function call 13. computedata( ); // ← computedata function call 14. printdata( ); // ← printdata function call 15. return 0; 16. }//MAIN 17. 18. // readdata function definition 19. void readdata( void ){ 20. cout << "Enter three separate numbers: "; 21. cin >> firstnumber >> secondnumber >> thirdnumber; 22. }//READDATA 23. 24. // computedata function definition 25. void computedata( void ){ 26. sum = firstnumber + secondnumber + thirdnumber; 27. }//COMPUTEDATA 28. 29. // printdata function definition 30. void printdata( void ){ 31. cout << "First number is " << firstnumber << endl; 32. cout << "Second number is "<< secondnumber << endl; 33. cout << "Third number is " << thirdnumber << endl; 34. cout << "The sum is " << sum << endl; 35. }//PRINTDATA 36. // end source codeFigure 6.6e - The complete program shows how function prototypes, function calls, and function definitions interact with the function main. Enter three separate numbers: 3 6 9 First number is 3 Second number is 6 Third number is 9 The sum is 18Figure 6.6f - Output of Figure 6.6e LOCAL AND EXTERNAL ( GLOBAL ) VARIABLES Variables that are declared in the main program or in the functions of a program are said to be local. Variables declared outside of the main program or outside of the functions are said to be global or external. Local variables are variables that are defined locally. Global variables are defined externally. 1. #include <iostream> 2. using namespace std; 3. int z = 7; // z is a global variable 4. // function prototype 5. void myfunction( void ); 6. 7. main( ){ 8. int x = 5, y = 6; // x and y are local variables 9. z = 0; 10. cout << "BEFORE MYFUNCTION CALL x = " 11. << x << " y = " << y << " z = " << z << endl; 12. myfunction( ); // ← function call 13. 14. cout << "AFTER MYFUNCTION CALL x = " 15. << x << " y = " << y << " z = " << z << endl; 16. return 0; 17. }//MAIN 18. 19. // function definition 20. void myfunction( void ){ 21. z = z + 1; 22. }//MYFUNCTION 23. // end source codeFigure 6.7a - Program shows local vs. global variables. BEFORE MYFUNCTION CALL x = 5 y = 6 z = 0 AFTER MYFUNCTION CALL x = 5 y = 6 z = 1Figure 6.7b - Output of figure 6.7a. In Figure 6.7a, variables x and y are declared in the main program; therefore, they are local to the main. As a result, myfunction cannot use these variables. However, the variable z is declared outside of the function myfunction and the main program. This allows the use of variable z by both the main program and myfunction. WHY NOT DECLARE ALL VARIABLES AS GLOBAL? At a glance, it appears easier to declare all variables outside the main program and all other function. Then every function can access the global variables as needed. So what is the drawback of using global variables? What happens if a function changes the value of a variable by mistake? Is it necessary to make an external variable visible to a function that has no interaction with that variable? A global variable holds its storage for the life of a program, even if it is not needed. Holding storage space for a variable that is not needed takes away resources needed to run a program. For simplicity, use external variables with caution. EXTERNAL VARIABLE AND THEIR SIDE EFFECTS If you have a headache, you take a pill. What happens if your headache goes away and you experience some hair loss? The loss of the hair is a side effect of taking the pill. Although this type of situation is rare, it can be costly. Figure 6.8a demonstrates the use of external variables and their unexpected side effect. Observe, the intended output of the program is 8 not 16. Since x is declared as an external variable, the return value of the function findsquare is 4, 4 is then multiplied by the value of x which has been set to 4 in the findsquare function. 1. #include <iostream> 2. using namespace std; 3. // function prototype 4. int findsquare( int ); 5. 6. // global variable 7. int x; 8. 9. void main( ){ 10. x = 2; 11. cout << "CUBE OF X IS " << findsquare( x ) * x << endl; 12. }//MAIN 13. 14. // function definition 15. int findsquare( int x1 ){ // x1 is the alias for x 16. x = x1 * x1; 17. return x; 18. }//FINDSQUARE 19. // end source codeFigure 6.8a - The side effect of using global variables. The findsquare function does not produce the intended result. CUBE OF X IS 16Figure 6.8b - Output of Figure 6.8a. SCOPE OF NAME When a variable is declared either locally or externally, the variable has a life span and its own visibility. This determines where the variable exists, is used, and finally where it ceases to exist. When a variable is declared locally, the variables scope starts from the point of declaration and continues to the end of the block. Local variables no longer exist after the block where the variable was declared is exited. A local variable name overrides an external variable with the same name. BLOCK AND VARIABLE DECLARATION A block is represented by a pair of braces { }, one opens the block and the other closes it. When a variable name is declared within the braces, its scope begins at the point of declaration and ends at the closing brace. To understand the concept of scope, look at the programs and output of Figures 6.9a and 6.10a. The output of both programs is the same. 1. #include <iostream> 2. using namespace std; 3. main( ){ 4. int x, y, temp; 5. x = 3; y = 8; 6. cout << "X AND Y BEFORE SWAP " 7. << "x = " << x <<" y = " << y << endl; 8. temp = x; 9. x = y; 10. y = temp; 11. cout << "X AND Y AFTER SWAP " 12. << "x = " << x <<" y = " << y << endl; 13. return 0; 14. }//MAINFigure 6.9a - The program as listed shows local scope within the function main. X AND Y BEFORE SWAP x = 3 y = 8 X AND Y AFTER SWAP x = 8 y = 3Figure 6.9b - Output of figure 6.9a - Local scope within the function main. 1. #include <iostream> 2. using namespace std; 3. main( ){ 4. int x, y; 5. x = 3; y = 8; 6. cout << "X AND Y BEFORE SWAP " 7. << "x = " << x <<" y = " << y << endl; 8. { // ← Start new local block 9. int temp; 10. temp = x; 11. x = y; 12. y = temp; 13. } // end of block- temp is gone 14. cout <<"X AND Y AFTER SWAP " 15. << "x = " << x <<" y = " << y << endl; 16. return 0; 17. }//MAINFigure 6.10a - Illustration of a local block within the function main. X AND Y BEFORE SWAP x = 3 y = 8 X AND Y AFTER SWAP x = 8 y = 3Figure 6.10b - Output of figure 6.10a. DIFFERENCE BETWEEN C AND C++: BLOCK AND VARIABLE DECLARATION In C, a variable is declared in the function main immediately following the beginning of the function block; while in C++, a variable can be declared anywhere after the block. The next two examples illustrate the difference in how C and C++ declare variables. Figure 6.11a shows the C version of a swap and Figure 6.11b shows the C++ version of the swap. The output for both programs is shown in Figure 6.11c. 1. /* C VERSION */ 2. #include <cstdio> 3. using namespace std; 4. main( ){ 5. int x, y; 6. x = 3; y = 8; 7. printf( "LET's SWAP\n" ); 8. printf( "X AND Y BEFORE SWAP x = %d y = %d \n", x, y ); 9. { // ← start new local block 10. int temp; 11. temp = x; 12. x = y; 13. y = temp; 14. } // end of block -- temp is gone 15. printf( "X AND Y AFTER SWAP x = %d y = %d \n", x ,y ); 16. return 0; 17. }//MAINFigure 6.11a - C version of swapping the contents of two local variables 1. // C++ VERSION 2. #include <iostream> 3. using namespace std; 4. main( ){ 5. cout <<"LET's SWAP"<< endl; 6. int x, y; 7. x = 3; y = 8; 8. { // ← start new local block 9. cout << "X AND Y BEFORE SWAP " 10. << "x = " << x <<" y = " << y << endl; 11. int temp; 12. temp = x; 13. x = y; 14. y = temp; 15. } // end of block - temp is gone 16. cout <<"X AND Y AFTER SWAP " 17. << "x = " << x <<" y = " << y << endl; 18. return 0; 19. }//MAINFigure 6.11b - C++ version of swapping the contents of two variables. Notice the extra effort to make sure the declaration of the local variables x, y, and temp were not made at the very beginning of each block. LET's SWAP X AND Y BEFORE SWAP x = 3 y = 8 X AND Y AFTER SWAP x = 8 y = 3Figure 6.11c - The output of both figure 6.11a and 6.11b. FIND AVERAGE: ALL VARIABLES EXTERNAL The program of Figure 6.12a demonstrates functions using external variables. The program takes in three numbers, and then produces the sum of these numbers. Next, the average of the inputted numbers is calculated. Finally, all inputted numbers and their sum and average are printed. 1. #include<iostream> 2. using namespace std; 3. //external variables 4. int firstnumber, secondnumber, thirdnumber; 5. float sum, average; 6. 7. // function prototype 8. void readnumbers( void ); 9. void findsum( void ); 10. void findavg( void ); 11. void printall( void ); 12. 13. main( ){ 14. readnumbers( ); 15. findsum( ); 16. findavg( ); 17. printall( ); 18. return 0; 19. }//MAIN 20. 21. // function definitions 22. void readnumbers( ){ 23. cout << "Enter three separate numbers: "; 24. cin >> firstnumber >> secondnumber >> thirdnumber; 25. }//READNUMBERSFigure 6.12a (Part 1) - The use of global (external) variables and functions to find the average of three entered numbers. 26. void findsum( ){ 27. sum = firstnumber + secondnumber + thirdnumber; 28. }//FINDSUM 29. void findavg( ){ 30. average = sum / 3.0; 31. }//FINDAVG 32. void printall( ){ 33. cout << "First number is " << firstnumber << endl; 34. cout << "Second number is " << secondnumber << endl; 35. cout << "Third number is " << thirdnumber << endl; 36. cout << "The sum is " << sum << endl; 37. cout << "The average is " << average << endl; 38. }//PRINTALL 39. // end source codeFigure 6.12a (Part 2) - The use of global (external) variables and functions to find the average of three entered numbers. Enter three separate numbers: 2 4 6 First number is 2 Second number is 4 Third number is 6 The sum is 12 The average is 4Figure 6.12b - Sample output of the program of figure 6.12a using external variables and functions to find the average of three inputted numbers. Observe the program listed in Figure 6.12a. The functions within the function main outline the objectives of the program. The variables are defined above the functions and the main program. FIND AVERAGE: EXTERNAL VARIABLE, LOCAL VARIABLE, AND RETURN VALUE The program listed in Figure 6.13a demonstrates functions using external variables, local variables and return values. The program takes in three numbers, produces the sum of the numbers, finds the average of the numbers, then prints out the numbers, their sum, and the average. 1. #include<iostream> 2. using namespace std; 3. //external variables 4. int firstnumber, secondnumber, thirdnumber; 5. float sum,average; 6. // function prototypes 7. void readnumbers( void ); 8. float findsum( void ); 9. float findaverage( void ); 10. void printall( void ); 11. 12. main( ){ 13. readnumbers( ); 14. sum = findsum( ); 15. average = findaverage( ); 16. printall( ); 17. return 0; 18. }//MAIN 19. 20. void readnumbers( void ){ 21. cout << "Enter three separate numbers: "; 22. cin >> firstnumber >> secondnumber >> thirdnumber; 23. }//READNUMBERS 24. 25. float findsum( void ){ 26. float sum; 27. sum = firstnumber + secondnumber + thirdnumber; 28. return sum; 29. }//FINDSUM 30. 31. float findaverage( void ){ 32. float average; 33. average = sum / 3.0; 34. return average; 35. }//FINDAVERAGE Figure 6.13a (Part 1) - The use of global (external) variables, return values, and functions to find the average of three entered numbers 36. void printall( void ){ 37. cout << "First number is " << firstnumber << endl; 38. cout << "Second number is "<< secondnumber << endl; 39. cout << "Third number is " << thirdnumber << endl; 40. cout << "The sum is " << sum << endl; 41. cout << "The average is " << average << endl; 42. }//PRINTALL 43. // end source codeFigure 6.13a (Part 2) -- The use of global (external) variables, return values, and functions to find the average of three entered numbers Enter three separate numbers: 2 4 6 First number is 2 Second number is 4 Third number is 6 The sum is 12 The average is 4Figure 6.13b - Sample output of the program of figure 6.13a using external variables return values, and functions to find the average of three inputted numbers. In the above program, the input numbers, the sum and the average are declared externally. Variables sum and average are also declared locally in findsum and findaverage. Each local variable has its own scope and storage, even though they possess the same name. The variables sum and average have the same value as sum and average in the function because the return value from each function assigns its corresponding value. FIND AVERAGE: EXTERNAL AND LOCAL VARIABLES, PARAMETERS, AND A RETURN VALUE The program shown in Figure 6.14a demonstrates functions using external variables, local variables, and return values in conjunction with input parameters. The program takes in three numbers, sums the numbers, finds the average and prints out the numbers, their sum and the average. 1. #include<iostream> 2. using namespace std; 3. // external variables 4. int firstnumber, secondnumber, thirdnumber; 5. // function prototypes 6. void readnumbers( void ); 7. float findsum( int, int, int ); 8. float findaverage (float ); 9. void printall( int, int, int, float, float ); 10. 11. main( ){ 12. float sum; 13. float average; 14. readnumbers( ); 15. sum = findsum( firstnumber, secondnumber, thirdnumber ); 16. average = findaverage( sum ); 17. printall( firstnumber, secondnumber, thirdnumber, sum, average ); 18. return 0; 19. }//MAIN 20. 21. // function definitions 22. void readnumbers( void ){ 23. cout << "Enter three separate numbers: "; 24. cin >> firstnumber >> secondnumber >> thirdnumber; 25. }//READNUMBERS 26. 27. float findsum( int firstnumber, int secondnumber, int thirdnumber ){ 28. float sum; 29. sum = firstnumber + secondnumber + thirdnumber; 30. return sum; 31. }//FINDSUMFigure 6.14a (Part 1) - The use of external and local variables in association with function parameters and return values. Enter three separate numbers: 2 4 6 The first number is 2 The second number is 4 The third number is 6 The sum is 12 The average is 4Figure 6.14b - Sample output to figure 6.14a. In program 6.14a, the input variables are declared externally, while the variables sum and average are declared locally in the main program. The variable sum is also declared locally within the findsum function. The variable average is declared locally in the findaverage function. Each local variable has its own scope within the function where it is declared. Therefore, sum and average can be declared in many different functions and used locally, even though the variable name is used elsewhere. The variables sum and average of the function main have the same values as sum and average in the functions findsum and findavg because these functions return their local variable value to the main function's corresponding local variable. PASS BY VALUE AS DEFAULT In C/C++, when a parameter is passed to a function, by default only the value of the parameter is sent to the function. In other words, a copy of the variable value is made and sent to the function. The called function does not communicate back to the calling function. That is the called function takes but does not give back any changes to the calling function's parameters. WHY PASS BY VALUE AS DEFAULT A large program is divided into many functions and functions can be placed in many files. A function can unintentionally change the value of a variable and this may be undesirable and as a consequence cause problems. To avoid an unintentional change to an original value, C/C++ encourages pass by value. Any other passing mechanism requires additional knowledge and steps. Figure 6.15a illustrates passing by value to functions. Notice that the program initializes the variable x equal to 5 in the function main. Before the nochange function call the value of x is equal to 5. In the function nochange, the copy of the value of x is incremented to 6 and displayed. And when the function nochange returns control to the function main, the value of x is displayed again, and the value of x returns to 5. This simple program completely illustrates the default mechanism for sending parameters to a function. As a result, many errors are eliminated when passing parameters to functions. 1. #include <iostream> 2. using namespace std; 3. //prototype 4. void nochange( int ); 5. void main( ){ 6. int x = 5; 7. cout <<" BEFORE THE FUNCTION CALL X IS " << x << endl; 8. nochange( x ); 9. cout<<" AFTER THE FUNCTION RETURN X IS " << x << endl; 10. }//MAIN 11. // function definition 12. void nochange( int x ){ 13. x = x + 1; 14. cout << " INSIDE THE FUNCTION nochange X IS " << x <<endl; 15. }//NOCHANGE 16. // end source codeFigure 6.15a - Illustration of passing a parameter to a function by value. BEFORE THE FUNCTION CALL X IS 5 INSIDE THE FUNCTION nochange X IS 6 AFTER THE FUNCTION RETURN X IS 5Figure 6.15b - Output of figure 6.15a. Notice passing by value will not change the content of the actual variable. PASSING A PARAMETER VALUE BACK - TWO WAY COMMUNICATION
PASS BY POINTER - C METHOD There are three steps to follow in order to pass a parameter by pointer:
Figure 6.16a illustrates how the address of a variable is passed and how any change to the memory address results in the change of the original variable value. 1. #include <iostream> 2. using namespace std; 3. // function prototype 4. void changebyone( int* ); // ← function expects a pointer to int 5. void main( ){ 6. int x = 0; 7. cout << "X BEFORE changebyone " << x << endl; 8. changebyone( &x ); // sending the address of x 9. cout << "X AFTER changebyone " << x << endl; 10. }//MAIN 11. 12. // function definition 13. void changebyone( int *px ){ //declaring the variable as a pointer by using * 14. *px = *px + 1; // adding 1 to the content of px 15. cout << "VALUE STORED IN POINTER *px is " << *px << endl; 16. }//CHANGEBYONE 17. // end source codeFigure 6.16a - Illustration of passing a parameter by pointer. Line 17 is read as add 1 to the value stored in memory location px and assign the value back to the memory address px. X BEFORE changebyone 0 VALUE STORED IN POINTER *px is 1 X AFTER changebyone 1Figure 6.16b - Output of passing a parameter by pointer. PASS BY REFERENCE - C++ METHOD C++ simplifies the C method by declaring the receiving variable as a reference. To declare a variable as a reference, precede the variable with an ampersand (&) in the function heading and C++ automatically de-references it. Figure 6.17a illustrates passing a parameter to a function by reference. 1. #include <iostream> 2. using namespace std; 3. // function prototype 4. void changebyone( int& ); 5. 6. void main(){ 7. int x = 0; 8. cout << " X BEFORE changebyone " << x << endl; 9. changebyone( x ); // create an alias for x 10. cout << " X AFTER changebyone " << x << endl; 11. }//MAIN 12. 13. // function definition 14. void changebyone(int& ax){ //declaring a reference variable 15. ax = ax +1; // adding 1 to ax 16. cout << " VALUE STORED IN REFERENCE ax is " << ax << endl; 17. }//CHANGEBYONE 18. // end source codeFigure 6.17a - Illustration of passing a parameter by reference. Line 17 adds one to the alias of x (ax) and stores the value back in ax. X BEFORE changebyone 0 VALUE STORED IN REFERENCE ax is 1 X AFTER changebyone 1Figure 6.17b - Output of passing a parameter by reference. C scanf AND SENDING THE ADDRESS OF A PARAMETER When reading a value in C using scanf, you may wonder why you have to use the address of operator ( & ). Look at the following line of code: scanf( "%d", &x );The task of scanf is to bring a value back, for example, from the keyboard. This is the reason it is necessary to send the address the value will be stored in. With printf it is not necessary to use the address of the operator because the task of printf is simply to take a value and display it. printf("%d", x ); THE NAME OF AN ARRAY AS AN ADDRESS Interestingly in C/C++, the name of an array is an address; therefore, it is not necessary to precede the array name with an ampersand ( & ). When the name of an array is sent to a function, the actual variable is automatically sent. Any changes made will affect the original array. Figure 6.18a illustrates the syntax needed to send an array to a function. 1. #include <iostream> 2. using namespace std; 3. // function prototypes 4. void read_data( int[ ], int ); 5. void print_data( int[ ], int ); 6. main( ){ 7. int tbl[ 5 ]; 8. read_data( tbl, 5 ); // name of array is an address 9. print_data( tbl, 5); 10. return 0; 11. }//MAIN 12. // function definition 13. void read_data(int tbl[ ], int n) { 14. cout << "READING…" << endl; 15. for( int i = 0 ; i < n ; i++ ) { 16. cout << "Enter tbl[" << i << "]: "; 17. cin >> tbl[ i ]; 18. cout << "tbl[ " << i << " ] = " << i << endl; 19. }//FOR 20. cout << endl; 21. }//READ_DATA 22. 23. void print_data( int tbl[ ], int n ){ 24. cout << "PRINTING…" << endl; 25. for( int i = 0; i < n ; i++ ){ 26. cout << "tbl[ " << i << " ] = " << i << endl; 27. }//FOR 28. cout<<endl; 29. }//PRINT_DATA 30. // end source codeFigure 6.18a - Illustrates sending an array to a function as a parameter. By default, an arrays memory address is sent to a function. Changes to an array in a function where the array is sent as a parameter affects the actual variable. READING: Enter tbl[0]: 1 tbl[ 0 ] = 1 Enter tbl[1]: 2 tbl[ 1 ] = 2 Enter tbl[2]: 3 tbl[ 2 ] = 3 Enter tbl[3]: 4 tbl[ 3 ] = 4 Enter tbl[4]: 5 tbl[ 4 ] = 5 PRINTING: tbl[ 0 ] = 0 tbl[ 1 ] = 1 tbl[ 2 ] = 2 tbl[ 3 ] = 3 tbl[ 4 ] = 4Figure 6.18b - Output of figure 6.18a. STRINGS AND POINTERS A string is an array of characters that ends with a null terminating character ( '\0' ). The following illustration shows how an array of characters declared as char str[ 10 ], that holds the name "Ebrahimi", is stored in computer memory. The name "Ebrahimi" starts with location zero ( 0 ) and continues to location 7. The terminating null fills location 8 and location 9 is empty. It is important to note, if a character array is created with 10 locations, only nine locations can be used to store characters related to the string. One character must be reserved for the terminating null.
When building a string, character by character, after the last character is read into the array, a null must be inserted at the end of the array. The null signifies the end of a character array and is important for string processing. When inputting data from the keyboard into a string using cin, the terminating null is automatically added to the end of the string. The variable name used to represent a string is also a memory address. When the name of the variable is passed to a function, the function receives a pointer to the character array. In this case, an array of characters and a pointer to characters can be used interchangeably. The compiler prefers a pointer rather than an array for efficiency. The following array and pointer examples are equivalent:
A more efficient use of a pointer to a character is to increment the address of a pointer variable by one. Instead of incrementing an index named i in the following example, refer to a specific character as follows:
Lines 22 through 30 in Figure 6.19a illustrates the above use of incrementing a specific character while scanning the string with the use of the pointer. The terminating null character is represented in three ways. All three are equivalent:
The program of Figure 6.19a shows examples of how to print strings character by character as well as all at once. Note the role of the terminating null in string processing when printing character by character. The null is used to determine the end of the string. The output for Figure 6.19a is located in Figure 6.19b. 1. #include <iostream> 2. using namespace std; 3. void printbycharusingpointer( char* ); 4. void printbycharusingarray( char[ ] ); 5. main( ){ 6. char str[10]; 7. cout << "Enter a name: "; 8. cin >> str; 9. printbycharusingpointer( str ); 10. printbycharusingarray( str ); 11. return 0; 12. }//MAIN 13. void printbycharusingpointer( char* str ){ 14. // prints out a string one character at a time until the end 15. // of string character, the null, is read. The function uses 16. // pointer notation, also known as pointer arithmetic to print 17. // out each array element. Both of the examples provided 18. // provide the same results. 19. char *temp = str; // hold first location of array 20. cout << "\nUSING POINTER NOTATION: " << endl; 21. cout << "Print entire name at once: " << str << endl; 22. cout << "Print name one character at a time:" << endl; 23. while( *str != '\0' ){ 24. cout << *str; 25. str++; }//WHILE 26. cout << endl; 26. str = temp; 27. int i = 0; 28. while( *( str + i ) != '\0' ){ 29. cout << *( str + i); 30. i++; }//WHILE 31. cout << endl << endl; }//PRINTBYCHARUSINGPOINTER 32. void printbycharusingarray( char str[ ] ){ 33. // prints out a string one character at a time until the end 34. // of string character, the null, is read. The function uses 35. // array notation to print out each array element. 36. cout << "USING ARRAY NOTATION: " << endl; 37. cout << "Print entire name in at once: " << str << endl; 38. cout << "Print name one character at a time:" << endl; 39. int i = 0; 40. while( str[ i ] != '\0' ){ 41. cout << str[ i ]; 42. i++; }//WHILE 43. cout << endl; }//PRINTBYCHARUSINGARRAYFigure 6.19a - The program illustrates string manipulation through pointer notation and standard array indices. Enter a name: Ebrahimi USING POINTER NOTATION: Print entire name at once: Ebrahimi Print name one character at a time: Ebrahimi Ebrahimi USING ARRAY NOTATION: Print entire name in at once: Ebrahimi Print name one character at a time: EbrahimiFigure 6.19b - Output of the program from Figure 6.19a. OTHER FUNCTION RELATED SUBJECTS There are other important function related subjects, including recursion, inline functions, pointers to functions, virtual function, and separate compilation. These topics will be covered later in the book. PAYROLL PROGRAM WITH FUNCTIONS Figure 6.20a shows the complete Payroll Program taking advantage of arrays. First the program reads all data from an input file into the appropriate parallel array. Then each appropriate function is called sequentially to create the payroll. Each function passes only the necessary information to the function definition. Looking at the main function of the program and notice how well the program reads. Even a non-programmer looking at the source code of the function main would recognize the first action is to get all the data and read it into the program. The next task is to determine the overtime hours, if any. Functions to find overtime pay, regular hours, regular pay, gross pay, tax rate, tax amount, and net pay follow. The program concludes with the print function, which sends all data to the monitor for display. Breaking the program into smaller tasks enables a programmer to visualize the entire scope of a project. If you list all the tasks that need to be accomplished and make a function call for each of these tasks, the program becomes much simpler to grasp. This concept is conducive to the idea of pooling employees into teams. Once the project has been broken into many modules ( functions ), several programmers or programmer teams can work simultaneously to solve a particular module. The ideas stated here represent the gateway towards real software development.
1. #include <iostream> 2. #include <fstream> // file input output stream 3. using namespace std; 4. // function prototypes 5. int readalldata( long int[ ], int[ ], float[ ], const int ); 6. void findovertimehours( int[ ], int[ ], int ); 7. void findovertimepay( int[ ], float[ ], float[ ], int ); 8. void findregularhours( int[ ], int[ ], int ); 9. void findregularpay( int[ ], float[ ], float[ ], int ); 10. void findgrosspay( float[ ], float[ ], float[ ], int ); 11. void findtaxrate( float[ ], float[ ], int ); 12. void findtaxamount( float[ ], float[ ], float[ ], int ); 13. void findnetpay( float[ ], float[ ], float[ ], int ); 14. void printalldata( long int[ ], int[ ], float[ ], float[ ], float[ ], float[ ],float[ ], int ); 15. 16. void main( ){ 17. const int MAXSIZE = 100; // for maximum of 100 employees 18. 19. //declaration of variables 20. int n; 21. long int id[ MAXSIZE ]; 22. int hoursworked[ MAXSIZE ], overtimehours[ MAXSIZE ]; 23. int regularhours[ MAXSIZE ]; 24. float hourlyrate[ MAXSIZE ], regularpay[ MAXSIZE ]; 25. float overtimepay[ MAXSIZE ], grosspay[ MAXSIZE ]; 26. float taxrate[ MAXSIZE ], taxamount[ MAXSIZE ],netpay[ MAXSIZE] ; 27. 28. //functions calls 29. n = readalldata( id, hoursworked, hourlyrate, MAXSIZE ); // get all data 30. findovertimehours( hoursworked, overtimehours, n ); 31. findovertimepay( overtimehours, hourlyrate, overtimepay, n ); 32. findregularhours( hoursworked, regularhours, n ); 33. findregularpay( regularhours, regularpay, hourlyrate, n ); 34. findgrosspay( regularpay, overtimepay, grosspay, n ); 35. findtaxrate( grosspay, taxrate, n ); 36. findtaxamount( grosspay, taxamount, taxrate, n ); 37. findnetpay( grosspay, netpay, taxamount, n ); 38. printalldata( id, hoursworked, hourlyrate, overtimepay, 39. grosspay, taxamount, netpay, n ); 40. }//MAINFigure 6. 20a ( Part 1 ) - The Payroll Program using parallel arrays and function calls. 41. int readalldata( long int id[ ], int hoursworked[ ], float hourlyrate[ ], int n ){ 42. ifstream fin( "payroll.in" ); 43. n = 0; 44. 45. while( fin >> id[ n ] >> hoursworked[ n ] >> hourlyrate[ n ] ) n++; 46. 47. fin.close( ); 48. return n; 49. }//READALLDATA 50. 51. void findovertimehours( int hoursworked[ ], int overtimehours[ ], int n ){ 52. for( int i = 0 ; i < n ; i++){ 53. if( hoursworked[ i ] > 40 ) overtimehours[ i ] = hoursworked[ i ] - 40; 54. else overtimehours[ i ] = 0; 55. }//FOR 56. }//FINDOVERTIMEHOURS 57. 58. void findovertimepay( int overtimehours[ ], float hourlyrate[ ], 59. float overtimepay[ ], int n ){ 60. for( int i = 0 ; i < n ; i++){ 61. overtimepay[ i ] = overtimehours[ i ] * hourlyrate[ i ] * 1.5; 62. }//FOR 63. }//FINDOVERTIMEPAY 64. 65. void findregularhours( int hoursworked[ ], int regularhours[ ], int n ){ 66. for( int i = 0 ; i < n ; i++){ 67. if( hoursworked[ i ] > 40 ) regularhours[ i ] = 40; 68. else regularhours[ i ] = hoursworked[ i ]; 69. }//FOR 70. }//FINDREGULARHOURS 71. 72. void findregularpay( int regularhours[ ], float regularpay[ ], 73. float hourlyrate[ ], int n ){ 74. for( int i = 0 ; i < n ; i++ ){ 75. regularpay[ i ] = regularhours[ i ] * hourlyrate[ i ]; 76. }//FOR 77. }//FINDREGULARPAYFigure 6.20a ( Part 2 ) - The Payroll Program using parallel arrays and function calls. 78. void findgrosspay( float regularpay[ ], float overtimepay[ ], 79. float grosspay[ ],int n ){ 80. for( int i = 0 ; i < n ; i++){ 81. grosspay[ i ] = regularpay[ i ] + overtimepay[ i ]; 82. }//FOR 83. }//FINDGROSSPAY 84. 85. void findtaxrate( float grosspay[ ], float taxrate[ ], int n ){ 86. for( int i = 0 ; i < n ; i++){ 87. if( grosspay[ i ] > 4000.00 ) taxrate[ i ] = 0.40; 88. else if(grosspay[ i ] > 3000.00 ) taxrate[ i ] = 0.30; 89. else if(grosspay[ i ] > 1000.00 ) taxrate[ i ] = 0.20; 90. else taxrate[ i ] = 0.10; 91. }//FOR 92. }//FINDTAXRATE 93. 94. void findtaxamount( float grosspay[ ], float taxamount[ ], 95. float taxrate[ ], int n ){ 96. for( int i = 0 ; i < n ; i++){ 97. taxamount[ i ] = grosspay[ i ] * taxrate[ i ]; 98. }//FOR 99. }//FINDTAXAMOUNT 100. 101. void findnetpay( float grosspay[ ], float netpay[ ], float taxamount[ ], int n){ 102. for( int i = 0 ; i < n ; i++){ 103. netpay[ i ] = grosspay[ i ] - taxamount[ i ]; 104. }//FOR 105. }//FINDNETPAY 106. 107. void printalldata( long int id[ ], int hoursworked[ ], float hourlyrate[ ], 108. float overtimepay[ ], float grosspay[ ], float taxamount[ ], 109. float netpay[ ], int n ){ 110. cout << "EMP ID" << "\t" << "HOURS" << "\t" << "RATE " << "\t " 111. << "OVERPAY " << "\t" << "GROSSPAY" << "\t" << "TAX "<< "\t" 112. << " NETPAY " << endl; 113. for( int i = 0 ; i < n; i++){ 114. cout << " " << id[ i ] << "\t " << hoursworked[ i ] << "\t"<<hourlyrate[ i ] 115. << "\t " << overtimepay[ i ] << "\t\t" << grosspay[ i ] << "\t\t" 116. << taxamount[ i ] << "\t " << netpay[ i ] << endl; 117. }//FOR 118. }//PRINTALLDATA 119. // end source codeFigure 6.20a ( Part 3 ) - The Payroll Program using parallel arrays and function calls. 1234 43 100.00 2345 40 120.75 3456 35 110.50 4567 52 20.25 5678 34 45.00 6789 44 30.50 7890 31 115.25 8901 35 34.23 9012 38 70.75 1221 45 90.50Figure 6.20b - Input file used for the program of figure 6.19a named payroll.in. EMP ID HOURS RATE OVERPAY GROSSPAY TAX NETPAY 1234 43 100 450 4450 1780 2670 2345 40 120.75 0 4830 1932 2898 3456 35 110.5 0 3867.5 1160.25 2707.25 4567 52 20.25 364.5 1174.5 234.9 939.6 5678 34 45 0 1530 306 1224 6789 44 30.5 183 1403 280.6 1122.4 7890 31 115.25 0 3572.75 1071.83 2500.92 8901 35 34.23 0 1198.05 239.61 958.44 9012 38 70.75 0 2688.5 537.7 2150.8 1221 45 90.5 678.75 4298.75 1719.5 2579.25 CLOSING REMARKS AND LOOKING AHEAD Functions are the building blocks of C/C++ programs. A large program may incorporate hundreds of functions. A problem is divided into sub-problems (divide-conquer tactic) and for each problem a subprogram or function is written. The main program's task is to outline and coordinate function calls. When a function is called, the control flow transfers to the called function. Once the function's task is complete, the flow returns to main for the next operation. Functions make a program readable, reusable, extendable, expandable, and easier to debug. Also, it is much easier to rewrite a function than the entire program. A function size may range from one line to one or more pages. Finally, functions promote teamwork. A team of programmers can work simultaneously with each other working on one or more components of a large program. When all the functions are completed, the team compiles their work to produce the final product. In Chapter 7, we will learn how to make our programs more organized by using structure. With structure, all related data are grouped together to eliminate sending parameters to a function. Instead of sending parameters, a structure variable is sent to the function. Structure eliminates the need for parallel arrays. |