- 一、对函数的了解
- 1、函数定义的理解
- 2、函数的分类
- 3、创建这些函数的好处
- 4、函数的结构
- 5、函数的调用
- 6、函数的嵌套
- 7、函数的链式访问
函数是由多行代码组成的,它是为了完成某一项具体的任务
跟其他多行代码相比较来说,函数更具有独立性。
对于它是如何完成一项任务,我们可以把函数类比于一个加工厂,加工之前,需要有材料输入到加工厂,最后通过加工,输出产品,函数与加工厂有着类似的功能,也是将数值输入到函数里面,通过处理,得到结果。
函数分为库函数和自定义函数
库函数顾名思义就是库里面的函数,C语言自带的函数
自定义函数是程序员可以自己创建的函数。
创建函数之后,大大提高了程序的效率和支持可移植性。
对于库函数来说,当我们在编写程序时,总是有基础功能,我们经常使用,所以我们可以把形成这个功能的代码,封装成一个函数,在每次使用这个功能的时候,就直接调用这个函数就可以,大大提高了程序的效率。
并且我们每一个程序员都可以使用这个函数。
对于自定义函数来说,由于是我们个人编写的,所以其他程序员用不了我们自己写的函数,只能是自己用,我们也是把一个具体的功能,封装成一个函数,提高了程序的效率。
完整的函数包括函数名,参数,和返回类型。
对于返回类型:
如果函数有返回值,就需要一个对于的数据类型来接收,
如果没有返回值,就不需要返回类型,只用写void。
对于参数:
分为实参和形参
实参的意思是实际的参数,当我们调用函数时,传给函数的一个真实的值,这个值就是实参。
需要注意的是:
必须是一个真实的值,不可以是一个未知数,这里可以想象一下加工厂,当我们要使用加工厂加工产品的时候,我们需要传给加工厂真实的材料才可以,对于函数也是一样,需要传给函数一个真实的值,函数才会处理。
形参的意思是形式参数,当我们调用函数时,形参是用来接收实参传过来的值的,就像当我们给加工厂传给材料,需要接收材料,把这些材料放到一个仓库里面。
需要注意的是:
形参和局部变量的功能类似,局部变量的作用范围是大括号之内,进了大括号之后,局部变量被创建,发挥作用,出大括号之后,局部变量被销毁。
没有调用函数时,没有值传给函数,用不到形参接收,就没有必要实例化。
调用函数时,有值传给函数了,需要用到形参接收了,就会被实例化。
调用完成之后,用不到形参接收了,就会被销毁。
函数的调用方式分为传址调用和传值调用
对于传值调用: 当调用函数时,传给函数一个数值,形参接收值
需要注意的是:
调用函数时,将实参的数值,传给形参,只是将数值传过去了,相当于拷贝了实参的值
形参和实参都占有不同的内存块,内存地址不一样。
在这里可以说,形参是实参的一份临时拷贝,对形参的修改不会影响到实参,不会影响实参里面的值。
举个例子:
创建一个自定义函数,用来实现交换两个变量的值。
此时,我们可以看到,a和b里面的值,并没有进行交换,a和b作为实参,将值传给了形参,形参对值进行修改,并未影响到实参,没有对实参进行修改。并且可以看到内存地址不一样。
对于传址调用:
当调用函数时,实参此时作为变量的内存地址,传给函数,形参作为指针变量接收地址。
通过地址,可以找到函数体外的变量,直接进行修改。
举个例子
创建一个函数,使两个变量的值完成交换。
可以看到,完成了交换,将a和b的地址传给了c和d,通过解引用操作符找到了a和b,实现了对实参的修改,不再是对形参进行修改。
可以帮助理解传值和传址两种调用方式
- 写一个函数可以判断100-200之间哪个是素数。
- 写一个函数判断1000-2000哪一年是闰年。
- 写一个函数,实现一个整形有序数组的二分查找。
- 写一个函数,每调用一次这个函数,就会将 num 的值增加1。
第一题:判断素数
先写简单版本
#includeint main() { // 1.先产生100-200的数 int i = 0; for (i = 100;i <= 200;i++) { //2.对进来的每一个数进行判断,产生2-(i-1)的数 int z = 2; for (z = 2;z <= i - 1;z++) { //3.进行判断 if (i % z == 0) { // 如果不是素数,直接跳出循环 break; } } //4. 当2-(i-1)遍历完之后,和执行break跳出循环之后,都会来到这一步,所以进行判断是哪一种情况。 if (z == i) { // 2-(i-1)遍历完之后,for的条件比循环体多执行一次,z会加到i printf("%dn", i); } } return 0; }
下面是升级版本,使用函数进行判断
#includeint is_prime(int i) { int z = 2; for (z = 2;z <= i - 1;z++) { //3.进行判断 if (i % z == 0) { // 如果不是素数,直接返回,返回值,返回值是0; return 0; } } //4. 当2-(i-1)遍历完之后,和执行break跳出循环之后,都会来到这一步,所以进行判断是哪一种情况。 if (z == i) { // 5. 2-(i-1)遍历完之后,for的条件比循环体多执行一次,z会加到i // 直接返回1. return 1; } } int main() { // 1.先产生100-200的数 int i = 0; for (i = 100;i <= 200;i++) { //2.对进来的每一个数进行判断,调用函数进行判断, int ret = is_prime(i); //6.对返回的值,进行判断 if (ret == 1) { printf("%dn", i); } } return 0; }
第一题答案:
第二题:判断1000-2000哪一个年份是闰年
先写简单版本
#includeint main() { int z = 0; int count = 0; // 1.产生1000-2000的数 for (z = 1000;z <= 2000;z++) { //2.对进来的数,进行判断 //3.不可使用if-else if 进行判断,if-else if 语句只能对进来的数判断一次,而一个数需要判断两次,因为有两个条件。 if (z % 4 == 0 && z % 100 != 0) { printf("%dn", z); count++; } if (z % 400 == 0) { printf("%dn", z); count++; } } printf("%d", count); return 0; }
下面是升级版本,使用函数判断数
#includeint is_leap_year(int z) { //3.不可使用if-else if 进行判断,if-else if 语句只能对进来的数判断一次,而一个数需要判断两次,因为有两个条件。 if (z % 4 == 0 && z % 100 != 0) { //4.满足条件,直接返回1; return 1; } if (z % 400 == 0) { return 1; } } int main() { int z = 0; int count = 0; // 1.产生1000-2000的数 for (z = 1000;z <= 2000;z++) { //2.对进来的数,使用函数进行判断 int ret = is_leap_year(z); //5.对返回值进行判断,看看函数告诉了我们什么。 if (ret == 1) { printf("%dn", z); count++; } } printf("%d", count); return 0; }
第二题答案:
第三题:实现一个整形有序数组的二分查找
先写简单版本
#includeint main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int z = 8; // 数一下,数组里面有多少个元素 int sz = sizeof(arr) / sizeof(arr[0]); // 根据数组元素的下标找到元素 int left = 0; // 元素个数减一,是最右边元素的下标 int right = sz - 1; // 1.开始对数进行判断 // 2.进行循环判断,直到找到,退出循环,或者遍历完,没有找到,退出循环 while (left <= right) { // 3.对于条件是如何选择的:二分查找是通过确定范围,来确定中间值的, //当范围存在时,就代表还有数据没有遍历完。直到范围不存在了,就代表数据没有了。 //当范围存在时,范围的左下标就会小于等于右下标。 int mid = (right - left) / 2 + left; if (arr[mid] == z) { printf("找到了,下标是:%d", mid); break; } else if (arr[mid] < z) { left = mid + 1; } else if (arr[mid] > z) { right = mid - 1; } } return 0; }
下面是升级版本
#includeint game(int z,int arr[10],int sz ) { int left = 0; int right = sz - 1; while (left <= right) { // 2.进行循环判断,直到找到,返回下标的值,或者遍历完,没有找到,返回-1 // 3.对于条件是如何选择的:二分查找是通过确定范围,来确定中间值的, //当范围存在时,就代表还有数据没有遍历完。直到范围不存在了,就代表数据没有了。 //当范围存在时,范围的左下标就会小于等于右下标。 int mid = (right - left) / 2 + left; if (arr[mid] == z) { return mid; } else if (arr[mid] < z) { left = mid + 1; } else if (arr[mid] > z) { right = mid - 1; } } return -1; } int main() { int arr[10] = { 1,2,3,4,5,6,7,8,9,10 }; int z = 8; // 数一下,数组里面有多少个元素 int sz = sizeof(arr) / sizeof(arr[0]); // 根据数组元素的下标找到元素 int left = 0; // 元素个数减一,是最右边元素的下标 int right = sz - 1; // 1.创建一个函数.开始对数进行判断 int ret = game(z,arr,sz); // 4.根据返回值,来得到函数的信息 if(ret != -1) { printf("找到了,下标是:%d", ret); } return 0; }
第三题答案:
第四题:写一个函数,每调用一次这个函数,就会将 num 的值增加1。
#include6、函数的嵌套game(int* Pcount) { *Pcount = *Pcount + 1; } int main() { int count = 0; int input = 0; for (input = 1;input <= 5;input++) { game(&count); } printf("%d", count); return 0; }
函数可以嵌套调用,但是不能嵌套定义
函数与函数之间是平等的,不能在一个函数体里面定义一个函数。
一个函数的返回值作为另一个函数的参数
printf("%d",printf("%d",printf("%d",43));
分析步骤:
首先,由外向内
最外层的函数,要打印一个整数类型的参数,值是次外层函数的返回值,
要得到次外层函数的返回值,要调用次外层函数。
次外层函数也要打印一个整数类型的参数,值是最内层函数的返回值,
要得到最内层函数的返回值,要先调用最内层函数。
最内层函数要打印一个整数类型的参数,参数是43。
最后,由内向外
返回值是在控制台输出的字符的个数。
最内层函数调用完成,在控制台打印参数,参数是43,在控制台打印43。
43是两个字符组成,所以返回值是2,
最内层函数的返回值2,作为次外层函数的参数,
次外层函数调用完成,在控制台打印参数,参数是2,在控制台打印2。
2是由一个字符组成,所以返回值是1,
次外层函数的返回值1,作为最外层函数的参数,
最外层函数调用完成,在控制台打印参数,参数是1,在控制台打印1。
希望能给看到这篇文章的小伙伴带来一些帮助
送给各位一句名言:欲戴皇冠,必承其重!



