C语言——函数
c源程序是由函数组成。函数是c源程序的基本模块,通过对函数模块的调用实现特定的功能。c语言中的函数相当于其它高级语言的子程序。c语言不仅提供了极为丰富的库函数(如turbo c,ms c 都提供了三百多个库函数),还允许用户建立自己定义的函数。c语言称为函数式语言。
一、在c语言中可从不同的角度对函数分类。
1. 从函数定义的角度看,函数可分为库函数和用户定义函数两种。
(1)库函数
(2)用户定义函数:必须对该被调函数进行类型说明,然后才能使用。
2. c语言的函数兼有其它语言中的函数和过程两种功能,从这个角度看,又可把函数分为有返回值函数和无返回值函数两种。
3. 从主调函数和被调函数之间数据传送的角度看又可分为无参函数和有参函数两种。
(1)无参函数:可以返回或不返回函数值。
(2)有参函数
4. c语言提供了极为丰富的库函数,这些库函数又可从功能角度作以下分类。
(1)字符类型分类函数
用于对字符按ascii码分类:字母,数字,控制字符,分隔符,大小写字母等。
(2)转换函数
用于字符或字符串的转换;在字符量和各类数字量 (整型,实型等)之间进行转换;在大、小写之间进行转换。
(3)目录路径函数
用于文件目录和路径操作。
(4)诊断函数
用于内部错误检测。
(5)图形函数
用于屏幕管理和各种图形功能。
(6)输入输出函数
用于完成输入输出功能。
(7)接口函数
用于与dos,bios和硬件的接口。
(8)字符串函数
用于字符串操作和处理。
(9)内存管理函数
用于内存管理。
(10)数学函数
用于数学函数计算。
(11)日期和时间函数
用于日期,时间转换操作。
(12)进程控制函数
用于进程管理和控制。
(13)其它函数
用于其它各种功能。
二、在一个函数的函数体内,不能再定义另一个函数,即不能嵌套定义。但是函数之间允许相互调用,也允许嵌套调用。习惯上把调用者称为主调函数。函数还可以自己调用自己,称为递归调用。main 函数是主函数,它可以调用其它函数,而不允许被其它函数调用。因此,c程序的执行总是从main函数开始,完成对其它函数的调用后再返回到main函数,最后由main函数结束整个程序。一个c源程序必须有,也只能有一个主函数main。函数的类型实际上是函数返回值的类型。有参函数比无参函数多了两个内容,其一是形式参数表,其二是形式参数类型说明。在形参表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔。函数定义、函数说明及函数调用函数说明与函数定义中的函数头部分相同,但是末尾要加分号。
以下几种方式调用函数:
1.函数表达式
2.函数语句
函数调用的一般形式加上分号即构成函数语句。例如: printf ("%d",a);scanf ("%d",&b); 都是以函数语句的方式调用函数。
3.函数实参
应特别注意的是,无论是从左至右求值, 还是自右至左求值,其输出顺序都是不变的, 即输出顺序总是和实参表中实参的顺序相同。函数的参数和函数的值发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
函数的形参和实参具有以下特点:
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。
3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。
4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
三、函数的值
函数的值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。
1. 函数的值只能通过return语句返回主调函数。return语句的一般形式为:
在函数中允许有多个return语句,但每次调用只能有一个return 语句被执行,因此只能返回一个函数值。
2. 函数值的类型和函数定义中函数的类型应保持一致。 如果两者不一致,则以函数类型为准,自动进行类型转换。
3. 如函数值为整型,在函数定义时可以省去类型说明。
4. 不返回函数值的函数,可以明确定义为“空类型”, 类型说明符为“void”。
四、c语言中又规定在以下几种情况时可以省去主调函数中对被调函数的函数说明。
1. 如果被调函数的返回值是整型或字符型时,可以不对被调函数作说明,而直接调用。这2. 当被调函数的函数定义出现在主调函数之前时,在主调函数中也可以不对被调函数再作说明而直接调用。
3.如在所有函数定义之前, 在函数外预先说明了各个函数的类型,则在以后的各主调函数中,可不再对被调函数作说明。
4. 对库函数的调用不需要再作说明, 但必须把该函数的头文件用include命令包含在源文件前部。
五、数组名作为函数参数
用数组名作函数参数与用数组元素作实参有几点不同:
1. 用数组元素作实参时,只要数组类型和函数的形参变量的类型一致,那么作为下标变量的数组元素的类型也和函数形参变量的类型是一致的。对数组元素的处理是按普通变量对待的。
2. 在普通变量或下标变量作函数参数时,形参变量和实参变量是由编译分配的两个不同的内存单元。在函数调用时发生的值传送是把实参变量的值赋予形参变量。实参数组的首地址赋予形参数组名。形参数组名取得该首地址之后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间。
3. 前面已经讨论过,在变量作函数参数时,所进行的值传送是单向的。即只能从实参传向形参,不能从形参传回实参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,两者的终值是不同的。例5.3证实了这个结论。而当用数组名作函数参数时,情况则不同。由于实际上形参和实参为同一数组,因此当形参数组发生变化时,实参数组也随之变化。当然这种情况不能理解为发生了“双向”的值传递。但从实际情况来看,调用函数之后实参数组的值将由于形参数组值的变化而变化。
从运行结果可以看出,数组b 的初值和终值是不同的,数组b 的终值和数组a是相同的。这说明实参形参为同一数组,它们的值同时得以改变。
用数组名作为函数参数时还应注意以下几点:
a. 形参数组和实参数组的类型必须一致,否则将引起错误。
b. 形参数组和实参数组的长度可以不相同,因为在调用时,只传送首地址而不检查形参数组的长度。当形参数组的长度与实参数组不一致时,虽不至于出现语法错误(编译能通过),但程序执行结果将与实际不符,这是应予以注意的。
函数的嵌套调用
六、c语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下一级函数的问题。但是c语言允许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用。即在被调函数中又调用其它函数。
函数的递归调用
一个函数在它的函数体内调用它自身称为递归调用。在递归调用中, 主调函数又是被调函数。形参变量只在被调用期间才分配内存单元,调用结束立即释放。
七、c语言中的变量,按作用域范围可分为两种,即局部变量和全局变量。
(一)局部变量
局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内,离开该函数后再使用这种变量是非法的。
关于局部变量的作用域还要说明以下几点:
1. 主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其它函数中定义的变量。因为主函数也是一个函数,它与其它函数是平行关系。这一点是与其它语言不同的,应予以注意。
2. 形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量。
3. 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆。
4. 在复合语句中也可定义变量,其作用域只在复合语句范围内。
(二)全局变量
全局变量也称为外部变量,它是在函数外部定义的变量。
只有在函数内经过说明的全局变量才能使用。全局变量的说明符为extern。但在一个函数之前定义的全局变量,在该函数内使用可不再加以说明。
对于全局变量还有以下几点说明:
1. 对于局部变量的定义和说明,可以不加区分。外部变量定义必须在所有的函数之外,且只能定义一次。其一般形式为: [extern] 类型说明符变量名,变量名…其中方括号内的extern可以省去不写。
2. 外部变量可加强函数模块之间的数据联系,但是又使函数要依赖这些变量,因而使得函数的独立性降低。从模块化程序设计的观点来看这是不利的,因此在不必要时尽量不要使用全局变量。
3. 在同一源文件中,允许全局变量和局部变量同名。在局部变量的作用域内,全局变量不起作用。
变量的存储类型各种变量的作用域不同,就其本质来说是因变量的存储类型相同。所谓存储类型是指变量占用内存空间的方式,也称为存储方式。
变量的存储方式可分为“静态存储”和“动态存储”两种。
静态存储变量是一直存在的, 而动态存储变量则时而存在时而消失。我们又把这种由于变量存储方式不同而产生的特性称变量的生存期。生存期表示了变量存在的时间。生存期和作用域是从时间和空间这两个不同的角度来描述变量的特性,这两者既有联系,又有区别。一个变量究竟属于哪一种存储方式,并不能仅从其作用域来判断,还应有明确的存储类型说明。
八、 在c语言中,对变量的存储类型说明有以下四种:
auto 自动变量
register 寄存器变量
extern 外部变量
static 静态变量
自动变量和寄存器变量属于动态存储方式, 外部变量和静态变量属于静态存储方式。 因此变量说明的完整形式应为: 存储类型说明符 数据类型说明符 变量名,变量名…; 例如:
static int a,b; 说明a,b为静态类型变量
auto char c1,c2; 说明c1,c2为自动字符变量
static int a[5]={1,2,3,4,5}; 说明a为静整型数组
extern int x,y; 说明x,y为外部整型变量
下面分别介绍以上四种存储类型:
(一)自动变量的类型说明符为auto。
这种存储类型是c语言程序中使用最广泛的一种类型。c语言规定,函数内凡未加存储类型说明的变量均视为自动变量,也就是说自动变量可省去说明符auto。
自动变量具有以下特点:
1. 自动变量的作用域仅限于定义该变量的个体内。
2. 自动变量属于动态存储方式,只有在使用它,即定义该变量的函数被调用时才给它分配存储单元,开始它的生存期。函数调用结束,释放存储单元,结束生存期。
3. 由于自动变量的作用域和生存期都局限于定义它的个体内( 函数或复合语句内),因此不同的个体中允许使用同名的变量而不会混淆。即使在函数内定义的自动变量也可与该函数内部的复合语句中定义的自动变量同名。
4. 对构造类型的自动变量如数组等,不可作初始化赋值。
(二)外部变量外部变量的类型说明符为extern。
1. 外部变量和全局变量是对同一类变量的两种不同角度的提法。全局变是是从它的作用域提出的,外部变量从它的存储方式提出的,表示了它的生存期。
2. 当一个源程序由若干个源文件组成时, 在一个源文件中定义的外部变量在其它的源文件中也有效。
(三)静态变量
静态变量的类型说明符是static。 静态变量当然是属于静态存储方式,但是属于静态存储方式的量不一定就是静态变量,例如外部变量虽属于静态存储方式,但不一定是静态变量,必须由 static加以定义后才能成为静态外部变量,或称静态全局变量。
1. 静态局部变量
在局部变量的说明前再加上static说明符就构成静态局部变量。
静态局部变量属于静态存储方式,它具有以下特点:
(1)静态局部变量在函数内定义,但不象自动变量那样,当调用时就存在,退出函数时就消失。静态局部变量始终存在着,也就是说它的生存期为整个源程序。
(2)静态局部变量的生存期虽然为整个源程序,但是其作用域仍与自动变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后,尽管该变量还继续存在,但不能使用它。
(3)允许对构造类静态局部量赋初值(4)对基本类型的静态局部变量若在说明时未赋以初值,则系统自动赋予0值。而对自动变量不赋初值,则其值是不定的。
2.静态全局变量
全局变量(外部变量)的说明之前再冠以static就构成了静态的全局变量。全局变量本身就是静态存储方式,静态全局变量当然也是静态存储方式。这两者在存储方式上并无不同。这两者的区别虽在于非静态全局变量的作用域是整个源程序,当一个源程序由多个源文件组成时,非静态的全局变量在各个源文件中都是有效的。而静态全局变量则限制了其作用域,即只在定义该变量的源文件内有效,在同一源程序的其它源文件中不能使用它。由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以避免在其它源文件中引起错误。从以上分析可以看出,把局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。把全局变量改变为静态变量后是改变了它的作用域,限制了它的使用范围。因此static 这个说明符在不同的地方所起的作用是不同的。应予以注意。
(四)c语言提供了另一种变量,即寄存器变量。这种变量存放在cpu的寄存器中,使用时,不需要访问内存,而直接从寄存器中读写,这样可提高效率。寄存器变量的说明符是register。对于循环次数较多的循环控制变量及循环体内反复使用的变量均可定义为寄存器变量。
对寄存器变量还要说明以下几点:
1. 只有局部自动变量和形式参数才可以定义为寄存器变量。因为寄存器变量属于动态存储方式。凡需要采用静态存储方式的量不能定义为寄存器变量。
2. 在turbo c,ms c等微机上使用的c语言中,实际上是把寄存器变量当成自动变量处理的。因此速度并不能提高。而在程序中允许使用寄存器变量只是为了与标准c保持一致。
3. 即使能真正使用寄存器变量的机器,由于cpu 中寄存器的个数是有限的,因此使用寄存器变量的个数也是有限的。
上一篇: 那用A和C可以不!
下一篇: 1、今天发现女友怀孕了