C语言的函数分类:
1.库函数:
1.1 IO函数
1.2 字符串操作函数
1.3 字符操作函数
1.4内存操作函数
1.5时间/日期函数
1.6数学函数
1.7其他库函数
如何学习使用其他不熟悉的库函数呢?
搜索网站:cplusplus.com - The C++ Resources Network
百度一下,你就知道 (doge)
是不是学会了,咱们浅试一下~
#include
#include
int main()
{
char arr1[] = "bit";
char arr2[20] = "#####";
strcpy(arr2, arr1);
printf("%s\n", arr2);
return 0;
}
如何学会使用库函数?
需要全部记住吗?漏!只需要运用查询工具即可:
MSDN(Microsoft Developer Network)
cplusplus.com - The C++ Resources Network
https://en.cppreference.com/
2.自定义函数
自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是需要我们自己来设计。
函数的组成:
ret_type fun_name(paral, *)
{
statement;//语句项
}
ret_type 返回类型
fun_name 函数名
paral 函数参数
浅试一下吧:
求最大值的函数
get_max(int x, int y)
{
if (x > y)
return x;
else
return y;
}
int main()
{
int a = 10;
int b = 20;
int max = get_max(a, b);
printf("max = %d\n", max);
return 0;
}
再写一个函数吧
交换值的函数:
这个代码交换了a和b的值了吗?
int main()
{
int a = 10;
int* pa = &a;//pa指针变量
*pa = 20;//解引用操作符
printf("%d\n", a);
return 0;
}
void Swap(int* pa, int* pb)//void表示空,即没有返回值
{
int tmp = 0;
tmp = *pa;
*pa = *pb;
*pb = tmp;
}
int main()
{
int a = 10;
int b = 20;
Swap(&a, &b);
printf("a=%d,b=%d\n", a, b);
return 0;
}
知识点来咯:
形参(形式参数)
在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为形式参数,简称形参。
实参(实际参数)
函数被调用时给出的参数包含了实实在在的数据,会被函数内部的代码使用,所以称为实际参数,简称实参。
上面的函数中的参数x,y,pa,pb 都是形式参数,在main函数中传给swap函数的num1和num 2都是实际参数。
注:当实参传给形参的时候,形参其实是实参的一份临时拷贝,对形参的修改是不会改变实参的。
函数的调用:
传值调用:函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
传值调用:传值调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也会就是函数内部可以直接操作函数外部的变量。
传址调用
练习:
写一个函数可以判断是不是素数
int is_prime(int n)
{
int j = 0;
for (j = 2; j < n; j++)
{
if (n % j == 0)
return 0;
}
return 1;
}
int main()
{
int i = 0;
for (i = 100; i <= 200; i++)
{
//判断i是否为素数
if (is_prime(i) == 1)
printf("%d ", i);
}
return 0;
}
二分查找
int binary_search(int arr[], int k, int sz)
{
//算法的实行
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)
{
left = mid + 1;
}
else if (arr[mid] > k)
{
right = mid - 1;
}
else
{
return mid;
}
}
return -1;
}
int main()
{
// 二分查找
//在一个有序数组中查找具体的某个数
//如果找到了返回这个数的的下表,找不到的返回-1
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int k = 7;
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = binary_search(arr, k, sz);
if (ret == -1)
{
printf("找不到指定的数字\n");
}
else
{
printf("找的到,下标是:%d\n", ret);
}
return 0;
}
函数的嵌套调用和链式访问
函数和函数之间可以有机结合
嵌套调用
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;
}
链式访问
把一个函数的返回值作为另外一个函数的参数
int main()
{
int len = 0;
//1
len = strlen("abc");
printf("%d\n", len);
//2
printf("%d\n", strlen("abc"));
return 0;
}
练习:
以下代码输出值是多少?
int main()
{
printf("%d", printf("%d", printf("%d",43)));
return 0;
}
答案;4321
函数的声明与定义
函数的声明一般放在.h头文件中,函数调用可以放在.c源文件中。函数要满足先声明后使用。
函数的递归
递归函数是“自己调用自己”的函数,可以采用直接或间接调用方式。间接递归意味着函数调用另一个函数(然后可能又调用第三个函数等),最后又调用第一个函数。因为函数不可以一直不停地调用自己,所以递归函数一定具备结束条件。递归的主要思考方式在于:把大事化小。
递归的必要条件:
1.存在限制条件,当满足这个限制条件时,递归便不再继续。
2.每次递归调用之后越来越接近这个限制条件。
练习:
接受一个整型值(无符号),按照顺序打印它的每一位。例如:输入123,输出:1 2 3
参考代码:
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;
}
练习2:
编写函数不允许创建临时变量,求字符串的长度
/*int my_strlen(char* str)
{
int count = 0;
while (*str != '\0')
{
count++;
str++;
}
return count;
}8*/
int my_strlen(char* arr)
{
if (*str != '\0')
return 1 + my_strlen(str + 1);
else
return 0;
}
int main()
{
char arr[] = "bit";
int len = my_strlen(arr);//arr'是数组,数组传参,传过去的不是整个数组,而是第一个元素的地址
printf("len = %d\n", len);
return 0;
}
递归与迭代
描述第n个斐莫那切数列
int Fib(int n)
{
if (n <= 2)
return 1;
else
return Fib(n - 1) + Fib(n - 2);
}
int main()
{
int n = 0;
int ret = 0;
scanf("%d", &n);
//TDD-测试驱动开发
ret = Fib(n);
printf("ret = %d\n", ret);
return 0;
}
函数递归的经典题目(感兴趣可自主研究)
1.汉诺塔问题
2.青蛙跳台阶问题