十. 函数

● 基本概念

函数

函数定义 function definition:

return_type function_name ( parameter list )

{ Body of function; }        //函数体内先是变量的声明, 然后是语句; 这就样平时看到的主函数一样, 先有变量, 再有语句

函数调用 function call:

function_name ( arguments list );

函数原型: 函数原型也叫函数声明,还叫引用说明, 函数声明由函数返回类型、函数名和形参列表组成。形参列表必须包括形参类型,但是不必对形参命名。

函数声明 function declaration

return_type function_name ( parameter list );

※ 如果函数定义在先,调用在后,调用前可以不必声明;
如果函数定义在后,调用在先,调用前必须声明。

#include <iostream>

using namespace std;

void show_message();    //声明一个返回值类型为空(不返回函数值), 没有形参, 函数体只有一条输出语句的子函数,

void show_age();        //声明一个返回值类型为空(不返回函数值), 没有形参的子函数, 函数体有变量定义和输出语句的子函数

void out(int x, int y);    //声明一个返回值类型为空(不返回函数值), 但有两个形参的子函数(一些返回值类型为空的子函数不需要没有形参); 形参列表可以省略形参, 即int dec(int, int)

int dec(int x, int y);    //声明一个返回值为int型, 函数体只包含一条返回语句的子函数; 两个不同子函数的形参的标识符可以一样

int func(int n);        //声明一个返回值类型为空, 有一个形参, 函数体为一个if...else if...else...语句的子函数

int main()

{

show_message();        //函数调用, 不需要实参

show_age();

out(10, 5);            //不能写成cout<<out(10, 5)<<endl, 因为子函数out()的没有返回值, 无法传值给cout对象

cout<<dec(10, 5)<<endl;    //调用子函数dec()以后, 返回值返回到 主函数main()调用dec()函数的位置

int a=10, b=5;

cout<<dec(10, a+b)<<endl;    // 实参可以是常量、变量或表达式,如这里的dec(10, a+b),但要求a和b有确定的值; 形参不能是表达式

//不直接给出fun()实参的值, 而是靠用户输入

int n;

cout<<"input n: "<<endl; //如果没有这个提示, 就直接输入n的值

cin>>n;

cout<<"\nthe result: "<<func(n)<<endl;

return 0;

}

//子函数show_message()

void show_message()

{

cout<<"Hello World!"<<endl;        //就算只有一条语句, 也必须要用一对花括号

}

//子函数show_age()

void show_age()

{

int age=23;

cout<<"age is: "<<age<<endl;

}

//子函数out()

void out(int x,int y)

{

cout<<x+y<<endl;

cout<<x-y<<endl;

}

//子函数dec()

int dec(int x, int y)

{

return(x+y);

}

//子函数dec()

int func(int n)

{

if(n>0)

return 1;        //n>0成立

else if (n==0)

return 0;        //n=0成立

else

return -1;    //n=-1成立

}

#include <iostream>

using namespace std;

int add(int x)

{

return x;

}

int main()

{

int a=add(0);

cout<<a<<endl;

int b=add(a+10);

cout<<b<<endl;

return 0;

}

//函数的实参可以是表达式:

● 栈帧

栈帧(Stack Frame)是栈上的内存片段,也叫过程活动记录,是编译器用来实现过程/函数调用的一种数据结构。其主要作用有:为局部变量和临时变量分配空间,传递参数,保存返回地址。

每个函数在栈上拥有独立的帧,这些帧是在函数调用时分配的。在任一时刻,寄存器ebp(帧指针)都指向帧的起始处,寄存器esp(栈指针)指向帧的结尾处,它们之间的部分是当前函数的栈帧。我们可以这样认为,ebp是局部的,作用于当前帧,而esp是全局的,作用于整个栈。

