Chapter 7 - Functions (C++ programming modules)

Review the basics of functions

To use C++ functions, the following work must be done:

  • Provide a function definition
  • Provide function prototype
  • Call functions 

A library function is a function that has been defined and compiled, and the standard library header file can be used to provide its prototype, so it is only necessary to call this function correctly. But when creating your own functions, you have to handle the 3 aspects mentioned above by yourself. For example

#include<iostream>
using namespace std;

void hello();	//函数的声明

int main()
{
	cout << "主函数将调用自己编写的hello这个函数:" << endl;
	hello();	//函数的调用
	cout << "调用自编函数hello结束" << endl;
	return 0;
}

//函数的声明
void hello() 
{
	cout << "我向大家问好!"<<endl;
}

 

Programs are executed in line order. When the function hello() is executed, the code in main() will be suspended; after the function hello() is executed, the code in main() will continue to be executed. 

define function

Functions can be divided into two categories: functions that do not return a value and functions that return a value.

A function that does not return a value is called a void function , and the general format is as follows:

void functionName(parameterList)
{
    statement(s)
    return;
}

 Among them, parameterList specifies the type and number of parameters passed to the function.

A function that returns a value generates a value and returns it to the calling function . The return type of such a function is declared as the type of the return value. The general format is as follows:

typeName functionName(parameterList)
{
    statement(s)
    return value;
}

 For functions that return a value, a return statement must be used to return a value to the calling function. Note that the type of the return value cannot be an array, but can be any other type - integer, float, pointer, structure, object

The function ends after executing the return statement. If a function contains multiple return statements, the function ends after executing the first return statement it encounters. For example

int bigger(int a,int b)
{
    if(a > b)
        return a;
    else
        return b;
}

 Function Prototypes and Function Calls

See an example below

#include<iostream>
using namespace std;
void cheers(int);		//prototype, no return value
double cube(double x);  //prototype, return a double
int main()
{
	cheers(5);			//function call
	cout << "Give me a number: ";
	double side;
	cin >> side;
	double volume = cube(side);   //function call
	cout << "A " << side << "-foot cube has a volume of ";
	cout << volume << " cubic feet" << endl;
	cheers(cube(2));
	return 0;
}

void cheers(int n)
{
	for (int i = 0; i < n; i++)
	{
		cout << "Cheers! ";
	}
	cout << endl;
}
double cube(double x)
{
	return x * x * x;
}

 

1. Why do you need a prototype?

The prototype describes the function's interface to the compiler, that is, it tells the compiler the type of the function's return value (if any) and the types and number of parameters.

How does the function prototype affect the following statement? 

double volume = cube(side);

 For the above statement, the function prototype tells the compiler that cube() has a double parameter. If the program does not provide such parameters, the prototype will allow the compiler to catch such errors; secondly, after the cube() function completes the calculation, it will put the return value in the specified position, and then call the function (here is the main() function) The return value will be fetched from this specified location. Since the prototype states that the return type of cube() is double, the compiler knows how many bytes it should retrieve and how to interpret them. Without this information, the compiler can only make guesses, which the compiler doesn't do.

2. Syntax of Prototypes

The prototype of a function is a statement, so it must end with a semicolon. The easiest way to do this is to copy the function header in the function definition and add a semicolon. (The function prototype does not require variable names, just a list of types; both of the following are correct)

void hell(int);
void hell(int x);

3. The function of the prototype

Prototypes ensure the following:

  • The compiler correctly handles function return values
  • The compiler checks that the correct number of arguments are used
  • The compiler checks that the parameter type used is correct; if not, converts to the correct type within its capabilities 

Function parameters and passing by value 

 C++ generally passes parameters by value, which means passing a numeric parameter to a function, which in turn assigns it to a new variable.

The variables used to receive the passed values ​​are called formal parameters, and the values ​​passed to the function are called actual parameters.

 Variables (including parameters) declared in a function are private to that function. When the function is called, the computer will allocate memory for these variables, and when the function ends, the computer will release the memory used by these variables. Such variables are called local variables.

If you declare a variable named x in main() and a variable named x in another function, they will be two completely different and unrelated variables

multiple parameters

 Functions can have multiple parameters, just separate them with commas when calling the function:

n_chars('R',50);

 The above function call passes two arguments to the function n_chars()

Similarly, when defining a function, use a comma-separated list of parameter declarations in the function header

void n_chars(char c,int n)  //two arguments

