An indispensable part of C language-function

1. What is a function?

(1) In computer science, a subroutine (English: Subroutine, procedure, function, routine, method,
subprogram, callable unit) is a certain part of the code in a large program composed of one or more statement blocks
. It is responsible for completing a specific task, and is relatively independent compared to other codes.
(2) Generally, there will be input parameters and return values, providing encapsulation of the process and hiding of details. These codes are usually integrated into software
libraries.

In the C language, functions are an indispensable part of writing code, because we can't write all functions in the main function, so we need a variety of library functions and custom functions.

Library Functions

The library functions are like the input and output functions printf and scanf we usually use, the string copy function strcpy, and the mathematical functions: square function sqrt and power function pow, etc. These are provided in the basic library of C language Function to facilitate our software development. Therefore, in the learning of C language, one of the most needed skills is to use some software to learn different library functions and use them proficiently.

Commonly used websites are: www.cplusplus.com
en, cppreference.com
Commonly used offline tools: MSDN (Microsoft Developer Network)
Regarding MSDN, self-collection if necessary: ​​https://pan.baidu.com/s/1nHiYFsbrUATplBcs8Ff0Kw (extract Code: ybhz)

But with library functions, don't we need to write functions ourselves? It must be impossible. The library function only helps us integrate some of the more commonly used functions, but it does not meet all our needs. Therefore, the custom function is the most important. It can implement various functions according to our ideas. Kind of function.

Custom function

The following is the basic definition of
a function : functions have function names, return value types and function parameters, all of which are designed by us, and different functions are designed according to different functional requirements.

Insert picture description here
Note: But the most important thing in writing a function is that the function of the function must be independent, which means that each function can be used not only by you, but also by others, which means it must be applicable. When writing a function, it is necessary to isolate this function from other functions.

For example, the following example:
find the maximum value between two numbers

int get_max(int x, int y)
{
    
    
	return (x>y)?(x):(y);
}
int main()
{
    
    
	int num1 = 10;
	int num2 = 20;
	int max = get_max(num1, num2);
	printf("max = %d\n", max);
	return 0;
}

In the get_max function, there is only one function, which is to find the maximum value, while the printing function is completed after the call, which ensures the independence of the function. Because maybe you need to print it out with this function, others may just want to find the maximum value. If you put the printing function in the function, it will make others unable to achieve the desired result when using it.

2. The return value and parameters of the function

There are two more important places in the definition of a
function : 1. The return value of the
function The return value of a function is not necessarily required, but it must be written in the function definition. If there is a return value, write the type of the return value, if not, use void.
2. Function parameters The
function parameters are divided into actual parameters (actual parameters) and formal parameters (formal parameters).
Actual parameters: The parameters actually passed to the function are called actual parameters. The actual parameters can be: constants, variables, expressions, functions, etc. No matter what kind of quantity the actual parameters are, they must have certain values ​​when the function is called in order to transfer these values ​​to the formal parameters.
Formal parameters: Formal parameters refer to the variables in parentheses after the function name. Because the formal parameters are instantiated (allocated memory units) only when the function is called, they are called formal parameters. The formal parameters are automatically destroyed when the function call is completed. Therefore, formal parameters are only valid in functions.

Insert picture description here

For example, in the above get_max function, num1 and num2 are actual parameters, which are the parameters passed to get_max in the main function, and have a certain value before the function is called. The x and y inside get_max are formal parameters, and space is allocated only when called, and it will be destroyed after the life cycle of the function. Therefore, the instantiation of the formal parameter is equivalent to a temporary copy of the actual parameter, because the contents of x and y are exactly the same, but the memory space is different.

3. Call by value and call by address

After the function is written, it is necessary to call the function.
Function call is divided into value call and address call:

Call by value: The formal parameters and actual parameters of the function occupy different memory blocks, and the modification of the formal parameters will not affect the actual parameters.
Call by address: Call by address is a way to call a function by passing the memory address of the variable created outside the function to the function parameter.
This way of passing parameters allows the function to establish a real connection with the variables outside the function, that is, the variables outside the function can be directly manipulated inside the function.

In other words, if the internally implemented function of the custom function does not need to change the value of the externally passed parameter in the custom function, use the pass-by-value call; if you want to change the value of the externally passed parameter in the custom function, It is necessary to use the address call, that is, to give the address of the actual parameter to the custom function, so that the custom function can find the memory space where the actual parameter is located by the address. This part will be explained in detail in the pointer, now use the following example to explain:

#include <stdio.h>
void Swap1(int x, int y)
{
    
    
int tmp = 0;
tmp = x;
x = y;
y = tmp;
}

void Swap2(int *px, int *py)
{
    
    
int tmp = 0;
tmp = *px;
*px = *py;
*py = tmp;
}

int main()
{
    
    
int num1 = 1;
int num2 = 2;
Swap1(num1, num2);
printf("Swap1::num1 = %d num2 = %d\n", num1, num2);
Swap2(&num1, &num2);
printf("Swap2::num1 = %d num2 = %d\n", num1, num2);
return 0;
}

