函数
本文将表述函数声明及使用的相关知识点。
函数概述
在C语言中,子程序的作用是由函数完成的。一个C程序可由一个主函数和若干个其它函数构成,并且只能有一个主函数。由主函数来调用其他函数,其他子函数之间也可以相互调用。
C程序的执行总是从main()函数开始。调用其他函数完毕后,程序流程回到main()函数,继续执行主函数中其他语句,直到main()函数结束,则整个程序的运行结束。
从用户使用的角度函数分为:
● 标准函数(库函数)
● 自定义函数
● 无参函数
● 有参函数
说明:
●库函数: C语言自带的函数
●库: 函数集合
●参数: 函数括号内包含的数据或变量
无参函数的定义
如果函数不接收用户传递的数据,那么这时可不带参数,即使用无参函数,如下:
1 | dataType functionName(){ |
●dataType为返回值类型,可以为任意数据类型。
●functionName是函数名,是标识符的一种。
●body是函数体,由花括号包围。
●若有返回值须在函数体内使用return语句返回,返回值数据类型须与dataType一致。
无返回值函数
若函数不需要返回值,或返回值类型不确定则定义无返回值函数,如下:
1 | void hello(){ |
有参函数的定义
如果函数需要接收用户传递的数据,那么定义时就要带上参数,即定义有参函数,如下:
1 | dataType functionName(dataType param1,dataType2 param2 ...){ |
●有参函数可以有一个或多个参数,之间用”,”分隔。参数的本质上也是变量,定义时要指明类型和名称。
函数参数和函数返回值
形式参数和实际参数
●在定义函数时,函数名后面括号中的变量称为”形式参数”(简称”形参”)
●在主调函数中,函数名后面括号中的参数(可以是一个表达式)称为”实际参数”(简称”实参”)
函数的返回值
1.定义:函数的返回值就是通过函数调用使主调函数能得到一个确定的值。
2.表达形式:
return 表达式;
reutrn (表达式);
return;
3.说明:
return语句中的表达式值的类型必须与函数首部所说明的一致。若类型不一致,则以函数值的类型为准,由系统自动进行强制转换。
当函数没有指明返回值,或没有返回语句时,函数返回了一个不确定的值。为了使函数不返回任何值,可以使用void定义函数。
形参与实参的区别和联系
①形参变量只有在函数被调用时才会分配内存,调用结束后,立刻释放内存,所以形参变量只有在函数内部有效,不能在函数外部使用。
②实参可以是常量、变量、表达式、函数等,无论实参是何种类型的数据,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参,所以应该提前用赋值,输入等办法使实参获得确定值。
③实参和形参在数量上、类型上、顺序上必须严格一致,否则会发生”类型不匹配”的错误。当然,如果能够进行自动类型转换,或者进行了强制类型转换,那么实参类型也可不同于形参类型。
④函数调用中发生的数据传递是单向的,只能把实参的值传给形参,而不能把形参的值反向地传给实参。换句话说,一旦完成了数据传递,实参与形参就无关了,即在函数调用过程中,形参的改变不会影响实参。
函数的调用
一般形式: 函数名(实参表列)
函数的调用可分为 无参函数 和 有参函数两种:
● 调用无参函数,不用”实参表列”,但括号不能省略。
● 调用有参函数,各参数间用逗号隔开,其实参与形参类型一致。
所谓调用(Function Call)就是使用已定义好的函数。
函数的嵌套调用
函数不能嵌套定义,但可用嵌套调用,也就是一个函数的定义或调用过程中允许出现另外一个函数的调用。
函数的声明以及函数原型
C语言中,除了主函数外,对于用户定义的函数要遵循先定义后使用的规则。把函数的定义放在调用之后,应该在调用之前对函数进行说明(或函数原型说明)(声明 Declaration)
函数声明一般形式如下:
dataType functionName(dataType1 param1, dataType2 param2 …);
或
dataType functionName(dataType1, dataType2…);
函数声明的格式相当于去掉函数定义中的函数体,并在最后加上分号;
函数声明给出了函数名、返回值类型、参数列表(重点是参数类型)等与该函数有关的信息,又称 函数原型(Function Prototype)。函数声明的作用是告诉编译器与该函数有关的信息,让编译器知道函数的存在及存在形式,即使函数暂时没有定义,编译器也知道如何使用它。
函数的嵌套调用与递归调用
函数的嵌套调用
C语言的函数定义都是独立的,互相平行的,C语句不允许嵌套定义函数,即一个函数内不能定义另一个函数。但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。
函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
使用递归法解决问题,须符合的条件:
● 可以把要解决的问题转化为一个新的问题,而这个新的问题的解决方法仍与原来的解决方法相同,只是所处理的对象有规律地递增或递减。
● 可以应用这个转化过程使问题得到解决,必须有一个明确的结束递归的条件。
数组作为函数参数
数组元素作为函数实参
数组元素可以作为函数的实参,与用变量作为实参一样,按照单向值传递的方式进行传递。
数组名可以作为函数参数
可以用数组名作为函数的参数,此时实参与形参都应用数组名,数组名是整个数组的首地址。
全局变量和局部变量
在函数内部定义的变量称为局部变量,只能在本函数内部使用。
在函数之外定义的变量称为外部变量,也即全局变量,可为本文件中其他函数所共用,他的有效范围从定义变量开始到本文件结束。
如果在同一个源文件中,全局变量与局部变量同名,则在局部变量的作用范围内,外部变量被”屏蔽”,即不起作用。
变量的作用域
所谓 作用域(scope) 就是变量的有效范围,就是变量可以在哪个范围内使用,有些变量只能在一定范围内使用,超出范围就失效了。
变量的作用域由变量的定义位置决定,在不同位置定义的变量,其作用域不同。
块级变量
即由{}包围起来的代码中的变量定义,这样的变量具有块级作用域。
每个C语言程序都包含了许多作用域,不同的作用域中可以出现同名的变量,C语言会按照从小到大的顺序,一层一层地去父级作用域中查找变量,如果在最顶层的全局作用域中还未找到这个变量,那么就会报错。
变量的存储类别
auto变量
当在函数内部或复合语句内定义变量时,如果没有指定存储类别,或使用了auto说明符,系统就认为所定义的变量具有自动类别。
register变量
寄存器变量也是自动类变量。它与auto变量的区别仅在于:用register说明变量是建议编译程序将变量的值保留在CPU的寄存器中,而不是像一般变量那样占用内存单元。
局部static变量
当函数体(或复合语句)内部用static来说明一个变量时,可以称该变量为静态局部变量。
它与auto变量,register变量的本质区别是:
①在整个程序运行期间、静态局部变量在内存中的静态存储区中占据着永久性的存储单元。即使退出函数后,下次再进入该函数时,静态局部变量仍使用原来的存储单元。由于不释放这些存储单元,这些存储单元中的值得以保留,因而可以继续使用存储单元中原来的值。
②静态局部变量的初值是在编译时赋予的,在程序执行期间不再赋以初值。对未赋值的局部变量,C语言编译程序自动给它赋初值为0。
版权声明
Scholar’s Blog by scholargeek is licensed under a Creative Commons BY-NC-ND 4.0 International License.
由董仕麟创作并维护的scholargeek博客采用创作共用保留署名-非商业-禁止演绎4.0国际许可证。
本文首发于Scholar’s Blog博客,版权所有,侵权必究。
本文永久链接:https://scholargeek.github.io/2018/02/12/C%E8%AF%AD%E8%A8%80%E5%AD%A6%E4%B9%A06/