Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1619021
  • 博文数量: 268
  • 博客积分: 8708
  • 博客等级: 中将
  • 技术积分: 3764
  • 用 户 组: 普通用户
  • 注册时间: 2007-04-06 15:58
文章分类

全部博文(268)

文章存档

2014年(1)

2013年(15)

2012年(23)

2011年(60)

2010年(51)

2009年(12)

2008年(59)

2007年(47)

分类: C/C++

2008-04-16 17:01:00

 函数
一、             函数的引入:
高级语言中的“函数”实际上是功能的意思,当需要完成某个功能时,就用一个函数去实现它。将一个大的程序分成几个功能模块,并把功能块组织成层次关系。在C++中,可用函数实现每个功能块的功能。
将程序中的一些语句用函数来代替,可简化主程序的设计。
 
二、函数的定义:
类型修饰符  函数名(形式参数表)     //函数头
函数体
}
  函数的组成要素:类型修饰符、函数名、形式参数表和函数体
1、  类型修饰符:用于反应其返回值的情况,可分为有返回值函数和无返回值函数。
A、对于有返回值的函数,必须用int,double,bool等类型修饰符来说明函数返回值的类型,且函数体中必须用return 表达式;return指示系统结束当前函数的执行,返回到调用该函数的地方继续执行。

表达式值的类型应当与类型修饰符所限定的类型相同,否则,将自动被转换成类型修饰符所限定的数据类型,若二者不兼容,则会产生编译错误。

B、对于无返回值的函数,必须以void作为类型修饰符,函数体中可以用return;,也可以不用任何return语句结束函数的运行。
注:a、类型修饰符可以是除数组以外的任意数据类型。
    B、当函数中的类型修饰符为空时,则该函数具有默认的返回值类型int
2、  函数名:代表函数所封装的一组相关语句。
3、  形式参数表:是函数完成功能所需要的输入信息。可有0个或多个参数,之间用“,”隔开。
            函数定义中的参数称为形式参数,与其对应的是实参,实参是在调用函数的地方传递给函数的。
4、  函数体:是函数功能的实现之处。
       体中的语句可以是任意形式的语句,包括变量和常量定义语句表达式语句流程控制语句等。
 
三、函数的调用:
定义函数的目的是使用它,而函数的使用就是进行函数的调用。调用一个函数就是暂时中断现有程序的运行,转去执行被调用函数,当被调用函数执行结束后,在返回到中断处继续执行的过程。
1、  函数调用格式及调用方式:
一般格式:函数名(实在参数表)

是一系列用逗号分开的实在参数说明,每一个实参就是一个表达式,可以是常量、变量、函数调用等不含操作符的简单表达式,也可以是包含操作符的复杂表达式,但必须保证在数量和类型上与函数定义中的形式参数表一致。
 

有两种不同方式的函数调用:作为表达式的函数调用和作为语句的函数调用。
如:
#include
int max(int,int);

系统先调用main()函数,按顺序执行各语句,当需要计算max(a,b)时,就产生了一个函数调用,程序的执行转到max()中,并将实参a,b的值传递给形参x,y。当执行结束时,用return语句返回最大值给c。回到调用函数的地方,继续执行后序语句。
注:无返回值的函数调用一般会形成一个单独的语句。
void main()

{
    int a,b,c;
    cin>>a>>b;
    c=max(a,b);
    cout<
}
int max(int x,int y)
{
    if(x>y)
           return x;
    else return y;
}
2、  函数的递归调用:函数直接或间接地调用自身,则称为递归调用。
例题:设计函数fact(n),计算并返回n的阶乘。
四、函数原形与头文件:
1、函数原形(无函数体,以分号结尾,可省略形参)
   函数原型是一条函数说明语句,一条函数原型语句说明了一个函数的接口(函数名、函数参数的个数、参数类型及返回值类型)
2、函数原形:延伸了函数的作用域
a)         必须使用函数原型的场合:
                                       i.              多文件程序;
                                      ii.              函数之间的递归调用;
