函数
函数的定义是子程序,是一个大型程序中的某部分代码,由一个或多个语句块组成,它负责完成某项特定任务,而且相对于其他代码,函数具有相对独立性。
函数分为自定义函数和库函数。库函数是C语言本身提供给我们的函数,一般是大量的普遍的使用,由C语言统一提供可以大大减轻代码书写的负担,也便于代码的可读性。自定义函数是我们想实现不同的功能模块的时候自己定义的函数,不具有统一性。
需要掌握一些基本的库函数的使用,要学会查看库函数的文档,链接:
cplusplus.com/reference/cstdio/printf/
std::basic_string - cppreference.com (C语言中文参考手册)
英文还是很重要,不然连参考手册都看不明白
函数的组成:
其中:ret_type是返回类型,fun_name是函数名, para1是函数参数
statement交代了函数的实现
我们尝试封装一个Swap函数,它的作用是交换两个整型变量的值,但是在实际操作的过程中发现这么编写不能达到目的:
分析原因,虽然我们在函数内部对传入的两个值进行了交换,但是我们实际改变的是x和y的值,他们和ab并不是存储在同一位置,因此ab的值并没有得到交换。实际运行结果如下:
解决方法是使用指针,我们重新写一个函数Swap2,传入a和b的地址作为指针变量,这样我们在函数内部对两个指针指向的值进行交换就等于对ab的值进行了交换:
运行结果就对了:
函数的参数
实际参数(实参)
真实传递给函数的参数,叫实参,实参可以是:常量、变量、表达式
函数等。无论实参是何种类型的量,在进行函数调用时,他们都必须由确定的值,以便把这些值传送给形参。
形式参数(形参)
形式上的参数,形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化,所以叫形式参数。形式参数当函数调用完成之后就会自动销毁了。因此形参只在函数中有效。
例如我们上面实现的交换两个变量的值,第一个写法失败的原因:当实参传递给形参的时候,形参实际上时实参的一份临时拷贝,对形参的修改时不会改变实参的。
函数的调用
传值调用
我们上例中的Swap函数就是传值调用,将ab的值传递到函数中。
传址调用
在上例的Swap函数用的就是传址调用,因为此时我们需要在自定义函数中操作主函数中的变量,将ab的地址作为参数传到函数中。
练习
- 写一个函数可以判断一个数是不是素数,调用函数输出100-200之间的素数.
- 写一个函数判断一年是不是闰年,打印1000-2000之间的闰年
- 写一个函数,实现一个整型有序数组的二分查找
- 写一个函数,每调用一次这个函数,就会将num的值增加1
第一题:
运行结果:
我在做这道题的时候想在循环和判断中返回值,结果出现了一个警告:
查了一下,如果要在if分支中return值的话,那么每一个分支都应该给一个返回值,但是这里具体怎么改我没有头绪,用了一个flag变量记录结果最后统一 return。
补:或许可以这样改:
第二题:
运行结果:
思考:函数在定义的时候要单一干净,具有可复用性,不要乱返回或者打印输出一些东西。
第三题:
写出bug了:
运行结果是错误的:
错的原因是函数传值的时候我们传入了数组arr[],我误以为传到binary_search函数中的是整个数组,其实不是,我们这里传进去的只有数组第一个元素的地址,这么设计是为了降低存储空间的浪费。因此int binary_search(int arr[],int x)里面的这个arr[]其实是指针,从而我计算数组长度的方式就错了。
解决方法,我们先在主函数中求出数组元素个数,再传给函数就不会出错了。
这样一改就对了:
运行结果:
第四题:
比较简单,唯一需要注意的是++的优先级要大于解引用操作符*,因此我们需要给*p用()括起来:
运行结果: