第七章 函数

7.1 函数的概念

1.从函数定义的角度分类

  1)库函数

库函数(标准函数)是由C语言编译系统提供的,用户不必自己定义而直接使用它们,只需要在程序前包含有该函数原型的头文件即可在程序中直接调用。

  2)定义函数

由用户按需要写的函数。对于用户自定义的函数,不仅要在程序中定义函数,而且在主调函数中必要时还需要对其进行声明,然后才能使用。

2. 从函数的定义形式分类

  1)无参函数

函数定义、函数说明及函数调用中均不带参数。主调函数和被调子函数之间不进行参数传递。此类函数常常用来完成一组指定的功能,可以返回或不返回函数值。

  2)有参函数

有参函数也称为带参函数。在函数定义及函数说明时都有参数,称为形式参数(简称为形参)。在函数调用时也必须给出参数,称为实际参数(简称为实参)。进行函数调用时,主调函数将把实参的值传递给形参,供被调函数调用。

 

7.2  函数的定义和调用

1. 无参函数的定义

  类型标识符 函数名( )

  {

    声明部分

    语句部分

  }

其中类型标识符和函数名合称为函数头或函数首部。类型标识符指明了本函数的类型,实际上是函数返回值的类型。该类型标识符与第二章介绍的各种标识符相同,特别的是在很多情况下都不要求无参函数有返回值,此时函数声明可以写为 void 。函数名是由用户定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少。{ }中的内容称为函数体。

2. 有参函数的定义

  类型标识符 函数名(形式参数表列)

  {

    声明部分

    语句部分

  }

形参需逐一说明,形参之间用逗号分隔。

 

7.2.2 函数的参数和返回值

1.函数的参数

  1)形式参数

    定义函数时函数名后面括号中的变量名称为“形式参数”。

  2)实际参数

    在主调函数调用函数时,函数名后面括号中的参数称为“实际参数”。

   形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参。从而实现主调函数向被调函数的数据传送。

 

实参和形参各占一个独立的存储单元....... (在函数调用时,实参和其所对应的形参分别占用不同的存储单元,彼此之间不影响。)

 

2.函数形参和实参的特点

  形参变量只有在被调用时系统才分配内存单元,在调用结束时,所分配的内存单元立刻释放。这正是形参只有在函数内部有效的原因。函数调用结束返回主调函数后则不能再使用相关的形参变量。

  实参可以是常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。

  实参和形参在数量上、类型上、顺序上应严格一致。

  函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参值反向地传送给实参。因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。

3. 函数的返回值

  函数的返回值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值。

  函数的值只能通过return 语句返回主调函数。

  return 表达式;  或  return (表达式);

该语句的功能是计算表达式的值,并返回给主调函数。在函数中允许有多个return语句,但每次调用只能有一个return语句被执行,因此只能返回一个函数值。

函数值的类型和函数定义中函数的类型应保持一致。如果两者不一致,则以函数定义类型为准,自动进行类型转换。

如函数值为整型,在函数定义时可以省去类型说明。在C中,如果函数没有声明类型,则默认为int型。

不返回函数值的函数,可以明确定义为“空类型”,类型说明符为“void”。

 

7.2.3 函数的调用

函数调用的一般形式为:

   函数名(实际参数);

   如果调用无参函数,则无实际参数,但括号不能省。

实参表中求值顺序

  所谓求值顺序是指对实参表中各实参是自左至右使用还是自右向左使用。对此,各编译系统的规定不相同,而可能会造成程序执行的结果不同。

 

7.2.4 函数声明

  在C程序中,一个函数的定义可以放在任意位置,即可放在主函数main之前,也可放在main之后。如果放在调用函数后面,则在使用该函数前需要对该函数进行声明。

函数声明一般形式为:

  类型标识符 被调函数名(形式参数列表);

函数声明的形式就是在函数定义的第一行(也称为函数首部)的尾部加上分号,目的是为编译系统提供函数名及其参数表信息。

什么时候需要函数的声明呢?如果函数定义出现在函数调用前面时,不需要函数声明,但如果函数定义出现在函数调用后面就需要函数声明了。

 

7.3 函数的参数传递方式

值传递方式是在形式参数和实际参数之间传递数据的一种方式。值传递方式所传递的是参数值。

   当形参是变量名时,实参可以是常数、已赋值的变量名或数组元素名、表达式、函数等。在调用函数时,系统为形参自动分配存储单元,并将实参对应的值传递给形参。调用结束后,形参单元被释放,其值将丢失,实参单元仍保留原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数中实参的值。

可见,值传递的特点是参数值的单向传递,即只能把实参的值传递给形参,而不能把形参的值反向传回给实参。

 

地址传递方式也是在形式参数和实际参数之间传递数据的一种方式。地址传递方式所传递的是地址。

