Sie sind auf Seite 1von 13

Lesson 14: Functions, Basics

Welcome to EasyCPlusPlus.com's free tutorial on C++ programming. This lesson covers functions. Functions are used to encapsulate a set of operations and return information to the main program or calling routine. Encapsulation is data, information or detail hiding. Once a function is written, we need only be concerned with what the function does. That is, what data it requires and what outputs it produces. The details, "how" the function works, need not be known. We have also seen encapsulation with objects. Objects in C++, which encapsulate both data and methods, will be discussed more in later lessons. The use of functions provides several benefits. First, it makes programs significantly easier to understand and maintain. The main program can consist of a series of function calls rather than countless lines of code. A second benefit is that well written functions may be reused in multiple programs. The C standard library is an example of the reuse of functions. A third benefit of using functions is that different programmers working on one large project can divide the workload by writing different functions. Defining and Declaring Functions A function is declared with a prototype. A function prototype consists of the return type, a function name and a parameter list. The function prototype is also called the function declaration. Here are some examples of prototypes. return_type function_name(list of parameters); int max(int n1, int n2); int printResults(string buffer, int status);

The function definition consist of the prototype and a function body, which is a block of code enclosed in parenthesis. A declaration or prototype is a way of telling the compiler the data types of the any return value and of any parameters, so it can perform error checking. The definition creates the actual function in memory. Here are some examples of functions. int FindMax(int n1, int n2) { if (n1 > n2) { return n1;

} else { return n2; } } void PrintMax(int someNumber) { cout << "The max is " << someNumber << endl; } void PrintHW() { cout << "Hello World" << endl; } float FtoC(float faren) { float factor = 5./9.; float freezing = 32.0; float celsius; celsius = factor * (faren - freezing); return celsius; } There are a few significant things to notice in these examples. The parameter list of a function may have parameters of any data type and may have from no to many parameters. The return statement can be used to return a single value from a function. The return statement is optional. For instance, the function PrintHW does not return a value. Techniques for returning multiple values from a function will be covered later in the lesson. Finally, observe that variables can be declared within a function. These variables are local variables and can only be used within the function. They have local scope. Scope refers to the section of code where a variable name is valid and may be used. We'll see more on scope in a later lesson. Using Functions A function must be declared prior to its use. This allows the compiler to perform type checking

on the arguments used in its call. A function is declared using its prototype. Let's use the functions defined in the previous section in a simple program. /* Include Files */ #include <iostream> using namespace std; /* Function Declarations */ int FindMax(int n1, int n2); void PrintMax(int someNumber); void PrintHW(); float FtoC(float faren); int main() { int i = 5; int j = 7; int k; float tempInF = 85.0; float tempInC; PrintHW(); /* Prints Hello World */ /* A nice sunny day */

k = FindMax(i,j); PrintMax(k); /* Prints Max Value */

tempInC = FtoC(tempInF); cout << tempInF << " Fahrenheit equals " << tempInC << " Celsius " << endl; return 0; } /* Function Definitions */ int FindMax(int n1, int n2) { if (n1 > n2) { return n1;

} else { return n2; } } void PrintMax(int someNumber) { cout << "The max is " << someNumber << endl; } void PrintHW() { cout << "Hello World" << endl; } float FtoC(float faren) { float factor = 5./9.; float freezing = 32.0; float celsius; celsius = factor * (faren - freezing); return celsius; }

Notice that the functions are declared prior to their use. The function definitions are actually below main in this file. Also, notice that the function definitions and declarations match. They have the same return type, names, and parameters. The function definitions need not even be in this file. For instance, when you use library functions, the definitions are not in your file. A program may be separated into multiple files. Main, along with the needed function declarations may be in one file. The functions themselves, that is, their definitions, may be separated, into multiple files. This is usually how any large project is organized.