Swap1 in the main function is called by value, and Swap2 is called by address. The function of the function is to exchange two integers.

Let’s take a look at the running results of the two functions:
Insert picture description here
As can be seen from the running results, the Swap1 function does not change the values ​​of a and b. This is because the Swap1 function is called by value, but the values ​​of a and b are passed in the past. The x and y in Swap1 exist in another memory space, so the values ​​of a and b cannot be changed. And Swap2 completes the exchange of a and b. Because the addresses of a and b are passed, the Swap2 function finds and modifies the values ​​of a and b through the addresses. This is the difference between call by value and call by address.

4. Nested function call and chain access

Nested call

The nested call of a function is to call other functions within the execution of a function to realize the function of the function. For example, the following code:

#include <stdio.h>

void print()
{
    
    
	printf("hehe\n");
}
int main()
{
    
    
	print();
	return 0;
}

Calling the print function inside the main function to print hehe on the screen is a nested call of the function, and calling the library function printf in the print function is also a nested call. It can be said that nested calls combine different functions to form a whole.

Chain access

Chained access refers to the return value of a function as a parameter of another function, which runs like a chain, connected in series.

#include <stdio.h>

int mul(int x,int y)
{
    
    
	return x * y;
}
int sum(int x,int y)
{
    
    
	return x + y;
}
int main()
{
    
    
	int a=2;
	int b=3;
	printf("%d\n",mul(sum(a,b),3));
	return 0;
}

In the above code, mul(sum(a,b),3) is a chain access, and the return value of sum(a,b) is used as the parameter of the mul() function. At the same time, the return value of the mul() function is also a parameter of the printf function, and chained access connects these three functions in series.

5. Function declaration and definition

1. The function declaration is to tell the compiler what the function is called, what the parameters are, and what the return value is, but it does not matter whether the function exists or not.
2. The declaration of the function generally appears before the use of the function, and it must be declared first and then used
. 3. The declaration of the general function is written in the header file, and the definition of the function is placed in another .c file. This is done The purpose is to make the entire code modular, easy to modify and use.

Insert picture description here
The definition of a function refers to the concrete realization of the function, explaining the function realization of the function.

6. Function recursion

What is recursion?

The programming technique of a program calling itself is called recursion. Recursion is widely used as an algorithm in programming languages. A process or function has a method of directly or indirectly calling itself in its definition or description. It usually converts a large and complex problem into a smaller problem similar to the original problem to solve. The recursive strategy only A small amount of programs can be used to describe multiple repetitive calculations required in the process of solving problems, which greatly reduces the amount of program code. The main way of thinking about recursion is: make big things small

Necessary conditions for recursion

There are two necessary conditions for
recursion : 1. Recursion must have a restriction. When this restriction is met, the recursion will not continue. In other words, recursion cannot be infinitely recursive, otherwise the stack will overflow.
2. After each recursive call, it will get closer and closer to this restriction.

Recursion must meet these two conditions, but recursion that meets these two conditions is not necessarily more efficient.

Here is an example to see what recursion looks like:

#include <stdio.h>
void print(int n)
{
    
    
	if(n>9)
	{
    
    
		print(n/10);
	}
	printf("%d ", n%10);
	}
int main()
{
    
    
	int num = 1234;
	print(num);
	return 0;
}

The above function is to print each digit of an integer.
It can be seen that n>9 is the restriction condition, and n/10 loses one bit each time, and it will continue to approach the restriction condition after each recursive call.

But sometimes using recursion does not necessarily improve efficiency. For example, we use recursion to find the nth number of the Fibonacci sequence:

int fib(int n)
{
    
    
if (n <= 2)
return 1;
else
return fib(n - 1) + fib(n - 2);
}

When running, it is very time consuming to calculate the 50th Fibonacci number.
Let's add a counter to the code to see how many times the third Fibonacci number is calculated when calculating the 30th Fibonacci number.
Insert picture description here
Calculated 317811 times, it can be seen that using recursion to calculate Fibonacci numbers is very inefficient.

But if you switch to a loop, it will be much faster:

int fib(int n)
{
    
    
	int result;
	int pre_result;
	int next_older_result;
	result = pre_result = 1;
	while (n > 2)
	{
    
    
		n -= 1;
		next_older_result = pre_result;
		pre_result = result;
		result = pre_result + next_older_result;
	}
	return result;
}

So there are a few notes:

  1. Many problems are explained in a recursive form, simply because it is clearer than the non-recursive form.
  2. But the iterative implementation of these problems is often more efficient than the recursive implementation, although the code is slightly less readable.
  3. When a problem is quite complex and difficult to implement iteratively, the simplicity of recursive implementation can compensate for the runtime overhead it brings.

The use of recursion depends on the situation. If it is more efficient to use loops, use loops. If recursion is more efficient, use recursion.

Guess you like

Origin blog.csdn.net/qq_41490958/article/details/112971847