The function header points out that the function n_chars() accepts a char parameter and an int parameter, and the type of each parameter must be specified separately, and declarations cannot be combined like regular variables.

functions and arrays

Functions are the key to dealing with complex types (such as arrays, structures), let's learn how to combine arrays and functions

Assuming that we want to calculate the sum of all elements in an array now, we can use the for loop to traverse and add one by one, so that every number has to be modified accordingly. Here we write a unified interface to make as few modifications as possible for different arrays, without having to write a new loop every time.

#include<iostream>
using namespace std;
const int ArSize = 8;
int sum_arr(int arr[], int n);
int main()
{
	int cookies[ArSize] = { 1,2,4,8,16,32,64,128 };
	int sum = sum_arr(cookies, ArSize);
	cout << "Total cookies: " << sum << endl;
	return 0;
}
int sum_arr(int arr[], int n)
{
	int total = 0;
	for (int i = 0; i < n; i++)
	{
		total = total + arr[i];
	}
	return total;
}

 

 Let's look at the function header

int sum_arr(int arr[], int n)

 The square brackets indicate that arr is an array, and the empty square brackets indicate that an array of any length can be passed to the function. But this is not the case: arr is not actually an array, but a pointer. (You can think of arr as an array while writing the rest of the function)

How functions use pointers to handle arrays

As mentioned earlier, C++ interprets an array name as the address of its first element

cookies == &cookies[0]

 The array declaration uses the array name to mark the storage location. Using sizeof on the array name will get the length of the entire array (in bytes). When the address operator & is used for the array name, it will return the address of the entire array

In the function call:

int sum = sum_arr(cookies, ArSize);

Among them, cookies is the name of the array, and according to the C++ rules, cookies is the address of its first element, so the function passes the address. Since the element type of the array is int, the type of cookies must be an int pointer, ie int*. This suggests that the correct function header should look like this :

int sum_arr(int *arr,int n)

This proves that both function headers int *arr and int arr[] are correct. Because in C++, if and only if used in function header or function prototype, they both have the same meaning, both mean that arr is an int pointer. In other contexts, int * arr and int arr[ ] have different meanings. 

 We can see that the above program does not pass the contents of the array to the function, but passes the location (address), the type of elements (type) and the number of elements (variable n) of the array to the function. With this information, The function can then use the original array.

When passing a regular variable , the function will use a copy of the variable ; but when passing an array , the function will use the original array .

 Taking an array address as an argument saves the time and memory required to copy the entire array.

pointers and const

The const keyword can be used with pointers in two different ways.

The first method is to let the pointer point to a constant object, which prevents the pointer from being used to modify the pointed value;

int age = 39;
const int* pt = &age;

The statement states that pt points to a const int (39), so pt cannot be used to modify this value

*pt += 1;      //INVALID
cin >> *pt;    //INVALID

The declaration of pt does not imply that the value it points to is actually a constant, only that the value is constant to pt. (For example, pt points to age, but age is not const. You can directly modify the value of age through the age variable, but you cannot use the pt pointer to modify it)

*pt = 20; //INVALID
age = 20;

Note here that there are two more cases. In the past, we always assigned the address of a regular variable to a regular pointer, but here we assign the address of a regular variable to a pointer to const (so there are two more cases: assigning the address of a const variable to To a pointer to const, assign the address of a const variable to a regular pointer. In fact, only the first is feasible, and the second is not feasible )

const float g_earth = 9.8;
const float *pe = &g_earth;    //VALID

 For this case, neither g_earth can be used to modify the value 9.8, nor can the pointer pe be used to modify it.

 use const whenever possible

There are two reasons to declare pointer parameters as pointers to constant data:

1) This avoids programming errors due to unintentional modification of data

2) Use const to enable the function to handle const and non-const arguments, otherwise it can only accept non-const parameters

The second way is to declare the pointer itself as a constant, which prevents changing what the pointer points to.

int sloth = 3;
int *const finger = &sloth;

 This declaration structure makes finger can only point to sloth, but allows the use of finger to modify the value of sloth

recursion

C++ functions have an interesting feature - they can call themselves (unlike C language, C++ does not allow main() to call itself), this feature is called recursion.

 If a recursive function calls itself, the called function will also call itself, which will continue in an infinite loop unless there is something in the code that terminates the chain of calls. The usual approach is to place the recursive call inside an if statement, as in the following recursive function

void recurs(argumentlist)
{
    statements1
    if(test)
        recurs(arguments2)
    statements2
}

Guess you like

Origin blog.csdn.net/yangSHU21/article/details/131632030