分类: C/C++
2009-04-21 23:25:30
函数的返回类型:函数返回值的类型.
return 语句只在函数内使用。它起到让函数停止运行,然后返回一个值的作用。
一个函数没有return;语句,也可以自然地结束,比如上面的代码一,当在屏幕上打印完第三行后,函数体内的代码也没了,所以函数自然就结束了,为什么还要return语句呢?
下面的函数实现返回二数中的较大者:
int max(int a, int b)
{
if(a > b)
return a;
return b;
}
这个函数有两个return;但并不是说它会返回两次。而是根据条件来执行不同的返回。执行以下面代码来调用上面的函数: int c = max(10,7); 得到的结果将是c等于10。
关于return的最后几句话是:
1、有些函数确实可以不需要return,自然结束即可;
2、有些人习惯为return的返回值加一对(),如: return (a); 这样写和 return a;完全一样。当然,在某些特殊的情况下,一对()是必要的。
3、一个函数是void类型时,return不能接返回,这时return仅起结束函数的作用。
4、记得return 接的是一个表达式,可以是一个立即数,一个变量,一个计算式,前面我们就看到 return a+b;的例子。 return 甚至也可以接一个函数。
----------------------------------------------------------------------------------
参数是调用函数的代码,传给函数的数据,在C,C++中,参数有两种传递方式:传值方式(它是程序中最常见的传递参数的方法)和传址方式(函数对参数的操作,将直接改变实参的值)。这两个名词分别指:传递“参数的值”和传递“参数的地址”。
“参数的传递方式”,“参数的传递过程”,方式和过程有何区别?中学时我对前桌的女生“有意思”,想给人家传递点信息,是往她家打个电话呢?还是来个“小纸条”?这就是“传递方式”的不同。我选择了后者。至于传递过程:刚开始时我把纸条裹在她的头发里,下课时假装关心地“喂,你的头发里掉了张纸……”。后来大家熟了,上课时我轻轻动一下她的后背,她就会不自在,然后在一个合适时机,自动把手别过来取走桌沿的纸条……这就是传递过程的不同吧?(以上故事纯属虚构)
程序是在内存里运行的。所以无论参数以哪一种方式传递,都是在内存中“传来传去”。在一个程序运行时,程序会专门为参数开辟一个内存空间,称为“栈”。栈所在内存空间位于整个程序所占内存的顶部(为了直观,我们将地址较小的内存画在示意图顶部,如果依照内存地址由下而上递增规则,则栈区应该在底部),如图:
当程序需要传递参数时,将一个个参数“压入”栈区内存的底部,然后,函数再从栈区一个个读出参数。
如果一个函数需要返回值,那么调用者首先需要在栈区留出一个大小正好可以存储返回值的内存空间,然后再执行参数的入栈操作。
假设有一函数:int AddTwoNum(int n1, int n2) 然后在代码某处调用:
....
int a = 1;
int b = 2;
int c = AddTwoNum(a,b);
当执行上面黑体部分,即调用函数的动作发生时,栈区出现下面的操作:
图中标明为返回值预留的空间大小是4个字节,当然不是每个函数都这个大小。它由函数返回值的数据类型决定,本函数AddTwoNum返回值是int类型,所以为4个字节。其它的a,b参数也是int类型,所以同样各占4字节大小的内存空间。
至于参数是a还是b先入栈,这依编译器而定,大都数编译器采用“从右到左的次序”将参数一个个压入。所以本示意图,参数b被先“压”入在底部,然后才是a。这样就完成了参数的入栈过程。根据前面讲的不同“传递方式”,被实际压入栈的数据也就不同。
一、如果是“传值”,则栈中的a,b就是“复制品”,对二者的操作,仅仅是改变此处栈区的内存,和调用处的实参:a,b毫不关联:
二、而在“传址”方式时,编译器会将调用处的a,b的内存地址写入栈区,并且将函数中所有对该栈区内存的操作,都转向调用处a,b的内存地址。请看:看起来二的图比一要复杂得多。其实实质的区别并不多。
在一图中,传给函数的是a,b的值,即1,2;
在二图中,传给函数的是a,b的地址,即:00129980,00129984。
“参数的传递过程”说到最后,还是和“参数的传递方式”纠缠在一起。我个人认为,在刚开始学习C++时,并不需要--或者甚至就是最好不要--去太纠缠语言内部实现的机制,而重在于运用。下面我们就来举一个使用“传址”方式的例子。
题目是:写一函数,实现将两个整型变量的值互换。
幸好实现它也非常的简单和直观。典型的方法是使用“第三者”你可能感到不解:交换两个变量的值,就让这两个变量自个互换就得了,比如小明有个苹果,小光有个梨子,两人你给我给你就好了啊,要小兵来做什么?
呵,你看吧:
int a = 1, b = 2;
//不要“第三者”的交换(失败)
a = b;
b = a;
好好看看,好好想想吧。当执行交换的第一句:a = b;时,看去工作得不错,a的值确实由1变成了2。然后再下去呢?等轮到b想要得到a的值时,a现在和b其实相等,都是2,结果b=a;后,b的值还是2.没变。
只好让“第三者”插足了……反正程序没有婚姻法。
int a = 1, b =2;
int c ; //“第三者”
//交换开始:
c = a;
a = b;
b = c;
程序代码区 |
存放函数编译成的二进制代码 |
全局数据区 |
存放定义的全局变量以及函数体中定义的静态变量 |
堆 |
是由程序支配的内存空间。在程序运行的初期,堆是一块空闲的区域,在程序运行过程中,可以用new在堆中动态申请空间,当用完了所申请的空间以后,就可以用delete释放这一块堆空间,然后这块空间就可以被重新利用了 |
栈 |
由系统使用的动态空间,在进行函数调用时,系统使用栈来存放传递给被调用函数的信息,并且在栈中为被调用函数的局部变量分配空间。当被调用函数执行结束时,为调用这个函数所分配的所有空间就会被系统自动释放。 |