用函数实现模块化程序设计

1.为什么要用函数


        当我们在编写程序的时候,如果程序的功能过多,规模比较大,把所有的程序都写在一个主函数里面的时候,会让程序变得复杂,不利于后面的维护和阅读。此外,当程序要多次实现某一功能的时候,就要多次重复编写实现此功能的代码使程序冗长。

        因此可以事先遍好我们常用的函数来实现各种不同的功能,在使用的时候,就可以像组装零件一样将它拿出来,实现我们想要的功能。这就是模块化编程的思路。

2.怎么定义函数

        在C语言中,在程序中用的函数,必须先定义,后使用。

        定义函数应包括以下内容:

        (1)指定函数的名字,以便以后按名调用

        (2)指定函数的类型,即函数返回值的类型。

        (3)指定函数的参数的名字和类型,以便在调用函数时向它们传递数据。对无参函数不需要这项。

        (4)指定函数应当完成什么操作,也就是函数是做什么的,即函数的功能。这是最重要的,是在函数体中解决的。

        对于C语言提供的库函数,是由编译系统事先定义好的,库文件中包括了对各函数的定义。

         2.1定义函数的方法

           1.定义无参函数

                在定义函数时要用“类型标识符”(即类型名)指定函数值的的类型,即指定函数带回来的值的类型。

类型名 函数名()
{
    函数体  //函数体包括声明部分和语句部分
}
或
类型名 函数名(void)//void表示空,即函数没有参数
{
    函数体
}

               2 定义有参函数

类型名 函数名(形式参数表列)
{
    函数体 //函数体包括声明部分和语句部分
}

比如

int max(int x,int y)
{
    int z;
    z=x>y?x:y;
    return z;
}

                3.定义空函数

               在程序设计中有时会用到空函数,他的形式为