当形参是地址(如数组名、指针变量)时,实参只能是变量的地址、数组名(数组首地址)或指针变量,此时参数传递按地址传递方式进行,即调用函数时将实参地址传递给对应的形参。由于形参和实参的地址相同(占用相同的内存单元),所以对形参的操作相当于对实参的操作。

 

7.4 函数的嵌套调用与递归调用

C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能包含另一个函数,不能嵌套定义函数。但是C语言允许在一个函数的定义中出现对另一个函数的调用----函数的嵌套调用。

一个函数在它的函数体内调用自身称为递归调用,这种函数称为递归函数。C语言允许函数的递归调用。在递归调用中,主调函数又是被调函数。执行递归函数将反复调用其自身。

例题. 用递归的方法求 n! 。

long fac(int n)
{
    int x;
    if ((n == 1) || (n == 0)) x = 1;
    else
        x = n*fac(n - 1);
    return x;
}

 

7.5 变量的作用域和生命期

通常把在函数内定义的变量称为内部变量,把在函数外定义的变量称为外部变量。

每种变量都有开始分配内存单元到最终内存单元被释放的过程,称为变量的生存期,生存期内变量起作用的范围称为变量的作用域。任何变量只能在作用域范围内使用,在作用域范围外使用将出错。

按作用域的范围,可以将变量分为局部变量和全局变量。凡在函数内部定义的变量都是局部变量,包括函数内部复合语句中定义的变量和函数的形式参数。而在函数外部任何位置上定义的变量都是全局变量。 局部变量的作用域是从定义位置起到函数体或复合语句结束为止。全局变量的作用域从定义点开始到源文件结束为止。

 

静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式。动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式。

在内存中,用户存储空间可以分为三个部分:程序区、静态存储区、动态存储区。

数据分别存放在静态存储区和动态存储区中。

全局变量和static局部变量存放在静态存储区,在程序开始执行时给全局变量分配存储区,直到程序执行完毕后才释放。在程序执行过程中它们占据固定的内存单元,而不是动态地进行分配和释放。

动态存储区存放以下数据:

函数形式参数、自动变量(未加static声明的局部变量)、函数调用时的现场保护和返回地址等。对以上这些数据,在函数开始调用时分配动态存储空间,函数结束时释放这些空间。

 

在C语言中,每个变量和函数有两个属性:数据类型和数据的存储类别。

存储类别指的是数据在内存中存储的方式。存储方式分为两大类:静态存储类和动态存储类。

具体包含4种:自动(auto)、静态(static)、寄存器(register)、外部(extern)。

定义变量存储类别的语句格式为;

  存储类别说明符 数据类型说明符 变量名1,变量名2……,变量名n。

 

1. auto 变量

  函数中的局部变量,如不专门声明为static存储类型,都是默认为其动态地分配存储空间,数据存储在动态存储区。函数中的形参和函数中定义的局部变量(包括复合语句中定义的变量),都属于此类。在调用该函数是系统会给它们分配存储空间,在函数调用结束时就自动释放这些存储空间。这类局部变量称为自动变量。自动变量用关键字auto做存储类别声明。

2. static 变量

  有时候希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明。

 对全局变量用static声明,则该文件的作用域只限于本文件模块,不能被其它文件中的函数使用。

静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间都不释放。

3. register 变量

  为了提高效率,C语言允许将局部变量的值放在CPU中的寄存器中,需要时直接从寄存器取出。不必再到内存中去取。这种变量叫做寄存器变量。

只用局部自动变量和形式参数可以作为寄存器变量。局部静态变量不能定义为寄存器变量。不能定义任意多个寄存器变量。

4. extern 变量

外部变量(即全局变量)是在函数外部定义的。它的作用为从变量定义处开始,到本程序文件的末尾。

如果在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字 extern对该变量做“外部变量声明”。表示该变量是一个已经定义的外部变量。

外部变量在函数外部只能初始化,而不能赋值。

注意:

  1)主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用。同时,主函数中也不能使用其它函数中定义的变量

  2)形参变量属于被调函数的局部变量,实参变量是属于调用函数的局部变量或全局变量。

  3)允许在不同函数中使用相同的变量名,它们代表不同的对象,分配不同的内存单元,互不干扰,也不会发生混淆。在复合语句中定义的变量,其作用域只在复合语句范围内。

若全局变量和某一函数中的局部变量同名,则在该函数中,此全局变量被屏蔽。在该函数内,访问的是局部变量,与同名的全局变量不发生任何关系,也就是局部变量覆盖全局变量。

 

posted @ 2020-08-18 23:13  YangXinYi  阅读(466)  评论(0编辑  收藏  举报
//color="150,150,150"粒子的颜色设置 opacity="1"粒子的透明度 count="100"粒子的个数