第17节 C语言之函数与全局变量局部变量

来源:互联网 发布:php5权威编程 pdf 编辑:程序博客网 时间:2024/05/17 00:59

函数

一、为什么要使用函数

1.代码的复用(重复使用)

2.可以降低程序的复杂性,模块化编程,提高开发的效率

3.大大的增加了代码的可维护性和可读性

4.对代码可以进行集中的控制便于改进性能

5.隐藏代码(全局变量)

6.隐含指针的操作

7.隐含数据结构(可以把数据结构的实现隐含起来)


二、函数是什么

函数就是具有相同功能或具有独立功能的语句和变量或表达式的封装就是函数。


三、函数的分类 ( 三类)

1.从用户的角度分

   系统函数

   <stdio.h>

   printf(),scanf(),gets()等

   自定义函数

   用户(程序员)根据自己的需求 给函数设定返回值类型,函数名,参数类型及个数这样的函数我们就成为自定义函数。


    函数的声明

    1.显式声明

       函数一般格式:

       返回值类型  函数名(形参列表);

       例子:说计算两个数的和 100,50;

       int add(int x,int y);

       int sub(int x,int y);

       表示:函数名为add,函数的参数有2个,int x,int y.这里的x,y叫做形参,也就是形式上得参数,没有具体的值,只是在函数声明时,告诉给编译器,有这样类型的参数和数量。函数前边的int表示是返回值类型,如果一个函数有返回值,就需要使用return,就是把函数运算以后的结果返回给程序,以便继续使用该结果继续运行。

     void show();


      也就是说显式的函数声明分为:声明和实现两个部分。

      int add(int x,int y);//声明部分


      int add(int x,int y)//函数的实现部分

      {

             return x+y;//函数的功能,也叫函数体

             //printf("return语句后面的都不被执行");

      }

     什么情况下有返回值,就是当这个函数的运行结果需要继续使用时,我们就需要给函数设定返回值,返回值的类型一般与函数参数相一致。函数有返回值的标志是return语句,通过return语句 返回运算符的结果。

     return语句一次只能返回一个运算符结果。不能是多个。

     注意:return语句后面的语句不管是什么语句都不在被执行。



    2.隐式声明(不推荐使用)

       int add(int x,int y)

       {

           return x+y;

       }

       隐式声明不能在程序的任意位置调用该函数,如果有多个函数,想进行嵌套调用时,只能是后面的函数调用前面声明的函数,前面声明的函数不能调用在该函数以后声明的函数。


2.返回值角度分

   有返回值    有返回值的标志   retrun

   无返回值    没有返回值的标志 void


3.参数的角度分

   有参数      有参数 告诉编译器 参数的类型和个数 ,隔开

   无参数      没有参数 (void)或();


练习1:声明4个函数,分别计算整型变量a,b的和 差  积  商,并返回计算结果。

练习2:在主函数中写,不用分装函数,声明一个数组赋值10整型的值,然后用冒泡排序排序(升),遍历数组。



四、函数调用


1.函数的一般调用


   函数名(实参);


   形参:形式上的参数,是在函数声明时,告诉给编译器,你参数的类型和个数。没有具体的值。int x;


   实参:在函数运行过程中实际参与运算符的值,就叫实参。有具体的一个值。10


   int add(int x,int y);

   注意:在函数调用前必须要实现这个函数。函数的入口地址是函数名所在的内存空间。实参的类型和个数需要和形参一致。

  add(10,5);


  如果我们需要用到这个函数的返回值,那么你可以用一个该函数返回值类型的变量来接收这个返回值。

  //有返回值 有参数/没参数

  int sum = add(10,5);

  printf("sum=%d\n",sum);//两个数之和


  //没有返回值 有参数/无参数

  print();

  print(100);