类型名 函数名()
/*
函数体是空的。调用此函数时,什么也不做,没有实际作用
它主要作用是为之后需要的函数占一个位置,
这样可读性会比较好,扩充功能方便
*\

3.调用函数

        3.1函数调用的形式

        一般形式为函数名(实参表列)

        1.函数调用语句:将函数调用单独作为语句。

        2.函数表达式:调用函数出现在另一个表达式中

        3.函数参数:函数调用作为另一个函数调用时的实参

        3.2函数调用时的数据传输

         1.形参和实参

         2.形参和实参间的数据传递

        3.3函数调用的过程

        1.在定义函数中的形参,未被调用的时候,并不占内存空间。发生调用时才会给他分配内存单元。

        2.将实参的值传给对应形参。

        3.在执行函数时,由于形参已有值,就利用形参进行有关的运算

        4.通过return语句将函数值待会到主调函数。返回值的类型与函数类型一致。(如果函数不需要返回值则不需要return语句。这时函数类型应定义为void)

        5.调用结束,形参被释放。注意:实参仍保留原值

        (实参向形参的数据传递是值传递,单向传递,只能由实参传给形参。两者在内存中占有不同的储存单元,实参无法得到形参的值)

        3.4函数的返回值

                通常我们希望通过函数调用使主调函数能得到一个确定的值,这就是函数值。

                函数返回值是通过return语句获得,类型和函数类型一样。函数类型决定返回值类型。

4.对被调函数的声明和函数原型

        一般形式:

        1.函数类型 函数名(参数类型1 参数名2,参数类型2 参数名2,……,参数类型n 参数名n);

        2.函数类型 函数名(参数类型1,参数类型2,……参数类型n);

        函数的声明和定义并不一样,函数的定义是一个完整 的函数单位,而函数的声明的最有则是把函数的名字、类型等通知编译器,以便调用函数时系统按此进行第一种检查,它不包含函数体

        如果已在文件的开头(所有函数之前),已对本文件所调用的函数进行声明,则在各函数中不必对其所调用的函数再作声明。

5.函数的嵌套使用

        C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能再定义另一个函数,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数

6.函数的递归调用

        在调用函数的过程中又直接或间接的调用该函数本身,成为函数的递归调用。

        比如

//递归法 求n!
int fac(int n)
{
    int f;
    if (n<0)
    printf("error!");
    else if(n == 0 | n == 1)
        f = 1
    else f = fac(n-1)*n;
    return f;
}

7.数组作为函数实参

        调用有参函数时,需要提供实参。实参可以是常量、变量或表达式。数组 。数组的作用与变量相当,一般来说,凡是变量可以用的地方,个都可以用数组代替。数组元素可以用作函数实参,其用法与变量相同,向形参传递数组元素的值。此外,数组名也可以做实参和形参,传递的是数组的第一个元素的地址。

        7.1数组作为函数参数

                数组元素可以作为参数,但是不能用作形参。因为形参 是在函数被调用时临时分配存储单元的,不可能为一个数组元素单独分配存储单元。在用数组元素做函数的实参时,把实参的值传给形参,是值传递的方式。数据传递的方向是从实参到形参,单向传递。

        7.2一维数组名作函数参数

                除了可以用数组元素作为函数参数外,还可以用数组名做函数参数(包括形参实参)

                注意:用数组元素作实参时,向形参变量传递的是数组元素的值,而用数组名作函数实参时,向形参(数组名或指针变量)传递的是数组首元素的地址。

        7.3多维数组名作函数参数

                多维数组元素可以作函数参数,这点与前述情况类似;

                可以用多维数组名作为函数的实参和形参,在被调用函数中对形参数组定义时可以指定每一维的大小,也可省略第一位的大小说明。

8.局部变量和全局变量

        每一个变量都有他的作用域,即它们在什么范围内有效。

        8.1 局部变量

                定义变量可能有三种情况:

                (1)在函数的开头定义

                (2)在函数内的复合语句内定义

                (3)在函数的外部定义

                在一个函数内部定义的变量只在本函数范围内有效,也就是说只有在本函数内才能引用他们,在函数以外是不能使用这些变量的。在复合语句内定义的变量只在本复合语句范围内有效,只有在本复合语句内才能引用它们。在该符合语句意外是不能使用这些变量的,以上这些成为“局部变量”。(形参也是局部变量 在一个程序内部,可以在复合语句中定义变量,这些变量只在本符合语句中有效,这种复合语句也称为“分语句”或“程序块”)

        8.2 全局变量

                一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数外定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。

                在一个函数中既可以用本函数的局部变量,也可以使用有效的全局变量;

                设置全局变量的作用是增加了函数间数据联系的渠道。为了区分全局变量和局部变量,大部分会将第一个字母用大写表示。

                全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要的时候才开辟单元

9. 变量的存储方式和生存期

        9.1 动态存储方式与静态存储方式

                从前面可知,从变量的作用域的角度,变量可以分为全局变量和局部变量。

                还可以从另一个角度,即从变量值存在的实际来观察。有的变量在程序运行的整个过程都是存在的,而有的变量则是在调用其所在的函数时才分配临时存储单元,而在函数调用结束后该存储单元就马上释放了,变量不存在了。也就是说,变量的存储有两种不同的方式,静态存储方式和动态存储方式。静态存储方式是指在程序运行期间由系统分配固定的存储空间的方式,而动态存储方式则是在程序运行期间根据需要进行动态的分配存储空间的方式。

                在内存中供用户使用的存储空间分为三部分:程序区;静态存储区;动态存储区

        数据分别存放在静态存储区和动态存储区中。全局变量全部存放在静态存储区中,在程序执行的过程中他们占据固定的存储单元而不是动态地进行分配和释放。

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

        1.函数形式参数。在调用函数时给形参分配存储空间

        2.函数中定义的没有用关键字static声明的变量,即自动变量

        3.函数调用时的现场保护和返回地址等

        对于以上这些数据,在函数调用开始时分配动态存储空间,函数结束时释放这些空间。

        如果一个程序中包含若干个函数,每个函数中的局部变量的生存期并不等于整个程序的执行周期,它只是程序执行周期的一部分

        在C语言中,每一个变量和函数都有两个属性:数据类型和数据的存储类别。(数据类型就是整型浮点型等),存储类别指的是数据在内存中的存储的方向(如静态存储和动态存储)

        在定义和声明变量和函数时,一般应同时指定其数据类型和存储类别,也可以采用默认方式指定

        C的存储类别包括4种:自动的(auto)、静态的(statis)、寄存器的(register)、外部的(extern)。根据变量的存储类别,可以指定变量的作用域和生存期、

        9.2 局部变量的存储类别

        9.2.1.自动变量(auto变量)

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

                实际上,关键字auto可以省略,不写auto则隐含指定为“自动存储类别”,它属于动态存储方式。程序中大多数变量属于自动变量。

        9.2.2.静态局部变量(static局部变量)

        有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次在调用该函数时,该变量已有值(就是上一次函数调用结束时的值)。这时就应该指定该局部变量为“静态局部变量”,用关键字static进行声明

        1.静态局部变量属于静态存储类别,在静态存储区内分配存储单元。在程序整个运行期间不释放。而自动变量属于动态存储类别,分配在动态存储区空间,函数调用结束后即释放。

        2.对静态局部变量是在编译时赋初值,只赋初值一次。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而对自动变量赋初值是在函数调用时进行的,每调用一次函数重新给一次初值,相当于执行一次赋值语句。

        3.如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(数值型)或空字符’\0‘(对字符变量)。而对自动变量来说,它的值是一个不确定的值。

        4.虽然静态局部变量在函数调用结束后仍然存在,但其他函数是不能与引用的。因为它是局部变量,只能被本函数引用,而不能被其他函数引用。

        注意:用静态存储要多占内存,而且降低了程序的可读性,因此非必要不要多用静态局部变量。

        9.2.3 寄存器变量(register)

        一般情况下,变量(包括静态存储方式和动态存储方式)的值是存放在内存中的。当程序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到运算器中。

        如果有些变量使用频繁,则为存取变量的值要花费时间。为提高执行效率,允许将局部变量的值放在cpu的寄存器,需要的时候直接从寄存器取出参与运算,不必再到内存中去存钱。寄存器的存取速度远高于内存 ,这样可以提高执行效率。这种变量叫寄存器变量,用关键字(register作声明)。(目前计算机性能变高,优化的编译系统能识别使用频繁的变量,从而不需要程序设计者指定。现在register声明变量的必要性不大)

        9.3全局变量的存储类别

        全局变量都是存放在静态存储区中。生存期固定,存在于程序的整个运行过程。

        作用域是从变量的定义处开始到程序文件末尾

        9.3.1在一个文件内扩展外部变量的作用域

        如果外部变量不在文件的开头定义,器有效的作用只限于定义处到文件结束。当我们在定义点之前的函数需要引用外部变量,则应该在引用之前用关键字extern对变量作“外部变量声明”,表示把该外部变量的作用域扩展到此位置

        9.3.2将外部变量的作用域扩展到其他文件

        一个C程序可以由一个或多个源程序文件组成。如果两个文件都要用同一个外部变量时,不能分别在两个文件中各自定义一个外部变量,否则会出现重复定义的错误。应当在任意文件中定义外部变量,而在另一文件中用extern对这个变量作外部变量声明       

        注意:这种方法在执行中可能会影响另一个文件中全局变量的值从而影响该文件中函数的执行结果。 

        9.3.3 将外部变量的作用域限制在本文将中

        可以在定义外部变量时加一个static声明。这种加上static声明、只能用于本文件的外部变量叫做静态外部变量。

       

用static声明一个变量的作用

        1.对局部变量用static声明,把它分配在静态存储区,该变量在整个程序执行期间不释放,其分配的空间始终存在

        2.对全局变量用static声明,则该变量的作用域只仅限于本文件模块

        注意:用auto,register和static声明变量时,是在定义变量的基础上加这些,而不能单独使用

10.关于变量的声明和定义

        一般来说把建立存储空间的声明称定义,把不需要建立存储空间的声明称为声明。

11.内部函数和外部函数

        根据函数能否被其他源文件调用,将函数分为外部函数和内部函数

        1.内部函数

                static 类型名 函数名(形参表);

                内部函数又叫静态函数。提高程序可靠性;

        2.外部函数

                extern 类型名 函数名(形参表)

                C语言规定,在定义时省略extern则默认为外部函数。在需要调用此函数的其他文件中,要加关键字extern。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值