Functions
Contents
Passing Data By Value
File: 1.cpp
#include <iostream> using namespace std; void changeme( int x1 ) { x1 = 100 ; } int main() { int i1 = 10 ; changeme( i1 ) ; cout << "i1:" << i1 << endl ; return(1) ; }
[amittal@hills functions]$ ./a.out i1:10Let us see how the above function "changeme" works. We call the function "changeme" and pass the "i1" but we don't pass the variable and instead pass in the value which is 10. This value is passed to the variable "x1" in the function "changeme". We are in the function "changeme" and the variable "x1" is defined at this point and set to 10. The function "changeme" ends and the variable "x1" is out of scope. When we come back to the main function nothing has happened to the variable "i1" and the value of i1 is still 10 as shown in the output. There is a way to pass in a reference to the original variable and that is called pass by reference.
File: 2.cpp
#include <iostream> using namespace std; // Function prototype. void divide(double, double); int main() { double num1, num2; cout << "Enter two numbers and I will divide the first\n"; cout << "number by the second number: "; cin >> num1 >> num2; divide(num1, num2); return 0; } void divide(double arg1, double arg2) { if (arg2 == 0.0) { cout << "Sorry, I cannot divide by zero.\n"; return; } cout << "The quotient is " << (arg1 / arg2) << endl; }We have see how the main function returns an "int" and we do "return 0" to end the function. A function can have "void" to signify that the function does not return anything. We can still use a "return" statement to come out of the function as shown in the above program. Notice a function declaration does not need to have the parameter names defined in the function.
Exercises
1)File: ex1.cpp
#include <iostream> using namespace std; //WRITE A FIUMCTIOM isPrime that takes a single integer and returns boolean //WRITE A FIUMCTIOM toPower that takes 2 integer named input and power // and returns the input to the power int main() { cout << "Is 7 prime " << isPrime( 7 ) << endl ; cout << "Is 7 prime " << isPrime( 14 ) << endl ; cout << "Is 7 prime " << toPower(2, 3) << endl ; cout << "Is 7 prime " << toPower(2, 0) << endl ; }
Output: 1 0 8 1
Inline
File: inline.cpp
#include <iostream> using namespace std; inline int max( int x1, int x2 ) { return x1 > x2 ? x1 : x2 ; } int main() { cout << max( 3, 4 ) << endl ; }We can declare a function inline. This is usually used for simple functions. The compiler will replace the function with the actual code replacing the arguments. The "inline" keyword is a hint to the compiler. It is up to the compiler to decide if the function should be made inline or not.This can make the code more efficient as a function call can be expensive if many function calls are made.
Macros
A macro is a preprocessor feature that replaces text and can be used in place of functions. They are a carry over from C and should be used sparingly in C++ .File: macro1.cpp
#include <iostream> using namespace std; #define max( x1, x2 ) (x1 > x2 ? x1 : x2) /* inline int max( int x1, int x2 ) { return x1 > x2 ? x1 : x2 ; } */ int main() { int x1 = 3 ; int x2 = 4 ; cout << max( 3, 4 ) << endl ; // cout << ( 3 > 4 ? 3 : 4 ) << endl ; }In the above code we have a macro:
#define max( x1, x2 ) (x1 > x2 ? x1 : x2)A macro can take on arguments. The preprocessor will look for the function name "max" and substitute it with the text:
(x1 > x2 ? x1 : x2)There is no type checking involved. It is purely a text replacement before the compiler kicks in.The line
cout << max( 3, 4 ) << endl ;gets replaced with:
cout << ( 3 > 4 ? 3 : 4 ) << endl ;Macros can cause unintended issues in the code. Let's take a look at the following example.
File: macro2.cpp
#include <iostream> using namespace std; #define SQUARE(a) a*a #define INCR_xx (xx)++ int xx = 0 ; int main() { int xx = 0 ; int y1 = SQUARE(xx+2) ; INCR_xx ; cout << y1 << endl ; cout << xx << endl ; cout << ::xx << endl ; }
[amittal@hills functions]$ ./a.out 2 1 0The line
int y1 = SQUARE(xx+2) ;should print "4" but prints "2" . The replacement happens with the expansion as:
(xx+2*xx+2) = xx + 2*xx + 2
Similarly the increment macro only increments the local variable and not the global one.
Default Arguments
A function can be defined so that the parameters take on default values.File: def1.cpp
#include <iostream> using namespace std; void function1( int x1 , int x2= 5 , int x3=6 ) { cout << x1 << " " << x2 << " " << x3 << endl ; } int main() { function1( 4 ) ; function1( 4 , 15 ) ; function1( 4 , 15 , 7) ; return(1) ; }With default arguments we do not have to give all the values for the arguments when we call the function. in the example above we have defined the last 2 parameters x1 and x2 to take on the values 5 and 6 .
If we call
function1( 4 )
the parameter x1 will take on the value 4 and the parameter x2 takes on the value 5 and the parameter. If we provide a default value for one parameter then we need to provide values for the parameters to the right. We cannot have something like:
File: def2.cpp
#include <iostream> using namespace std; void function1( int x1 , int x2= 5 , int x3 ) { cout << x1 << " " << x2 << " " << x3 << endl ; } int main() { function1( 4 ) ; function1( 4 , 15 ) ; function1( 4 , 15 , 7) ; return(1) ; }
$ g++ def2.cpp def2.cpp:5:42: error: default argument missing for parameter 3 of ‘void function1(int, int, int)’ 5 | void function1( int x1 , int x2= 5 , int x3 )If the function has a declaration that we are using then we need to place the default arguments in the declaration and not in the definition.
File: def3.cpp
#include <iostream> using namespace std; void function1( int x1 , int x2= 5 , int x3=10 ); int main() { function1( 4 ) ; function1( 4 , 15 ) ; function1( 4 , 15 , 7) ; return(1) ; } void function1( int x1 , int x2 , int x3 ) { cout << x1 << " " << x2 << " " << x3 << endl ; }
Exercise
What does the below program print ?File: ex2.cpp
#include <iostream> using namespace std; void function1( int x1=4 , int x2= 5 , int x3=6 ) { cout << x1 + x2 + x3 << endl ; } int main() { function1( ) ; function1( 2 ) ; function1( 3 , 4 ) ; function1( 3 , 4 , 5) ; return(1) ; }
Static variables in functions
File: static1.cpp
#include <iostream> using namespace std; void function1() { int localVar = 20 ; cout << "localVar:" << localVar << endl ; localVar++ ; } void function2() { static int staticVar = 20 ; cout << "staticVar:" << staticVar << endl ; staticVar++ ; } int main() { function1() ; function1() ; function1() ; function2() ; function2() ; function2() ; return 0; }Output:
$ ./a.exe localVar:20 localVar:20 localVar:20 staticVar:20 staticVar:21 staticVar:22When we enter the "function2" for the first time then the variable "StaticVar" is initialized and it retains it's value from that point onwards. It does not lose scope. It's almost like a global variable but it's scope is limited to the function. The standard function "strtok" uses static variables to keep track of the token position.
Overloading functions
We can have functions with the same name as long as the signature is different.File: over1.cpp
// This program uses overloaded functions. #include <iostream> #include <iomanip> using namespace std; // Function prototypes int square(int); double square(double); int main() { int userInt; double userFloat; // Get an int and a double. cout << fixed << showpoint << setprecision(2); cout << "Enter an integer and a floating-point value: "; cin >> userInt >> userFloat; // Display their squares. cout << "Here are their squares: "; cout << square(userInt) << " and " << square(userFloat); return 0; } int square(int number) { cout << "Inside the integer function." << endl ; return number * number; } //*************************************************************** // Definition of overloaded function square. * // This function uses a double parameter, number. It returns * // the square of number as a double. //*************************************************************** double square(double number) { cout << "Inside the double function." << endl ; return number * number ; }Signature difference
The signatures of 2 functions have to be different in the parameters and not just in the return values.
int square(int number) { return number * number; } double square(int number) { return number * number; }The above code will not compile because, the functions only differ in the return value.
Variable Arguments
We can provide variable number of arguments to functions.File: var1.cpp
#include <iostream> #include <cstdarg> using namespace std; //First argument will represent the number of //arguments double average(int num,...) { va_list valist; double sum = 0.0; int i1 ; va_start(valist, num); //initialize valist for num number of arguments for (i1 = 0; i1 < num; i1++) { //access all the arguments assigned to valist sum += va_arg(valist, int); } va_end(valist); //clean memory reserved for valist return sum/num; } int main() { cout << "Average of 2, 3, 4, 5 = "<< average(4, 2,3,4,5) << endl; cout << "Average of 5, 10, 15 = "<< average(3, 5,10,15)<< endl; }