C++中,函数之间完全可以随意进行相互调用,函数funcA ()调用了函数funcB(),而funcB中又调用了函数funcA(),这时就必须在开始说明后定义的函数原形,以便在先定义的函数中能够调用。
                                    iii.              使用函数库;
使用自己定义的函数原形。
3、 头文件:
为了便于提供函数调用所需的接口信息,程序文件中定义的函数的原形通常都记录、保存在头文件中,每个程序文件对应一个头文件。
四、程序运行时的内存分布:(P83
当一个应用程序被启动执行时,操作系统会给该程序分配一块内存空间,用于存放该程序运行过程中的数据,包括程序本身的执行代码、程序中定义的各种常量、变量等。
该内存可分为四个区域:程序代码区、全局数据区、堆和栈
 
程序代码区
存放函数编译成的二进制代码
全局数据区
存放定义的全局变量以及函数体中定义的静态变量
是由程序支配的内存空间。在程序运行的初期,堆是一块空闲的区域,在程序运行过程中,可以用new在堆中动态申请空间,当用完了所申请的空间以后,就可以用delete释放这一块堆空间,然后这块空间就可以被重新利用了
由系统使用的动态空间,在进行函数调用时,系统使用栈来存放传递给被调用函数的信息,并且在栈中为被调用函数的局部变量分配空间。当被调用函数执行结束时,为调用这个函数所分配的所有空间就会被系统自动释放。 
 
五、函数调用的实现机制:
从栈的变化角度进行讲解:
函数的调用和返回遵循的规律与栈的后进先出的特征相吻合。在每次进行函数调用时,需开辟一定的内存空间存放如下信息:
1、  当前函数的运行状态和返回地址;
2、  被调用函数的参数;
注:栈空间由系统管理的,函数之间并不能互相访问局部量。
提醒:由于内存空间是有限的,所以,为了确保内存的有效利用,在不再需要所申请的内存空间的时候,应及时释放它们。
 
六、函数的参数和返回值:
    除不能返回数组外,函数的参数和返回值可以是任意数据类型。
 
七、函数调用中的参数传递:P122
(一)、传递方式:(三种)
传递方式
特  点
按值传递
A、形参与实参占一个独立的存储空间。
B、形参的存储空间是函数被调用时才分配的。调用开始,系统为形参开辟一个临时存储区,然后将各实参之值传递给形参,这时形参就得到了实参的值,这种方式称为按值传递。
C、函数返回时,临时空间被释放。
D、对形参的修改,不会影响到实参的值。
按地址传递
 
按引用传递
A、引用是它所引用的变量或常量的一个别名(生成一个对实在参数的别名)。
B、当函数的形式参数是引用类型时,它实际上是对实在参数所代表的变量或常量的引用,自己不具有独立的内存空间
 
(二)
1、  数组参数:实际上是一个指向实在参数的数组元素的指针。
           在使用数组传递参数时,一般会同时将数组元素的个数作为参数传递给函数。并且,在函数中,对数组参数做的改变将会影响到实在参数。
2、  指针参数:将实参的地址传递给形参。
3、  引用参数:自己不具有独立的内存空间,函数的调用可直接用变量名。
4、字符串作参数:
当用字符串作参数时,不必将字符串的长度传递给函数,因为字符串是以空字符‘\0‘结尾,在函数中可通过判断空字符来决定字符串是否结束。
5、多维数组作参数
(三)可选参数:P126
是关于参数中有默认值的问题。
C++中允许为函数的参数指定默认值。指定的方法是在函数的参数表中为要指定默认值的参数直接赋值。
八、内联函数:
一种特殊类型的函数,在定义或声明时在前面加上“inline”关键字。
inline int max(a,b)
{
   return(a>b)?a:b;
}
C++编译器处理内联函数的特殊性:
在遇到调用内联函数的地方会用函数体中的代码来替换函数的调用,比如:
int maxinum=max(val1,val2);等价于:
              int maxinum=((val1>val2)?val1:val2);
也就是说,程序执行时并没有真正调用函数max(),而是将内联函数的函数体中的语句直接在函数调用的地方展开了。
九、函数重载:P129
函数名相同,功能相似,参数不同。也就是说,函数名重载是指同一作用域内的多个函数使用相同的函数名,这些同名函数通过它们各自不同的参数表进行区分
1、函数重载的条件:
如果几个函数完成的功能类似,但是所操作的数据类型不同,就可以将它们用同一个名字来命名,而用不同的参数来区分不同的函数,即使用函数重载。
2、函数重载的使用方法:
A、重载函数的区分是以函数参数来进行的,而不是用函数的返回值来区分不同的函数,所以参数表完全相同而返回值不同的两个同名函数在C++中不认为是重载,而判定为错误的定义。
B、不要让功能不同的函数进行重载。
十、函数和变量的作用域:
作用域就是标识符在程序中能使用的范围。C++中的作用域与标识符的声明位置密切相关,一个标识符的作用域一般开始于标识符的声明处,而作用域的结束位置取决于标识符声明在程序中的位置。
根据标识符作用的范围,可将作用域分为文件作用域、局部作用域和类作用域。
1、函数的作用域:通常是全局的,不但在定义它的文件中可调用,而且在同一应用系统的其它程序文件中也可以调用。
还有一种函数仅仅是为了提供给同一文件中的函数调用,这种函数属于静态函数,其作用域称为文件作用域。
2、举例
//演示:文件作用域
//___________________
#include     //cin,cout的作用域开始
 
double factorial(int n)    // factorial的作用域开始
{
   …..
}
void main()           //main的作用域开始
{
  cin>>n;            //在cin的作用域中
  …
  fact= factorial(n)    //在factorial的作用域中
  …
  cout<
  …
}                  //cin,cout,factorial和main的作用域结束
 
2、变量的作用域和生存期:
依据变量作用域的不同,变量可分为全局变量和局部变量。
A、全局变量:定义于函数外部的变量。
B、局部变量:定义于函数内部的变量,其作用域具有局部作用域。
标识符的声明出现在函数的定义中。
分为三种局部变量:
(1)    自动变量:具有自动生存期,从变量定义处开始,到所在块运行结束时为止。
(2)    寄存器变量:p133
(3)    静态局部变量:具有静态生存期。
(4)    举例:
//从键盘读入一个整数n,计算并输出n!
//使用goto语句
//__________________
#include
 
double factorial(int n)    //n作用域开始
{
       double retVal=1;       //retVal作用域开始
       for(int i;i<=n;i++)    //i
              retVal*=i;         //i作用域结束
       return retVal;
}                          //n,retVal作用域结束
 
void main()
{                          //END作用域开始
       double fact;           //fact作用域开始
 
       do{
              cout<<"please intput n:";
              int n;             //n作用域开始
              cin>>n;
              if(n==0)
                     goto END;
              fact=factorial(n);
              cout<
       }while(1);             //n作用域结束
END:
       cout<<"thank you!\n";
}                          //fact,END作用域结束
十一、函数模板:(P123
           利用函数重载可以让具有类似功能而参数不同的函数使用相同的名字,这样程序更易理解,但仍然要写多个函数,并且这些函数的代码几乎完全相同,怎样才能减少重复代码?用C++的函数模板可进一步提高程序代码的可重复利用程度。只要实现一个函数模板,就可以用这个模板生成许多具体的函数来。(看书中模板样例P124)
使用函数模板使得我们只要写一次代码就可以生成多个具体的函数。
由于模板不限制使用的数据类型,使得我们可以用任何数据类型,甚至是自己定义的类型来享受系统提供的各种功能。
1、模板的实例化:
通过声明函数原型来告诉编译程序实例化函数模板:
int max(int,int);
float max(float,float);
当编译器看到函数原型时,会先生成相应的函数代码。
2、支持多种类型的模板:
在创建函数模板时,可以指定多于一个需要实例化的类型
阅读(1464) | 评论(0) | 转发(0) |
0

上一篇:malloc一个二维数组

下一篇:文件

给主人留下些什么吧!~~