(1)ESP:栈指针寄存器(extended stack pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的栈顶。

(2)EBP:基址指针寄存器(extended base pointer),其内存放着一个指针,该指针永远指向系统栈最上面一个栈帧的底部。

ebp是寄存器,前面加%表示取寄存器的值, 以此类推.

假设函数P(caller)调用函数Q(callee),一般来说在P中会执行如下操作:

  1. push %ebp; move %esp, %ebp; 保存上一帧的ebp,以便恢复,并将ebp指向帧头
  2. sub $NUM, %esp; 为局部变量和临时变量分配空间,其中NUM为字节数,在编译时已经确定
  3. 将参数从右到左依次压栈
  4. 将返回地址压栈
  5. 跳转到函数Q的第一条语句
  6. 将返回值(如果有)保存在eax中
  7. 释放空间,恢复信息(如ebp)
  8. 弹出返回地址并返回

举个例子:

  1. int caller(int m, int n)
  2. {
  3. return m + n + callee(m, n);
  4. }
  5.  
  6. int callee(int x, int y)
  7. {
  8. return x + y;
  9. }

由gcc编译之后的汇编代码如下:

  1. caller:
  2. pushl %ebp //将上一帧的帧指针压栈
  3. movl %esp, %ebp //令ebp指向帧头
  4. pushl %ebx
  5. 个字节
  6. movl 12(%ebp), %eax //获取参数n
  7. movl 8(%ebp), %edx //获取参数m
  8. leal (%edx,%eax), %ebx //leal指令,相当于ebx = edx + eax = m + n
  9. movl 12(%ebp), %eax
  10. movl %eax, 4(%esp) //参数n压栈,注意n先于m压栈
  11. movl 8(%ebp), %eax
  12. movl %eax, (%esp) //参数m压栈
  13. call callee //返回地址压栈,并跳转到callee
  14. leal (%ebx,%eax), %eax //此时ebx的值为m+n,eax(前者)的值为callee的返回值
  15. addl $20, %esp //释放空间
  16. popl %ebx //恢复信息
  17. popl %ebp
  18. ret //弹出返回地址并返回
  19.  
  20. callee:
  21. pushl %ebp
  22. movl %esp, %ebp
  23. movl 12(%ebp), %eax
  24. movl 8(%ebp), %edx
  25. leal (%edx,%eax), %eax
  26. popl %ebp
  27. ret

个字节,但实际只需要8个字节,这是什么原因呢?
-----
| ebp |
| ebx |
| . |
| . |
| . |
| n |
| m |
| ra |
-----
这是因为在IA32架构中,栈帧的大小总是16的倍数。通过研究栈帧的内容,可以发现寄存器ebp、ebx再加上返回地址ra总共是12个字节,因此栈帧的总大小为32。

● 函数的调用

函数的调用的执行过程:

第一步:函数调用;
① 将函数调用语句下一条语句的地址保存在一种称为""的内存空间中,
以便函数调用完后返回。将数据放到栈空间中的过程称为压栈

② 对实参表从后向前,依次计算出实参表达式的值,并将值压栈。

③ 转跳到函数体处。

第二步:函数体执行,即逐条运行函数体中语句的过程。

④ 如果函数中还定义了变量,将变量压栈。

⑤ 将每一个形参以栈中对应的实参值取代,执行函数体。

⑥ 将函数体中的变量、保存在栈中的实参值,依次从栈中取出,以释放栈
空间。从栈中取出数据称为出栈,x出栈用pop(x)表示。

第三步:返回,即返回到函数调用表达式的位置。

⑦ 返回过程执行的是函数体中的return语句。

例如:

int max(int x,int y)

{

int z;

z=(x>y)?x:y;

return z ;

}

函数max()的详细过程是:

//几个概念

调用函数时,要先把寄存器的值入栈,这个过程叫做函数调用时的现场保护.

函数执行完成后要出栈,叫做现场还原.

返回地址一般是紧邻函数调用语句的下一条语句的地址, 因为函数调用结束后程序要继续执行, 所以先把这个地址压入堆栈, 等函数调用结束以后, 把这个地址从堆栈里面弹出来, 然后执行.

● 默认参数(default parameter)

//sample1.cpp

#include <iostream>

using namespace std;

void OutputInfo(const char* pchData = "Hello!") //括号里的参数还可以写成(char* pchData = "Hello!"), 差别是?△

{

cout << pchData << endl;    //输出信息

}

void main()

{

OutputInfo();            //利用默认值作为函数实际参数

OutputInfo("World!");    //直接传递实际参数

}

//sample2.cpp

#include <iostream>

using namespace std;

int add(int x=5, int y=6)

{

return x+y;

}

int main()

{

cout<<add(10,20)<<endl;

cout<<add(10)<<endl;

cout<<add()<<endl;

return 0;

}

/*注意①默认参数不能出现在非默认参数的左边:

int func(int x, int y=10, int z)    //非法

int func(int x, int y, int z=10)    //合法

②形参的默认值可以是: 全局常量, 全局变量, 表达式, 函数调用, 但不能是局部变量, 如:

void func1()

{

int k;

void func2(int x=k); //k为局部变量, 不能作为形参的默认值

}

*/

● 函数和宏的区别

//带参函数的定义和调用

#include <iostream.h>

int SQ(int);

void main()

{

int i=1;    //声明变量并初始化

while(i<=5)

cout<<SQ(i++)<<"\t";

cout<<endl;

}

int SQ(int x)

{

return ((x)*(x))

}

//带参宏

#define SQ(x) ((x)*(x))

#include <iostream.h>

void main()

{

int i=1;

while(i<=5)

cout<<SQ(i++)<<"\t"; //主函数运行前, SQ(i++)被替换为((i++)*(i++)), 每次循环后,i的值会增加2, 因此只会做三次循环

cout<<endl;

}

● C/C++参数传递的3种方式

传值调用----数据传送是单向的----不影响原始的实参值;

地址调用----数据传送是双向的----修改原始的实参的值(在被调用函数中修改调用函数环境中的参数变量);

引用调用---数据传送是双向的----同上

#include <iostream.h>

void swap1(int x, int y);        //单向值传递

void swap2(int *x, int *y);    //(双向)地址传递, 优先在C语言中使用

void swap3(int &x,int &y);                // (双向)引用传递, 在C语言中使用(因为引用是C++的概念)

int main()

{

int a=5,b=10;

swap1(a,b);

cout<<"a="<<a<<endl;

cout<<"b="<<b<<endl;

swap2(&a,&b);

cout<<"a="<<a<<endl;

cout<<"b="<<b<<endl;

swap3(a,b);

cout<<"a="<<a<<endl;

cout<<"b="<<b<<endl;

return 0;

}

void swap1(int x, int y)    //如下三个子函数, 也可以定义为int型, 并返回0

{

int tmp;

tmp=x;

x=y;

y=tmp;

cout<<"swap1: x="<<x<<endl;

cout<<"swap1: y="<<y<<endl;

}

void swap2(int *x, int *y)

{

int tmp;

tmp=*x;

*x=*y;

*y=tmp;

cout<<"swap2: x="<<*x<<endl;

cout<<"swap2: y="<<*y<<endl;

}

void swap3(int &x,int &y)

{

int tmp = x;

x = y;

y = tmp;

cout<<"swap3: x="<<x<<endl;

cout<<"swap3: y="<<y<<endl;

}

//把swap3独立出来, 那么swap2与swap3的效果就是一样的:

#include <iostream.h>

void swap3(int &x,int &y);                // (双向)引用传递, 在C++语言中使用(因为引用是C++的概念)

int main()

{

int a=5,b=10;

swap3(a,b);

cout<<"a="<<a<<endl;

cout<<"b="<<b<<endl;

return 0;

}

void swap3(int &x,int &y)

{

int tmp = x;

x = y;

y = tmp;

cout<<"swap3: x="<<x<<endl;

cout<<"swap3: y="<<y<<endl;

}

● 空类型函数

空类型函数: 凡不要求返回值的函数都应定义为空类型 & auto, 静态局部变量

#include<iostream.h>

void AddOne()        //形式参数列表为空, 这样就定义了不需要参数的函数,并且, 这个函数不要求返回值, 所以应定义为空类型

{

auto int a=1;

a+=1;

cout<<a<<endl;

}

int main()

{

cout<<"第一次调用:"<<endl;

AddOne();

cout<<"第二次调用:"<<endl;

AddOne();

return 0;

}

//上面的空类型函数也可以写成:

int AddOne()

{

auto int a=1;

a+=1;

cout<<a<<endl;

return 0;

}

//但为了降低程序出错的几率,凡不要求返回值的函数都应该定义为空类型,所以最好不要这样定义

#include<iostream.h>

void AddOne()    //函数声明/函数原型, 如果有形参,要写形参类型和形参(形参可省略)

void AddOne()

{

static int a=1;

a+=1;

cout<<a<<endl;

}

int main()

{

cout<<"第一次调用:"<<endl;        //第一次调用后,虽然变量a的作用域和上例中的auto变量a一样,即都是在AddOne函数体类,但此时a保留了此次调用后留下的值

AddOne();

cout<<"第二次调用:"<<endl;

AddOne();

return 0;

}

//在上面的程序中, 子函数的定义在主函数上面, 如果被定义在主函数下面, 那么在主函数上面要就要有函数声明(function declaration)/函数原型(function prototype), 如:

#include<iostream.h>

int main()

{

cout<<"第一次调用:"<<endl;        //第一次调用后,虽然变量a的作用域和上例中的auto变量a一样,即都是在AddOne函数体类,但此时a保留了此次调用后留下的值

AddOne();

cout<<"第二次调用:"<<endl;

AddOne();

return 0;

}

void AddOne()

{

static int a=1;

a+=1;

cout<<a<<endl;

}

● 返回值为空(void)类型的函数不能进行赋值和传值

返回值为空(void)类型的函数不能进行赋值和传值

//有如下空函数:

void show_index()

{

int index=10;

cout<<"Index is:"<<index<<end;

}

//下面的操作时不允许的

i=show_index();    //,非法语句, 返回值为空的函数不能进行赋值

set_index(show_index);    //非法语句,返回值为空的函数不能进行值传递

● 空函数

空函数: 没有参数和返回值, 函数的作用域也为空

void set_work_space() {}    //作用是在编程的开始阶段, 在将来准备扩展功能的地方写上一个空函数, 先占一个位置

int main()

{

set_work_space()

return 0;

}

● 自定义并调用可变参数函数

#include <iostream>

#include <STDARG.H> //需要包含该头文件

using namespace std;

void OutputInfo(int num,...)                        //定义一个省略号参数的函数

{

va_list arguments;                            //定义va_list类型变量

va_start(arguments,num);

while(num--)                                //读取所有参数的数据

{

char* pchData = va_arg(arguments,char*);    //获取字符串数据

int iData = va_arg(arguments,int);            //获取整型数据

cout<< pchData << endl;                    //输出字符串

cout << iData << endl;                        //输出整数

}

va_end(arguments);

}

void main()

{

OutputInfo(2,"Beijing",2008,"Olympic Games",2008);    //调用OutputInfo函数

}

● 三种函数调用

一般函数调用, 函数的嵌套调用, 函数的递归调用

● 嵌套调用

嵌套调用: 在自定义函数中调用其它自定义函数

注意: 在C/C++语言中, 函数的定义都是互相平行、独立的,也就是说,即在定义函数时,一个函数体内不能定义另一函数;即嵌套定义是不允许的,但嵌套调用是允许的,即在一个函数体内可以调用另一函数,如我们常见的在main()函数内调用另一函数。

//函数嵌套调用的简单案例

#include <iostream.h>

void show_message()

{

cout<<"The show_message function"<<endl;

}

void display()

{

show_message();    //嵌套调用, 即在子函数display()中调用另一个子函数show_message()

}

int main()

{

display();    //主函数调用子函数display(), 子函数display()调用另一子函数show_message()

return 0;

}

一般函数调用:

函数的嵌套调用:

//函数嵌套调用的复杂案例

#include <stdio.h>

int dif(int x,int y,int z);

int max(int x,int y,int z);

int min(int x,int y,int z);

void main()

{

int a,b,c,d;

scanf("%d%d%d",&a,&b,&c);

d=dif(a,b,c);

printf("Max-Min=%d\n",d);

}

int dif(int x,int y,int z)

{

return max(x,y,z)-min(x,y,z);

}

int max(int x,int y,int z)

{

int r;

r=x>y?x:y;

return(r>z?r:z);

}

int min(int x,int y,int z)

{

int r;

r=x<y?x:y;

return(r<z?r:z);

}

● 递归调用

函数直接或间接的调用自身叫函数的递归调用, 即递归可以分为直接递归调用和间接递归调用。

  1. 直接递归调用:是在调用函数的过程中又调用该函数本身;


  1. 间接递归调用:是在调用f1()函数的过程中调用f2()函数,而f2()中又需要调用f1()。


注意:

① 递归一定要有出口。

② 递归次数不宜过多,否则可能引起堆栈溢出。

③ 无限循环不一定会崩溃, 但如果函数的递归没有终止条件, 系统会崩溃.

#include <stdio.h>

void func(int n)

{

if (n > 0)

{

func(n - 1); // 这一语句是func()函数运行的第一步,当一次调用的函数运行结束时,系统将释放这次调用时所占用的存储单元,程序的执行流程返回到上一层的调用点,同时取用当初进入该层时函数中的变量(在函数体里面)和形参所占用的存储单元中的数据.

// 递推过程(剥卷心菜):func(10)→func(9)……func(1)

// 回归过程(合卷心菜):1→2→……10

printf("n=%d\n", n);

}

else

printf("n is less than or equal to 0.\n");

}

void main()

{

func(10);

}

#include <stdio.h>

void func(int n)

{

if (n > 0)

{

printf("n=%d\n", n);

func(n - 1);

}

else

printf("n is less than or equal to 0.\n");

}

int main(void)

{

func(-10);

func(0);

func(10);

return 0;

}

● 分析问题的两种方法:递推(迭代)和递归

分析问题的两种方法:递推(迭代)和递归

There are two approaches to writing repetitive algorithms: recursion and iteration (迭代和递归).

①    递归是重复调用函数自身实现循环。

②    而迭代与普通循环的区别是:循环代码中参与运算的变量同时是保存结果的变量,当前保存的结果作为下一次循环计算的初始值。

版本一:

● 递推:从一个已知的事实出发,按一定的规律推出下一个事实。

通常利用迭代公式法,通过循环结构实现,循环的终值是问题的结果。

● 递归:从要求的结果出发,归纳出后一个结果和前一个结果存在的关系,直到一个已知值(初值)为止(即反推法)。

这样我们就能设计一个函数(递归函数),使它不断使用下一级值调用自身,直到一个已知值(递归出口)。

版本二:

递归是首先自顶向下逐步拓展计算需求,最后自底向上计算, 即由f(n)拓展到f(1),再由f(1)逐步算回f(n)

迭代是直接自下向顶运算,由f(1)算到f(n)。

版本三:

递归(recursion): Any procedure(A) which, while being executed, either calls itself or calls another procedure (B),which in turn calls procedure(A).过程(A)执行时, 或调用其自身,或调用另一过程(B),而(B)又调用过程(A), 这种进程(process)称为递归。

经典案例: 阶乘, 汉诺塔, Fibonacci数列

迭代(iteration): a. The process of repeating a set of instructions a specified number of times or until a specific result is achieved.

重复一套指令的执行过程,执行特定的次数或直到得到一个特定的结果

b. One cycle of a set of instructions to be repeated: After ten iterations, the program exited the loop. 一个会被反复执行一套指令的循环.

加到100

int v=1;

for(i=2;i<=100;i++)

{

v=v+i;

}

● 函数递归典型案例1: n的阶乘

递推法

#include<stdio.h>

main()

{

int m=1,i,n;

scanf("%d",&n);

for(i=1;i<=n;i++)

m=m*i;

printf("the result is %10d\n",m);

}

递归法

递归函数设计的一般形式是:

//形式一

递归函数名f(参数n,……)

{

if(n==初值)

return…;

else

return含f(n-1)的表达式;

}

#include <stdio.h>

int fac(int n)

{

if(n==0||n==1)

return 1;/*递归出口*/

else

return fac(n-1)*n; /*递归公式*/

}

main()

{

int n, s;

scanf("%d",&n);

s=fac(n);

printf("%d! =%15d\n",n,s);

}

//形式二

递归函数名f(参数n,……)

{

定义一个保存结果的变量t;

if(n==初值)

结果(t)=…;

else

结果(t)=含f(n-1)的表达式;

return(返回结果(t));

}

#include <stdio.h>

int fac(int n)

{

int t;    //定义一个保存结果的变量t;

    if(n==0||n==1)

t=1;/*递归出口*/

    else

t=fac(n-1)*n; /*递归公式*/

return(t);

}

main()

{ int n, s;

scanf("%d",&n);

s=fac(n);

printf("%d! =%15d",n,s);

}

递归程序分两个阶段执行:

调用:欲求fac(n)→先求fac(n-1)→fac(n-2) → … → fac(0)

若fac(0)已知,回推结束。

欲求fac(3) →fac(2) →fac(1) →fac(0)

,回推结束。

回推:已知fac(0)→可求出fac(1)→fac(2)→ … → (n)

已知fac(0)→可求出fac(1)→fac(2) →fac(3)

次,递归调用了3次(考虑n=0的情况),到终止条件才有确定的值,然后再递推出每一次调用的值,最后得到所求的结果。

  • 另外一个图示(不考虑n=0的情况):

int fact(int n)

{

if(n<=1)

return 1;

else

return n*fact(n-1);

}

● 函数递归典型案例2: Fibonacci数列问题(求前12项之和)

,610,987,1597,2584,4181,6765,10946,17711,28657,46368...

项是0,第1项是第一个1。这个数列从第2项开始,每一项都等于前两项之和。

在数学上,斐波纳契数列以如下被以递归的方法定义:

//方法1: 用循环结构来实现

#include <stdio.h>

void main()

{

long int f1,f2;

int i;

f1=1;

f2=1;

for(i=1;i<=20;i++)

{

printf("%12ld %12ld",f1,f2);

if(i%2==0)

printf("\n");

f1=f1+f2;

f2=f2+f1; //每次循环打印两个数字

}

}

//方法2: 递归法

#include<stdio.h>

int fun(int n)

{

if(n==1||n==2)

return 1;

if(n>2)

return (fun(n-1)+fun(n-2));

}

void main()

{

int i;

for(i=1;i<=20;i++)

{

printf("%8d",fun(i));

if(i%5==0) //这两句是用来换行

printf("\n");

}

}

● 函数递归典型案例3: 反向输出一个整数(非数值问题)

//方法1:用循环结构来实现

#include<stdio.h>

main()

{

int n;

scanf("%d",&n);

if(n<0)

{

n=-n;

printf("-");    //如果n>=0, 这个符号就不会打印出来

}

while(n!=0)

{

printf("%d", n%10);

n=n/10;

}

printf("\n");

}

:用递归函数来实现

/* 将反向输出一个正整数的算法归纳为:

if(n为一位整数)

输出n;

else

{

输出n的个位数字;

对剩余数字组成的新

整数重复"反向输出"

操作;

} */

#include<stdio.h>

void main()

{

void printn(int x);

int n;

printf("Input n=");

scanf("%d",&n);

if(n<0)

{

n=-n;

putchar('-');

}

printn(n);

printf("\n");

}

void printn(int x) /*反向输出整数x*/

{

if(x>=0 && x<=9) /*若x为一位整数*/

printf("%d",x); /*则输出整数x*/

else /*否则*/

{

printf("%d",x%10); /*输出x的个位数字*/

printn(x/10);

/*将x中的个位数字去掉,形成新的x后,继续递归操作*/

}

}

● 函数递归典型案例4: 汉诺塔(河内塔)问题

假设: 塔A有n个盘子

已知条件:若只有一个盘子,则是直接从A移到C(递归出口)

算法设计如下:

  • 第一步:把n-1个盘子依照题目中的规则从塔A(源塔)借助于塔C(中间塔)搬到塔B(目标塔)。
  • 第二步:将剩下的一只盘(也就是最大的一只)直接从塔A(源塔)搬到那个仍然空着的塔C(目标塔)。
  • 第三步:再次将B塔(源塔)上的n-1个盘子借助于塔A(中间塔) 搬到塔C(目标塔)。这一步是没有问题的,因为C塔上仅有一只最大的盘。

函数hanoi( int n, int a, int b, int c)设计:

1. 如果(n==1) 则A→C;

(1) 调用函数hanoi(n-1,a,c,b);

(2) a→c;

(3) 调用函数hanoi(n-1,b,a,c);

#include<stdio.h>

void hanoi(int n,char a,char b,char c)

{

if(n==1) printf("%c--->%c\n",a,c);

else

{

hanoi(n-1,a,c,b);

printf("%c--->%c\n",a,c);

hanoi(n-1,b,a,c);

}

}

main()

{

int m;

printf("Input the number of disks:");

scanf("%d",&m);

printf("The steps to moving%3d disks:\n",m);

hanoi(m,'A','B','C');

}

● 重载函数

重载函数: 多个函数的函数名相同, 但参数类型或参数个数不同(不是返回值类型不同)

#include <iostream>

using namespace std;

int Add(int x ,int y)                //定义第一个重载函数

{

cout << "int add" << endl;    //输出信息

return x + y;                //设置函数返回值

}

double Add(double x,double y)        //定义第二个重载函数

{

cout << "double add" << endl;    //输出信息

return x + y;                //设置函数返回值

}

int main()

{

int a = Add(5,2);            //调用第一个Add函数

float b = Add(10.5,11.4);    //调用第二个Add函数

cout<<a<<endl;

cout<<b<<endl;

return 0;

}

● 内联函数

内联函数(inline function): 定义了一个内联函数后, 编译器会在调用该内联函数的地方展开这个函数的副本(copy), 这样可以减少函数调用带来的开销(在程序所在文件内移动指针寻找被调用函数地址带来的开销)

#include<iostream.h>

inline int integer_add (int x,int y);    //声明该函数为内联函数

void main()

{

int result=integer_add(5, 10);

cout<<result<<endl;

}

int integer_add(int x,int y)    //也可以写成inline int integer_add(int x,int y),表明定义了一个内联函数

{

return x+y;

}

(C/C++学习笔记) 十. 函数的更多相关文章

  1. python3.4学习笔记(十五) 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    python3.4学习笔记(十五) 字符串操作(string替换.删除.截取.复制.连接.比较.查找.包含.大小写转换.分割等) python print 不换行(在后面加上,end=''),prin ...

  2. python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL

    python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL实战例子:使用pyspider匹配输出带.html结尾的URL:@config(a ...

  3. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  4. Go语言学习笔记十: 结构体

    Go语言学习笔记十: 结构体 Go语言的结构体语法和C语言类似.而结构体这个概念就类似高级语言Java中的类. 结构体定义 结构体有两个关键字type和struct,中间夹着一个结构体名称.大括号里面 ...

  5. Matlab学习笔记 figure函数

    Matlab学习笔记 figure函数 matlab中的 figure 命令,能够创建一个用来显示图形输出的一个窗口对象.每一个这样的窗口都有一些属性,例如窗口的尺寸.位置,等等.下面一一介绍它们. ...

  6. python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例

    python3.4学习笔记(十四) 网络爬虫实例代码,抓取新浪爱彩双色球开奖数据实例 新浪爱彩双色球开奖数据URL:http://zst.aicai.com/ssq/openInfo/ 最终输出结果格 ...

  7. matlab学习笔记 bsxfun函数

    matlab学习笔记 bsxfun函数 最近总是遇到 bsxfun这个函数,前几次因为无关紧要只是大概看了一下函数体去对比结果,今天再一次遇见了这个函数,想想还是有必要掌握的,遂查了些资料总结如下. ...

  8. Learning ROS for Robotics Programming Second Edition学习笔记(十) indigo Gazebo rviz slam navigation

    中文译著已经出版,详情请参考:http://blog.csdn.net/ZhangRelay/article/category/6506865 moveit是书的最后一章,由于对机械臂完全不知,看不懂 ...

  9. python3.4学习笔记(十八) pycharm 安装使用、注册码、显示行号和字体大小等常用设置

    python3.4学习笔记(十八) pycharm 安装使用.注册码.显示行号和字体大小等常用设置Download JetBrains Python IDE :: PyCharmhttp://www. ...

随机推荐

  1. Oracle和MySQL的对比

    一.概述 1.1 Oracle 1.1.1 优点 开放性:Oracle 能所有主流平台上运行(包括 windows)完全支持所有工业标准采用完全开放策略使客户选择适合解决方案对开发商全力支持: 可伸缩 ...

  2. 【配置、开发】Spark入门教程[2]

    本教程源于2016年3月出版书籍<Spark原理.机制及应用> ,在此以知识共享为初衷公开部分内容,如有兴趣,请支持正版书籍. Spark为使用者提供了大量的工具和脚本文件,使得其部署与开 ...

  3. java对象在内存的大小

    前言 一直以来,对java对象大小的概念停留在基础数据类型,比如byte占1字节,int占4字节,long占8字节等,但是一个对象包含的内存空间肯定不只有这些. 假设有类A和B,当new A()或者n ...

  4. The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Path 解决方法

    项目忽然出现 The superclass "javax.servlet.http.HttpServlet" was not found on the Java Build Pat ...

  5. ASCII 、UTF-8、Unicode都是个啥啊,为啥会乱码啊?

    因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才能处理.最早的计算机在设计时采用8个比特(bit)作为一个字节(byte),所以,一个字节能表示的最大的整数就是255(二进制1111 ...

  6. go语言 变量类型

    package main import "fmt" func main() { //这是我们使用range去求一个slice的和.使用数组跟这个很类似.创建数组 nums := [ ...

  7. 使用 dplyr 管道操作处理数据框

    关于数据操作的另一个流行的包是dplyr,它发明了一种数据操作语法.dplyr 扩展包并没有使用构建子集函数([ ]),而是定义了一系列基础的变形函数作为数据操作模块,并且引入了一个管道操作符,利用管 ...

  8. [ios]ios读写文件本地数据

    参考:http://blog.csdn.net/tianyitianyi1/article/details/7713103 ios - Write写入方式:永久保存在磁盘中.具体方法为:第一步:获得文 ...

  9. c++ primer plus 第三章 课后题答案

    #include<iostream> using namespace std; int main() { ; int shen_gao; cout <<"Please ...

  10. Codeforces 909C - Python Indentation

    909C - Python Indentation 思路:dp. http://www.cnblogs.com/Leohh/p/8135525.html 可以参考一下这个博客,我的dp是反过来的,这样 ...