浅谈函数相关知识点整理(一)
一、函数的概念定义
1、,函数就是 C 语言的模块,一块一块的,有较强的独立性,可以相互调用,换句话说,C 语言中,一个函数里面可以调用 n 个函数,即大函数调用小函数,小函数又调用“小小”函数。这就是结构化程序设计,所以面向过程的语言又叫结构化语言。
2、,函数就是一系列 C 语句的集合,能完成某个特定的功能。需要该功能的时候直接调用该函数即可,不用每次都堆叠代码。需要修改该功能时,也只需要修改和维护这一个函数即可
二、函数的格式和声明定义
格式定义:

1、函数的定义包含一个函数头(function head,或称为声明符(declarator))和一个函数块。函数头指定了函数的名称、返回值的类型以及参数的类型和名称(如果有参数的话)。函数块中的语句明确了该函数要做的事。函数定义的一般格式如下所示:
在上述格式的函数头中,“名称”指函数名,而“类型”包含至少一个类型修饰符,用来定义函数返回值的类型。返回值的类型可以是 void 或者任何对象类型,但不可以是数组类型。而且,类型部分还可以包含函数修饰符 inline 或 _Noreturn,以及存储类修饰符 extern 和 static。
2、函数无法返回函数或数组。然而,可以定义一个函数的返回值为指针,并将该指针指向一个函数或数组。
在上述格式中,“参数声明”是一个以逗号分隔、由函数参数声明组成的列表。如果该函数没有参数需要传入,则这个列表为空,或者仅有关键字 void。
3、函数类型不仅指定了其返回值的类型,也指定了其所有参数的类型
4、每个函数都只能被定义一次。但一个函数可以根据需要被多次的声明和调用。
声明定义:
1、C语言代码由上到下依次执行,原则上函数定义要出现在函数调用之前,否则就会报错。但在实际开发中,经常会在函数定义之前使用它们,这个时候就需要提前声明。
2、所谓声明(Declaration),就是告诉编译器我要使用这个函数,你现在没有找到它的定义不要紧,请不要报错,稍后我会把定义补上。
3、函数声明的格式非常简单,相当于去掉函数定义中的函数体,并在最后加上分号;,如下所示:
dataType functionName( dataType1 param1, dataType2 param2 ... );
也可以不写形参,只写数据类型:
dataType functionName( dataType1, dataType2 ... );
函数声明给出了函数名、返回值类型、参数列表(重点是参数类型)等与该函数有关的信息,称为函数原型(Function Prototype)。函数原型的作用是告诉编译器与该函数有关的信息,让编译器知道函数的存在,以及存在的形式,即使函数暂时没有定义,编译器也知道如何使用它。
4、有了函数声明,函数定义就可以出现在任何地方了,甚至是其他文件、静态链接库、动态链接库等;
5、实例:

6、初学者编写的代码都比较简单,顶多几百行,完全可以放在一个源文件中。对于单个源文件的程序,通常是将函数定义放到 main() 的后面,将函数声明放到 main() 的前面,这样就使得代码结构清晰明了,主次分明。
使用者往往只关心函数的功能和函数的调用形式,很少关心函数的实现细节,将函数定义放在最后,就是尽量屏蔽不重要的信息,凸显关键的信息。将函数声明放到 main() 的前面,在定义函数时也不用关注它们的调用顺序了,哪个函数先定义,哪个函数后定义,都无所谓了。
然而在实际开发中,往往都是几千行、上万行、百万行的代码,将这些代码都放在一个源文件中简直是灾难,不但检索麻烦,而且打开文件也很慢,所以必须将这些代码分散到多个文件中。对于多个文件的程序,通常是将函数定义放到源文件(.c文件)中,将函数的声明放到头文件(.h文件)中,使用函数时引入对应的头文件就可以,编译器会在链接阶段找到函数体。
7、我们在使用 printf()、puts()、scanf() 等函数时引入了 stdio.h 头文件,很多初学者认为 stdio.h 中包含了函数定义(也就是函数体),只要有了头文件就能运行,其实不然,头文件中包含的都是函数声明,而不是函数定义,函数定义都放在了其它的源文件中,这些源文件已经提前编译好了,并以动态链接库或者静态链接库的形式存在,只有头文件没有系统库的话,在链接阶段就会报错,程序根本不能运行。

三、使用函数的目的
1、代码重用:将语句集合成函数的好处是方便代码重用。所谓“重用”,是指有一些代码的功能是相同的,操作是一样的,只不过针对的数据不一样,这时就可以将这种功能写成一个函数模块,以后用到这个功能时只需要调用这个函数模块就可以了,不需要再重复地编写同样的代码。这样可以解决大量同类型的问题,避免重复性操作。
2、便于代码维护:将语句集合成函数方便代码的维护。哪个功能出问题,或者需要修改某个功能,那就只需要修改某个功能的函数就可以了。所以,函数有利于程序的模块化。这实际上就是面向过程的思想。面向过程语言最基本的单位不是语句,而是函数。
函数的分类:

