content
1. Classification of functions in C language:
Example 1: Write a function to find the maximum of two integers
Example 2: Write a function to swap the contents of two integer variables
1.2.1*** Need to learn the process of finding bugs: debugging ( F10 )
2.1 Actual parameters (actual parameters)
2.2 Formal parameters (formal parameters)
4. Nested calls and chained access of functions
5. Declaration and Definition of Functions
6.1 Two necessary conditions for recursion
Supplement: Area division in memory
6.1.3 Exercise 3: Use recursion to find the factorial of n (regardless of overflow).
6.1.4 Exercise 4: Find the nth Fibonacci number. (regardless of overflow).
1. Classification of functions in C language:
1. Library functions
2. Custom function
1.1 Library functions
In order to support portability and improve program efficiency, the basic library of C language provides a series of similar library functions (which are encapsulated in C language by common functions (such as printing data, finding string length, inputting data, etc.) ), which is convenient for programmers to develop software.
Recommend a website for learning library functions: www.cplusplus.com
After opening, you can query the library functions contained in each header file, as well as the usage and examples of library functions, etc.
For example: query strcpy function:
Note : But a secret that the library function must know is: to use the library function, the header file corresponding to #include must be included .
A brief summary, the library functions commonly used in C language are:
IO function
String manipulation functions
character manipulation functions
memory manipulation functions
time/date functions
math function
Other library functions
Do library functions need to be memorized all?
Not really. But you need to learn how to use the query tool :
MSDN(Microsoft Developer Network)
www.cplusplus.com http://en.cppreference.com (English version)
http://zh.cppreference.com (Chinese version)
1.2 Custom Functions
Like library functions, custom functions have function names, return value types, and function parameters. But the difference is that these are all designed by us. This gives programmers a lot of room to play.
The basic composition of the function:
ret_type fun_name(para1, * )
{
statement; //语句项
}
//ret_type 返回类型
//fun_name 函数名
//para1 函数参数
Example 1: Write a function to find the maximum of two integers
#include <stdio.h>
int get_max(int x, int y)
{
return (x>y)? (x):(y);
}
/*或者
int get_max(int x, int y)
{
int z = 0;
if (x > y)
z = x;
else
z = y;
return z;
*/
int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d %d", &num1, &num2);
//get_max为自己创建的自定义函数
int max = get_max(num1, num2);
printf("max = %d\n", max);
return 0;
}
Example 2: Write a function to swap the contents of two integer variables
Let's first look at an example of an error:
//错误实例
#include <stdio.h>
//bug:结果并没有交换
//找bug的过程叫:调试 F10 按F10一步一步向下走,遇到函数时按F11进入函数内部
void Swap(int a, int b)
{
int temp = 0;
temp = a;
a = b;
b = temp;
}
int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d %d", &num1, &num2);
Swap(num1, num2);
printf("num1 = %d num2 = %d\n",num1,num2); /num1与num2的值并未发生交换
return 0;
}
1.2.1*** Need to learn the process of finding bugs: debugging ( F10 )
Press F10 to go down step by step, and when you encounter a function, press F11 to enter the function
In the error instance:
It can be seen that when the swap function is executed, the values of a and b are exchanged, but the values of num1 and num2 are not exchanged
Look at the addresses of a, b, num1, and num2:
When the parameters num1 and num2 are passed to a and b, a and b open up space independently . The swap function does exchange the values of a and b, but because a, b and num1, num2 are not in the same space , so num1 and The value of num2 does not change with ab.
num1 and num2 in the example are called actual parameters - actual parameters a and b are called formal parameters - formal parameters
When an actual parameter is passed to a formal parameter, the formal parameter is a temporary copy of the actual parameter ==" Modifications to the formal parameter will not affect the actual parameter
So how to do this example correctly?
Using a pointer: Pass in the addresses of num1 and num2 through the swap function. The address of num1 stored in pnum1, so that pnum1 points to num1; similarly, pnum2 points to num2. This makes the swap function connect inside and outside.
//正确示例
#include <stdio.h>
void Swap(int* pnum1, int* pnum2)
{
int temp = *pnum1;
*pnum1 = *pnum2;
*pnum2 = temp;
}
int main()
{
int num1 = 0;
int num2 = 0;
scanf("%d %d", &num1, &num2);
Swap(&num1, &num2);
printf("num1 = %d num2 = %d\n",num1,num2);
return 0;
}
Summary: When you need to change some external variables inside the function, you need to use a pointer (the address of the variable passed into the function is entered)
2. Parameters of the function
2.1 Actual parameters (actual parameters)
The actual parameters passed to the function are called actual parameters.
Arguments can be: constants, variables, expressions, functions , etc.
Regardless of the type of quantities the actual parameters are, they must have definite values in order to pass those values to the formal parameters when the function is called.
2.2 Formal parameters (formal parameters)
Formal parameters refer to the variables in parentheses after the function name, because the formal parameters are only instantiated (allocated memory units) when the function is called , so they are called formal parameters.
Formal parameters are automatically destroyed when the function call is complete. So formal parameters are only valid within functions.
After the formal parameter is instantiated, it is actually equivalent to a temporary copy of the actual parameter.
Exercise: Implementing Binary Search with Functions
//实现函数在arr数组中查找k
//若找到返回下标,找不到返回-1(因为数组下标可以为0,所以查找失败返回值采用-1)
#include <stdio.h>
int binary_search(int arr[], int k, int sz)
{
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] > k)
right = mid - 1;
else if (arr[mid] < k)
left = mid + 1;
else
return mid;
}
return -1;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
int k = 7; //k为被查找的数字
int ret = binary_search(arr, k, sz);
if (ret == -1)
printf("未找到指定元素");
else
printf("找到了,该元素下标是:%d", ret);
return 0;
}
It should be noted that if sz = sizeof(arr) / sizeof(arr[0]) is used inside the binary_search function to calculate the length of the array, the search will fail:
#include <stdio.h>
int binary_search(int arr[], int k)
{
int sz = sizeof(arr) / sizeof(arr[0]);
int left = 0;
int right = sz - 1;
while (left <= right)
{
int mid = (left + right) / 2;
if (arr[mid] > k)
right = mid - 1;
else if (arr[mid] < k)
left = mid + 1;
else
return mid;
}
return -1;
}
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7; //k为被查找的数字
int ret = binary_search(arr, k);
if (ret == -1)
printf("未找到指定元素");
else
printf("找到了,该元素下标是:%d", ret);
return 0;
} //未找到指定元素
The reason for the failure of the search is that when arr is passed to the binary_search function, only the address of the first element in the arr array is passed to the function. At this time, sizeof(arr) = 4, so the search fails.
When an array is passed as a parameter, the address of the first character of the array is passed in
So when the number of array elements needs to be calculated in the function, after the calculation is done outside the function, it is passed into the function.
3. Function call:
3.1 Call by value
The formal parameters and actual parameters of the function occupy different memory blocks respectively, and the modification of the formal parameters will not affect the actual parameters.
3.2 Call by address
Call by reference is a way to call a function by passing the memory address of a variable created outside the function to the function parameter.
This method of passing parameters allows the function to establish a real connection with the variables outside the function , that is, the function can directly operate the variables outside the function.
Example: Write a function that increments the value of num by 1 each time the function is called
#include <stdio.h>
void Add(int* p)
{
*p = *p + 1 ;
}
int main()
{
int num = 0;
Add(&num);
printf("num = %d\n", num); //1
Add(&num);
printf("num = %d\n", num); //2
return 0;
}
4. Nested calls and chained access of functions
Functions and functions can be combined according to actual needs, that is, they can call each other.
4.1 Nested calls
Functions can be called nested, but not nested definitions
#include <stdio.h>
void new_line()
{
printf("hehe\n");
}
void three_line()
{
int i = 0;
for (i = 0; i < 3; i++)
{
new_line();
}
}
int main()
{
three_line();
return 0;
}
4.2 Chain access
Use the return value of one function as an argument to another function
#include <stdio.h>
int main()
{
printf("%d", printf("%d", printf("%d", 43))); //4321
return 0;
In MSDN, it can be found that the return value of the printf function is the number of characters printed, and a negative value is returned when an error occurs
5. Declaration and Definition of Functions
5.1 Function declaration
1. Tell the compiler what a function is called, what the parameters are, and what the return type is. But whether it exists or not is not determined by the function declaration.
2. The declaration of a function generally appears before the use of the function . To satisfy the declaration before use .
3. Function declarations are generally placed in header files .
The writing method in the textbook: (This writing method is generally not used)
#include <stdio.h>
//声明一下
//声明函数 - 告诉编译器有一个函数,名叫ADD,2个参数都是int类型,函数返回类型是int
int Add(int x, int y);
int main()
{
int a = 10;
int b = 20;
int ret = Add(a, b);
printf("%d\n", ret);
return 0;
}
//函数定义
int Add(int x, int y)
{
int z = x + y;
return z;
}
Writing in the project:
5.2 Function Definition
The definition of a function refers to the specific implementation of the function, and the function implementation of the function is explained.
6. Function recursion
The programming technique in which a program calls itself is called recursion.
Recursion as an algorithm is widely used in programming languages.
A procedure or function has a method in its definition or specification that calls itself directly or indirectly.
It usually converts a large and complex problem into a smaller problem similar to the original problem to solve. The recursive strategy only needs a small number of programs to describe the repeated calculations required for the problem-solving process. The code size of the program is reduced.
The main way of thinking about recursion is: make big things small
6.1 Two necessary conditions for recursion
Baseline case : There is a constraint , when this constraint is met, the recursion does not continue.
Keep pushing : getting closer and closer to this limit after each recursive call .
Supplement: Area division in memory
Every function call needs to allocate space.
Therefore, when writing recursive functions, you must pay attention to two necessary conditions, otherwise stack overflow may occur .
6.1.1 Exercise 1: Take an integer value (unsigned) and print its bits in order. (solve with recursion)
Analysis, when inputting 1234, you need to use the function to output 1 2 3 4 , then use the recursive simplification idea:
Assuming that the custom print function is print, then:
1. When the incoming number is greater than or equal to two digits (>9), continue to divide
2. When divided to the one digit, print
The picture is:
code show as below:
#include <stdio.h>
void print(int n)
{
if (n > 9)
{
print(n / 10);
}
printf("%d ", n % 10);
}
int main()
{
unsigned int num = 0;
scanf("%d", &num);
print(num);
return 0;
}
6.1.2 Exercise 2: Write a function that does not allow the creation of temporary variables and finds the length of a string.
Create a version of the temporary variable (count):
#include <stdio.h>
int my_strlen(char* str)
{
int count = 0;//计数器
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);//传入的是首字符的地址,所以用字符指针接收
printf("%d\n", len); //6
return 0;
}
Version without creating temporary variables (recursive version) :
Recursive idea:
#include <stdio.h>
int my_strlen(char* str)
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr[] = "abcdef";
int len = my_strlen(arr);//传入的是首字符的地址,所以用字符指针接收
printf("%d\n", len);
return 0;
}
6.1.3 Exercise 3: Use recursion to find the factorial of n (regardless of overflow).
Recursive idea:
n! = n * (n-1) , n>= 2;
n! = 1 , n<= 1;
int Fac(int a)
{
if (a > 1)
return a * Fac(a - 1);
else
return 1;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fac(n);
printf("%d\n", ret);
return 0;
}
6.1.4 Exercise 4: Find the nth Fibonacci number. (regardless of overflow).
Fibonacci sequence: 1 1 2 3 5 8 13 21 34 55...
Rule: The nth number is equal to the sum of the first two numbers of n
Fib(n) = 1, n <= 2
Fib(n) = Fib(n - 1) + Fib(n - 2), n <= 2
Recursive idea:
#include <stdio.h>
int Fib(int a)
{
if (a > 2)
return Fib(a - 1) + Fib(a - 2);
else
return 1;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
The Fibonacci recursion code without pruning operation is very inefficient. If the parameter is relatively large, it will report an error: stack overflow (stack overflow).
The stack space allocated by the system to the program is limited, but if there is an infinite loop, or (dead recursion), it may cause the stack space to be opened all the time, and eventually cause the stack space to be exhausted, that is, stack overflow.
How to solve the above problem:
1. Rewrite recursion to be non-recursive.
2. Use static objects instead of nonstatic local objects .
In recursive function design, static objects can be used to replace nonstatic local objects (ie stack objects), which can not only reduce the overhead of generating and releasing nonstatic objects each time recursive calls and returns are made, but also static objects can save the intermediate state of recursive calls , and can be accessed by various call layers.
Non-recursive version:
the first time:
a = 1,b = 1,c = a + b
the second time:
a = b,b = c,c = a + b
So the non-recursive code is:
//更简洁的代码
#include <stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
while(n > 2)
{
c = a + b;
a = b;
b = c;
n--;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
//初始构思的代码
#include <stdio.h>
int Fib(int n)
{
int a = 1;
int b = 1;
int c = 1;
int i = 0;
if (n <= 2)
return 1;
for (i = 0; i < n - 2; i++) //因为逻辑上当n > 2时,才开始循环,所以n=3对应第1次循环 所以
//判断条件为i < n - 2
{
a = b;
b = c;
c = a + b;
}
return c;
}
int main()
{
int n = 0;
scanf("%d", &n);
int ret = Fib(n);
printf("%d\n", ret);
return 0;
}
summary:
1. Many problems are explained in recursive form simply because it is clearer than the non-recursive form.
2. But iterative implementations of these problems are often more efficient than recursive implementations, 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.