200 likes | 216 Views
Consider the example: int min(int a, int b) { // min function return (a < b ? a : b); } int main(void) { int x = 5, y = 10; cout << min(x, y) << endl; } When the min function is called, two new data objects are created and filled-in with the values of the arguments:.
E N D
Consider the example: int min(int a, int b) { // min function return (a < b ? a : b); } int main(void) { int x = 5, y = 10; cout << min(x, y) << endl; } When the min function is called, two new data objects are created and filled-in with the values of the arguments: Calling a Function
These data objects have type int (as specified in the function declaration). They may be used or changed just like other data objects, Changing their values does not change the values of x or y in main – they are different data objects The new data objects disappear once the function is finished. Calling a function (cont'd)
Think of functions as tasks that you don't want to do yourself – that you send off to your administrative assistant to be done. You specify the input that is needed and say what the output should be. Your assistant does the rest – takes the input. computes some value, and returns that value to you That way you (main) can concentrate on other tasks. Why use Functions?
Another way to think of a function is as a small program. Programs have input and have output and do some computation. That's exactly what a function does. It's a small, packaged program. More on Functions
We can use functions to break down large programming tasks into small pieces. Each function adds an additional operation to the program that can be used by other parts. In top-design, when we break the task into smaller steps, each step can be implemented by a function. Program Design
The last way to think of a function is a way to avoid repeated code. Instead of writing the same code fragment over and over again, we write it once, package it as a function, and call it repeatedly. The fragment doesn't have to be exactly the same each time. We can abstract out the differences, and represent values that vary from each call by the parameters. Functional Abstraction
Suppose we want to print out a bar chart with five lines of asterisks. The first line has 10 stars, the second 15, the third, 12, the fourth 3, and the last line has 9. We could use a different loop for each line. ********** *************** ************ *** ********* Example
for(int i1 = 0; i1 < 10; i1++) cout << “*”; cout << endl; for (int i2 = 0; i2 < 15; i2++) cout << “*”; cout << endl; for (int i3 = 0; i3 < 12; i3++) cout << “*”; cout << endl; for (int i4 = 0; i4 < 13; i4++) cout << “*”; cout << endl; for (int i5 = 0; i5 < 19; i5++) cout << “*”; cout << endl; One Solution
This code is repetitive and boring. It would be better to write the code once, as a function, abstract out the differences between the five code segments, and use a variable to represent those differences. We would call the function five times, with different arguments each time. But...
void printStars(int n) { // print out n stars for (int i = 0; i < n; i++) cout << “*”; cout << endl; } int main(void) { printStars(10); printStars(15); printStars(12); printStars(3); printStars(9); } Another Solution
Writing the code once and calling it repeatedly makes it easier to write, understand, and modify the code. Giving the section of code a mnemonic name (printStars) makes it easier for humans to follow the code. This could be part of the breakdown into code for a larger problem. About this Solution
Write a function void printRect(int m, int n) that prints out an m x n rectangle of asterisks, and then, in main, call it to print out a 5 x 5 rectangle, a 10 x 2 rectangle, a 2 x 10 rectangle, and a 40 x 4 rectangle. Exercise
Up until now, we have been using one kind of parameter, the call-by-value parameter. Call-by-value parameters created new data objects when the function is called. Changing the value of a call-by-value parameter, does not change the corresponding (if it is a variable) in the calling function. Call-by-value parameters are used as input parameters to the function. Call-by-value Parameters
Sometimes we want a function to return more than one value to the calling function. The return value is just one value (until we learn about structures and objects). Sometimes we would like to use the parameters to pass values back to the calling function. For this reason, C++ has another type of parameter, call-by-reference parameter. Returning more than one value
Suppose we want to write a function that returns both the min and the max of two values. We will use call-by-reference parameters rather than the return value to return those two numbers: void findMinMax(int a, int b, int& min, int& max) { if(a < b) { min = a; max = b; } else { min = b; max = a; } } Example
int main(void) { int x = 5, y = 10, z, w; findMinMax(x, y, z, w); cout << “Min = “ << z << “, Max = “ << w << endl; } Calling Function
The only syntactic difference is those little, hard-to-see, ampersands (“&”) after the type names. But the semantic difference is huge. When the main function is run, four new data objects are created: What's the Difference?
But when the function, findMinMax, is called, two new data objects are created for the call-by-value parameters, just like before. However, that's not the case for the call-by-reference parameters. Instead those identifiers (min, max) become additional labels for the corresponding arguments. The Difference
When the function is executed, the values given to min and max are put into the existing data objects. Function Execution
When the function, findMinMax, completes, the two new data objects (a and b) go away, as do the labels, min and max, leaving the data objects z and w in main changed: Finishing up