2.函数的嵌套调用


    2.1 一般嵌套

          函数的嵌套调用,就是指一个函数在自己的内部调用另外一个函数的过程,这个过程就叫做函数的嵌套调用。


    练习:我们模拟一个中国工商银行ATM系统。

    默认卡号:888888  密码:123456  

    余额:99999999.00元

    *********************************************

    卡号:

    密码:

    *********************************************

    进入主界面

    *********************************************

    1.查询                                                    2.存款

    3.转账                                                     4.取款

    5.改密                                                     6.其他

    *********************************************

    存款画面

    ---------------------------------------------------------

                   请放入面值:100元的人民币

                   数量:10张 (每次最多100张)

    ---------------------------------------------------------


    取款 单笔不能超过2500元   (0.5%)

    ---------------------------------------------------------

    1.200元                                               2.300元

    3.500元                                               4.1000元

    5.2000元                                             6.其他金额

    ---------------------------------------------------------


    转账

    ---------------------------------------------------------

        1.同行卡卡转账          2.跨行卡卡转账

    ---------------------------------------------------------

        转入卡号:899999(同)  999999(跨)

        再输一遍:899999

        金额:2000元

        转出卡中-2000  转入卡:+2000


    2.2 函数递归调用


          一个函数调用另外一个函数恰好就是它本身,就叫做函数的递归调用。


         例子:斐波那契数列(费氏数列),兔子繁殖,八皇后的问题,汉诺塔的游戏。


         1   1   2   3   5   8  13   21   34

         

         分析:找到费氏数列的规律并归纳推到出数列公式。


         提示:前三项   从第二项开始,后边的数等于前两项之和。


        f(n) = f(n-1) + f(n-2)


       计算费氏数列的前N项和。45项


        long long int保存结果。


        函数递归调用,在发生时会消耗大量的系统资源,如内存和CPU,以上边例子而言,如果是配置低得电脑,就可能出现卡顿的现象,因为在函数递归调用时函数会频繁的出栈和入栈,读写栈内存,交换数据。造成系统不稳定,所以在我们开发过程中如果遇到递归的情况应尽量避免,能不用就不用。就算非得用也有替换的方案,万不得已用了也必须是一个浅层的递归调用,一般不超过3层。否则容易造成系统不稳定,或程序运行缓慢。


       在使用递归时必须要同时具备如下几个条件

        1.必须是直接或间接的调用它本事。(充要条件)

        2.出口(结束递归的条件)

        3.有一个明显的公理或可以推导出来的公式


      优点:就是算法比较简单,你能够看得懂。

      缺点:   频繁入栈和出栈,执行效率低。


      递推

      递推是一种思想,递推就是循环迭代,简单的说,递推

的效率要比递归高很多很多很多。

      优点:凡是能都用递归的,都能用递推来解决,执行效率极高。

      缺点:算法及其复杂,一般人根本看不懂。

       

       1   1    2   3   5     8  13   21  34


五、函数中的传值


1.值传递(传的是一个数值)


   值传递的传递过程是,编译器需要给实参自我复制一份副本,也就是说形参和实参用的不是同一块内存空间,形参的改变不会影响到实参的变化。因为传递的是实参的副本,就算修改了,最后修改的也是 副本,不是实参本身。数据的保护。

   什么时候发生的是值传递,基本数据类型的变量,以及数组中的 某一个具体的数组元素 a[0],是值传递。


2.地址传递(传址)


   地址传递传递的是实参的指针(实参所在内存中的地址),把实参的地址直接替换形参,也就是说实参和形参共用了一块内存空间,形参的改变直接影响实参的值。

   传递 指针或数组(整个数组做参数时 传实际上数组的首地址)


六、数组做参数在函数中传递(地址传递)

void show(int A[],int n);

int find(int A[],int n)


for()

{

  scanf("%d",&a[i]);//值传递

}


for()

{

  printf("%d\n",a[i]);//值传递

}


七、变量和变量的作用域


1.全局变量


    全局变量 就是声明在全局区的变量,也可以通过特殊的关键字进行修饰限制以后变成全局变量。全局变量的作用域就是从程序开始运行一直到该程序结束的整个过程都可以访问全局变量,在函数体内部的局部变量也可以访问和修改任何一个全局变量。写在main()函数外部的 文件最开始的部分,声明的下方就是全局变量。如果你想让这个变量的值在程序中得任意位置都能够被访问,那么就把它设置称为全局变量。


2.局部变量

    是声明在函数内部的变量,也就是说在函数的代码块中声明的变量,作用域就是从该函数开始执行到 该函数结束为止,局部变量就被释放了。

void show()

{

    int a = 100;//局部变量

}

//a = 50;//这样是错误的

作用:

1.比如说这个变量就是处理一些临时性的事物的,就用一会,用完就释放,不需要该变量一直存在。

2.局部变量在函数体外部不可见,也就是说局部变量只能在函数体内部使用。

0 0