四、函数的形参和实参
1、形参和实参的定义:
C语言函数的参数会出现在两个地方,分别是函数定义处和函数调用处,这两个地方的参数是有区别的。
形参(形式参数)
在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为形式参数,简称形参。
实参(实际参数)
函数被调用时给出的参数包含了实实在在的数据,会被函数内部的代码使用,所以称为实际参数,简称实参。
形参和实参的功能是传递数据,发生函数调用时,实参的值会传递给形参,且只能单向传递;
2、形参与实参不同点:
1) 形参变量只有在函数被调用时才会分配内存,调用结束后,立刻释放内存,所以形参变量只有在函数内部有效,不能在函数外部使用。
2) 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的数据,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参,所以应该提前用赋值、输入等办法使实参获得确定值。
3) 实参和形参在数量上、类型上、顺序上必须严格一致,否则会发生“类型不匹配”的错误。当然,如果能够进行自动类型转换,或者进行了强制类型转换,那么实参类型也可以不同于形参类型。
4) 函数调用中发生的数据传递是单向的,只能把实参的值传递给形参,而不能把形参的值反向地传递给实参;换句话说,一旦完成数据的传递,实参和形参就再也没有瓜葛了,所以,在函数调用过程中,形参的值发生改变并不会影响实参。
实例:

五、函数的返回值
1、如果把函数比喻成一台机器,那么参数就是原材料,返回值就是最终产品;从一定程度上讲,函数的作用就是根据不同的参数产生不同的返回值。
2、函数的返回值是指函数被调用之后,执行函数体中的代码所得到的结果,这个结果通过 return 语句返回;
return 语句的一般形式为:
return 表达式;
或者
return (表达式);
注意:有没有()都是正确的,为了简明,一般也不写();
3、返回值类型说明:
3.1、没有返回值的函数为空类型,用 void 表示;

注意:一旦函数的返回值类型被定义为 void,就不能再接收它的值了。
例如,下面的语句是错误的:
int a = func(); ---->错误写法
3.2、return 语句可以有多个,可以出现在函数体的任意位置,但是每次调用函数只能有一个 return 语句被执行,所以只有一个返回值
实例:

3.3、函数一旦遇到 return 语句就立即返回,后面的所有语句都不会被执行到了。从这个角度看,return 语句还有强制结束函数执行的作用;
实例:

注意:
return 语句是提前结束函数的唯一办法。return 后面可以跟一份数据,表示将这份数据返回到函数外面;当返回值是 void时return 后面也可以不跟任何数据,表示什么也不返回,仅仅用来结束函数,直接写分号即可;
五、全局变量、局部变量、块级变量 的作用域
C语言中所有的变量都有自己的作用域。决定变量作用域的是变量的定义位置;所谓作用域(Scope),就是变量的有效范围
1、定义:
全局变量:
在所有函数外部定义的变量称为全局变量(Global Variable),它的作用域默认是整个程序,也就是所有的源文件,包括 .c 和 .h 文件,如果给全局变量加上 static 关键字,它的作用域就变成了当前文件,在其它文件中就无效了
实例:

局部变量:
定义在函数内部的变量称为局部变量(Local Variable),它的作用域仅限于函数内部, 离开该函数后就是无效的,再使用就会报错;
实例:

块级变量
C语言允许在代码块内部定义变量,这样的变量具有块级作用域;换句话说,在代码块内部定义的变量只能在代码块内部使用,出了代码块就无效了,所谓代码块,就是由{ }包围起来的代码。代码块在C语言中随处可见,例如函数体、选择结构、循环结构等。不包含代码块的C语言程序根本不能运行;
实例:

2、注意事项:
1) 在 main 函数中定义的变量也是局部变量,只能在 main 函数中使用;同时,main 函数中也不能使用其它函数中定义的变量。main 函数也是一个函数,与其它函数地位平等。
2) 形参变量、在函数体内定义的变量都是局部变量。实参给形参传值的过程也就是给局部变量赋值的过程。
3) 可以在不同的函数中使用相同的变量名,它们表示不同的数据,分配不同的内存,互不干扰,也不会发生混淆。
4) 在语句块中也可定义变量,它的作用域只限于当前语句块。
5) 当全局变量和局部变量同名时,在局部范围内全局变量被“屏蔽”,不再起作用。或者说,变量的使用遵循就近原则,如果在当前作用域中存在同名变量,就不会向更大的作用域中去寻找变量。
6) 由{ }包围的代码块也拥有独立的作用域。
7) C语言规定,只能从小的作用域向大的作用域中去寻找变量,而不能反过来,使用更小的作用域中的变量。对于 main() 函数,即使代码块中的 n 离输出语句更近,但它仍然会使用 main() 函数开头定义的 n,所以输出结果是 30
8)在一个函数内部修改全局变量的值会影响其它函数,全局变量的值在函数内部被修改后并不会自动恢复,它会一直保留该值,直到下次被修改。
综合实例重点说明:


运行结果:
func1 n: 20
func2 n: 30
func3 n: 10
block n: 40
main n: 30
六、函数调用
1、函数调用形式:
所谓函数调用(Function Call),就是使用已经定义好的函数。
函数调用的一般形式为:
functionName(param1, param2, param3 ...);
functionName 是函数名称,param1, param2, param3...是实参列表。实参可以是常数、变量、表达式等,多个实参用逗号,分隔
示例:
有参函数调用:
函数名(实参表)
无参函数调用
函数名()


2、函数调用的方式:

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
