大家好啊,本期和大家分享C语言函数相关知识。
1.函数的概念
我们早在数学中就接触过函数,比如:一次函数y=ax+b,a、b都是常数,给定任意一个x就可以得到y。在C语言中也引入函数(function)概念,更准确的翻译应该为:子程序。C语言中函数就是完成某一特定功能的一段代码。
一个大的任务可以分成许多窖小的函数完成。如果一个函数能完成某项特定的任务的话,这个函数是可以复用的,提升了软件的开发效率。
C语言函数分为两类:
- 库函数
- 自定义函数
1.1库函数
1.1.1标准库和头文件
C语言的国际标准ANSI C规定了一些常用的函数的标准,被称为标准库,不同的编译器厂商根据ANSI C提供的C语言标准给出了一系列函数的实现,这些函数被称为库函数。C语言并不提供库函数,它规定了C语言的各种语法规则。
我们在前文中学到的printf和scanf都是库函数,库函数也是函数,不过这些都是现成的,可以直接使用,一些常见的功能就不需要程序猿自己实现了,一定程度上提高了效率。
各种编译器的标准库中提供了一系列的库函数,这些函数根据功能的划分,都在不同的头文件中进行了声明。
库函数相关头文件可以访问c/c++官方链接查找:https://zh.cppreference.com/w/c/header
1.1.2库函数使用举例
例如:sqrt()函数,它的作用是计算平方根。使用它要包含math.h头文件,代码如下:
运行结果:
1.2自定义函数
了解了库函数,现在我们聚焦到自定义函数,自定义函数其实更加重要,也能给程序猿写代码更多的创造性。
1.2.1自定义函数语法
自定义函数语法形式如下:
我们可以把函数想象成一个工厂,工厂得输入原料,经过工厂加工生产出产品。函数也是一样,函数一般会输入一些值(可以是0个也可以是多个),经过函数计算得出结果。
函数返回类型可以是int、char,也可以是void(什么都不返回),可以理解为工厂加工后的产品类型。
函数名就是为了我们方便调用函数而起的名字,名字尽量有意义,方便调用。
形式参数相当于送进工厂中的原料,函数的参数也可以是void,表示函数没有参数。如果有要表明参数的类型和个数。
函数体就是函数的计算过程,相当于工厂的加工过程。
1.2.2自定义函数举例
例如:写一个乘法函数,用来计算两个整型变量的乘法。代码如下:
运行结果:
根据我们要完成的功能,给函数取名ride,函数ride需要接受两个整型的参数,函数计算结果也是整型。未来我们可以根据需要设计函数,函数名、参数、返回类型都是可以灵活多变的。
2.形参和实参
在函数的使用过程中,把函数的参数分为实参和形参。看下我们前面写的代码:
第5~8行是ride函数的定义,有了函数后,在第13行调用。
2.1实参
我们把第13行调用ride函数时,传递给函数的参数x和y称为实际参数,简称实参。
实际参数就是真实传递给函数的参数。
2.2形参
在上面代码第五行定义函数的时候,函数名ride后的括号中的x和y,称为形式参数,简称形参。
为什么叫形参呢?事实上,如果只定义ride函数,而不调用的话,ride函数的参数x和y只是形式上存在,不会向内存申请空间,也就是不是真实存在,所以叫形式参数。
形式参数只有在函数被调用的过程中为了存放实参传递过来的值,才会向内存申请空间,这个过程就是形参的实例化。
2.3形参和实参的关系
实参是传递给形参的,二者是有联系的,但形参和实参各自是独立的空间。我们可以通过对上面代码调试来观察:
&是取地址符,可以查看变量地址。从调试结果我们可以观察到,x和y确实得到了a和b的值,但是和a、b地址不同,所以我们可以理解为形参是实参的一份临时拷贝。由于二者不是同一块内存空间,名字也可以相同,对形参的修改也不会影响实参。
例如我们将上面代码中的x、y改成a、b:
结果依然正确:
3.return语句
函数的设计中经常会出现return语句,比如上面例子中的return x*y,作用就是返回x*y的值。以下是使用return语句的注意事项:
- return后面可以是一个数值,也可以是一个表达式,如果是表达式则先执行表达式,再返回表达式结果。
- return 后面可以什么也没有,这种写法适合函数返回类型是void的情况。
- return执行后,函数就彻底返回,后面的代码不再执行。
- 如果return返回的值和函数返回类型不一致,系统会自动将返回值转换为函数返回类型
- 如果函数中存在分支语句,则要保证每种情况下都有return返回,否则会出现编译错误。
- 如果没写函数返回类型,编译器会默认返回类型是int。
- 函数写了返回类型,但没有使用return返回值,那么函数的返回值是未知的。
4.数组做函数参数
在使用函数时,有时会将数组作为参数传递给函数,在函数内部进行操作。比如:写下一个函数将一个数组的内容全部置为0,再写一个函数打印数组。这里我们先来了解一些数组传参的知识:
- 函数的形参要和实参个数匹配。
- 函数的实参是数组,形参也要写成数组。
- 形参如果是一维数组,数组大小可以省略。
- 形参如果是二维数组,行可以省略,但列不能。
- 数组传参,形参不会创建新数组。
- 形参操作的数组和实参操作的数组是同一个。
我们可以考虑到代码基本形式应该是这样的:
modify_arr函数能够对数组内容修改,就得把数组作为参数传递给函数,同时能够遍历数组,对每个值进行修改,还要把数组元素个数作为参数传递给modify_arr。printf_arr也是如此,既要传递数组,也要传递数字元素个数。
这样,传参的问题解决了,那这两个函数要如何设计呢?我们可以使用for循环遍历数组:
这样便完成了对modify_arr函数和printf_arr函数的编写,代码整体以及运行结果如下:
5.嵌套调用和链式访问
5.1嵌套调用
顾名思义,嵌套调用就是函数间的相互调用,每个函数就像一个零件,正式由许多个零件精密配合才能做出完美的仪器,正是函数间有效的相互调用,最后写成一个大型程序。
举个栗子:输入年月,计算这一年这一月的天数。我们可以设计两个函数,count_year();根据输入年份确定是否是闰年,count_month();调用count_year();确定是否为闰年后,再计算这个月天数。分析完毕,代码如下:
代码运行,我们输入2033 3,运行结果:
这样这段代码就完成了。请注意:函数之间可以嵌套调用,但是函数不能嵌套定义。
5.2链式访问
所谓链式访问就是将一个函数的返回值作为拎一个函数的参数,像链条一样将函数串起来就是函数的链式访问。
举个栗子:前面我们提到了sqrt()函数,我们可以将它和printf函数一起使用:
运行结果:
再来看一个更有意思的,下面这段代码运行结果是什么呢?
要想弄明白关键在于printf函数返回的是什么,事实上printf函数返回的是打印字符的个数。
上面这个例子,第三个printf打印43,在屏幕上打印两个字符,返回2;第二个printf打印2,返回1;第一个printf打印1.
所以屏幕上最终打印:
6.函数的声明和定义
6.1单文件中函数声明和定义
一般我们在使用函数的时候,直接将函数写出然后调用。例如下面这段代码,判断是否是闰年:
43~53行是函数定义,59行是函数调用。这种是函数定义在调用前,没啥问题,如果我们将函数定义放在调用后呢?
编译代码,会报错:
这是因为C语言编译器对源代码进行编译时,从第一行向下扫描,但遇到第49行函数调用时,没有发现前面有count_year的定义,所以会报错。我们只要在调用前声明一下就可以了,如void count_year(int year);这就是函数声明。代码变成这样就可以正常编译了:
函数的调用一定要满足,先声明后使用。函数的定义也是一种特殊的声明,如果函数定义在调用前也是可以的。
6.2多个文件中函数声明和定义
如果在实际工作中,代码可能会很多,一般不会把所有代码放一个文件中,而是将函数的声明、类型的声明放在头文件(.h)中,函数的实现放在源文件(.c)中。
例如5.1求某年某月的天数问题,我们可以将定义、声明、调用分开:
这是将count_month();函数和count_year();函数在头文件count.h中声明。
这是将函数的实现(函数主体)放在count.c文件中。
在test.c中对函数调用。
有了对函数声明和定义的理解,我们写代码就更加清晰、方便了。
结语
让大家久等啦,本期我们学习了函数的相关知识,如果有任何需要修改或补充,请即时告诉我。
如果我的文章对您有帮助的话,不妨点个免费的赞和关注叭,以后我也会更加努力更新!!!感谢大家阅读。
标签:调用,函数,形参,代码,基础知识,学习,数组,实参,C语言 From: https://blog.csdn.net/Zhang886674/article/details/143335434