Practice Problem 1) Write functions to convert feet to inches, convert inches to centimeters, and convert centimeters to meters. Write a program that prompts a user for a measurement in feet and converts and outputs this value in meters. Facts to use: 1 ft = 12 inches, 1 inch = 2.54 cm, 100 cm = 1 meter. Solution Returning Multiple Values From Functions and Methods So far, all the examples shown have either not returned any values, or have returned a single value using the return statement. In practice, it will be common to need to return multiple values from a function. Let's see how this can be done by developing a function to swap two integer values. Here's a first attempt. #include <iostream> using namespace std void swap(int x, int y); /* Note that the variable names in the prototype and function definition need not match. Only the types and number of variables must match */ int main() { int x = 4; int y = 2; cout << "Before swap, x is " << x << ", y is " << y << endl; swap(x,y); cout << "After swap, x is " << x << ", y is " << y << endl; } void swap(int first, int second)

{ int temp; temp = second; second = first; first = temp; }

Results:

What happened? The values weren't swapped. The function didn't work as expected. The arguments were passed into the function by value. This means that the function received a local copy of the argument. Any modifications to the local copy do not change the original variable in the calling program. C++ has two techniques that can be used if a variable is to be modified within a function, and the modified value is desired in the calling routine. The first is to pass a pointer to the variable to the function. The pointer can then be manipulated to change the value of the variable in the calling routine. It is interesting to note that the pointer itself is passed by value. The function cannot change the pointer itself since it gets a local copy of the pointer. However, the function can change the contents of memory, the variable, to which the pointer refers. The advantages of passing by pointer are that any changes to variables will be passed back to the calling routine and that multiple variables can be changed. Here is the same example with pointers being passed into the function. The main disadvantage is that pointer notation can be cumbersome and difficult to use, especially for beginners.

#include <iostream>

using namespace std; void swap(int *x, int *y); int main() { int x = 4; int y = 2; cout << "Before swap, x is " << x << ", y is " << y << endl; swap(&x,&y); cout << "After swap, x is " << x << ", y is " << y << endl; return 0; } void swap(int *first, int *second) { int temp; temp = *second; *second = *first; *first = temp; }

Results:

Practice Problem 1) Write a function that will calculate the area and circumference of a circle. Write a program to

prompt a user for a radius and write out the values calculated by the function. Hint: Pass values that will be modified by pointer. Useful facts: pi = 3.14 area = pi * radius2 circumference = 2 * pi * radius Solution Returning Multiple Values From Functions, Continued The second method used in C++ to pass variables into functions in a way that their values are updated in the calling routine is to pass by reference. In the previous lesson, we saw that references are an alias to a variable. When references are passed into a function or class method, any changes made to the references will be seen in the calling routine. Here is the swap program implemented using references.

#include <iostream> using namespace std; void swap(int &x, int &y); int main() { int x = 4; int y = 2; cout << "Before swap, x is " << x << ", y is " << y << endl; swap(x,y); cout << "After swap, x is " << x << ", y is " << y << endl; } void swap(int &first, int &second) { int temp;

temp = second; second = first; first = temp; }

Please compare the above program to the pointer version on the previous page and note how the syntax is simplified. In the pointer version, the pointers needed to be dereferenced within the function. This is not needed when using references. In the main program of the pointer version, the addresses of the "x" and "y" were passed into the function. The address of operator, "&", was needed. In the reference version, within main, the two variables appear directly in the argument list of swap. Compare the reference version of this program to the "pass by value" version on the previous page. Notice that the only differences are in the parameter lists in the function definition and declaration. Only within the parameter lists are the variables declared as references. Within the main program and function body, the variables are used without any special or cumbersome notation, as we saw in the pointer version. Within main and the function body the variables are used exactly as if they were passed by value, except that any updates made in the function are seen in main, as well. This is the beauty of references. The compiler handles all the details. The programmer can write code as if using ordinary variables. This was not the case with pointers. Why are pointers ever used? Remember that references cannot be reassigned in C++. If reassignment is necessary, then pointers must be used. It is also possible that the variable to be passed in may change depending on particular data conditions or particular courses of program execution. In this case it is also likely that pointers rather than references must be used. Practice Problem 1) Write a function that will calculate the area and circumference of a circle. Write a program to prompt a user for a radius and write out the values calculated by the function. Use references to pass any values that must be updated in the main program.

Useful facts: pi = 3.14 area = pi * radius2 circumference = 2 * pi * radius Solution Passing Arrays to Functions When an array is passed into a function, the function receives not a copy the array, but instead the address of the first element of the array. The function receives a pointer to the start of the array. Any modifications made via this pointer will be seen in the calling program. Let's see how this works. Suppose the main program has an array of 10 integers and that a function has been written to double each of these. void doubleThem(int a[], int size); int main() { int myInts[10] = {1,2,3,4,5,6,7,8,9,10}; doubleThem(myInts, 10); return 0; } void doubleThem(int a[], int size) { int i; for (i = 0; i < size; i++) { a[i] = 2 * a[i]; } }

Note that due to relationship between pointers and arrays in C++. This function could also be written as follows and the rest of the program could be used without modification. void doubleThem(int *pt, int size)

{ int i; for (i = 0; i < size; i++) { *pt = 2 * *pt; pt++; } }

Strings can be stored in C++ as null terminated character arrays, although the use of the string class from the standard library is preferred. Null terminated character arrays are also called Cstyle strings. To conclude this lesson, let's see how to pass C-style strings into and out of functions by implementing a string copy function. Note that a string copy function, strcpy, is part of the C and C++ standard library. #include <iostream> using namespace std; void strcpy(char *dest, char *source); int main() { char a[100] = "Hello From EasyCPlusPlus C/C++"; char b[100]; strcpy(b,a); cout << b << endl; } void strcpy(char d[], char s[]) { int i = 0; for (i = 0; s[i] != '\0'; i++) { d[i] = s[i]; } d[i] = s[i]; /* Copy null terminator to dest */

Practice Problem 1) Try compiling and running this example. 2) Try rewriting the strcpy function using pointer notation. Compile and run.

Solution Default Parameters It is possible to define defaults for some or all of the parameters of a function or class method in C++. For now, let's look at functions. If any defaults are specified they must be specified for the right most parameters in the list. Let's look at some examples of function prototypes with defaults. float calcSalesTax(float purchase, float taxRate = 0.085); int calcSomeResult(int a, float b, int c = 1, float d = 2);

Notice that the right most parameters are the ones with defaults. Here's a simple program illustrating how to use a function with default parameter values. #include <iostream> using namespace std; float calcSalesTax(float purchase, float taxRate = 0.085); int main() { float purchase; cout << "Enter purchase amount: "; cin >> purchase; float tax = calcSalesTax(purchase); cout << "Tax is: " << tax << endl; //Calculates using default rate

tax = calcSalesTax(purchase,0.075); cout << "Tax is: " << tax << endl; return 0; }

//Calculates using specified rate

float calcSalesTax(float purchase, float taxRate) { return purchase * taxRate; }

Results: Enter purchase amount: 42 Tax is: 3.57 Tax is: 3.15 Although the default is shown in the function declaration, it is possible to have the default in either the declaration or the definition, but not both. It is better to have defaults in function definitions because typically these are in include files. The source for include files is usually available for programmers as documentation for the use of functions. The function definitions may become incorporated in libraries that may become available only in compiled form. Note on Efficiency of Passing by Pointer or Reference When a function is called, copies of variables passed by value in the argument list are created in a special section of memory called the stack. For large objects such as arrays or user-defined objects this can be costly in terms of execution time and memory used. This operation is avoided when arguments are passed by reference. When passed by pointer there also can be savings. Although a copy of the pointer is made on the stack, this can be less costly that copying large objects and possible needed to invoke constructors and destructors on those objects.

Das könnte Ihnen auch gefallen