📄 第13章 函数(二).htm
字号:
<P> </P>
<P>为什么代码二只输出了一行?原因正是因为代码中标成红色的return;当函数执行到return;后,函数就结束了。后面的代码等于白写。这里只是为了突出return的作用才故意这样写。</P>
<P>一个函数没有return;语句,也可以自然地结束,比如上面的代码一,当在屏幕上打印完第三行后,函数体内的代码也没了,所以函数自然就结束了,为什么还要return语句呢?</P>
<P>结合流程控制语句和return 语句,我们可以控制一个函数在合适的位置返回,并可返回合适的值。</P>
<P>下面的函数实现返回二数中的较大者:</P>
<P> </P>
<P>int max(int a, int b)</P>
<P>{</P>
<P> if(a > b)</P>
<P> return a;</P>
<P> return b;</P>
<P>}</P>
<P> </P>
<P>这个函数有两个return;但并不是说它会返回两次。而是根据条件来执行不同的返回。执行以下面代码来调用上面的函数:</P>
<P>int c = max(10,7); </P>
<P>得到的结果将是c等于10。</P>
<P> </P>
<P>这个例子也演示了return 后面可以接一个表达式,然后将该表达式的值返回。</P>
<P> </P>
<P>请大家想一想调用max(10,7)时,max函数中哪一行的return语句起作用了?想不出来也没关系,我们下一节将通过调试,看最终走的是哪一行。</P>
<P> </P>
<P>关于return的最后几句话是:</P>
<P>1、有些函数确实可以不需要return,自然结束即可,如上面的OutputSomething();</P>
<P>2、有些人习惯为return的返回值加一对(),如: return (a); 这样写和 return
a;完全一样。当然,在某些特殊的情况下,一对()是必要的。</P>
<P>3、一个函数是void类型时,return不能接返回,这时return仅起结束函数的作用。</P>
<P>4、记得return 接的是一个表达式,可以是一个立即数,一个变量,一个计算式,前面我们就看到 return
a+b;的例子。 return 甚至也可以接一个函数。</P>
<P> </P>
<H4><A name=13.1.3>13.1.3</A> 跟踪函数</H4>
<P>结合本小节的最后一个例子,我们来学习如何跟踪一个函数。同时我们也将直观地看到return的作用。</P>
<P> </P>
<P>我们一直说F7,F8都是单步运行,下面的例子,二者的区别就表现出来了。</P>
<P>F7和F8都是单步跟踪,让代码一行行运行,但如果代码调用一个函数,那么,按F8将使调试器直接完成该函数的调用,而按下F7,调试器将进入该函数的内部代码。</P>
<P> </P>
<P><B>例一:</B>调试函数</P>
<P> </P>
<P>新建一个控制台的工程,然后加入以下黑体部分的代码。</P>
<P>//---------------------------------------------------------------------------</P>
<P><B>#include <iostream.h></B></P>
<P>#pragma hdrstop</P>
<P>//---------------------------------------------------------------------------</P>
<P><B>int max(int a, int b)</B></P>
<P><B>{</B></P>
<P><B> if(a > b)</B></P>
<P><B> return a;</B></P>
<P><B> return b;</B></P>
<P><B>}</B></P>
<P>//---------------------------------------------------------------------------</P>
<P>#pragma argsused</P>
<P>int main(int argc, char* argv[])</P>
<P>{</P>
<P><B> int c = max(10,7);</B></P>
<P><B> cout << c << endl;</B></P>
<P> </P>
<P><B> getchar();</B></P>
<P> return 0;</P>
<P>}</P>
<P>//---------------------------------------------------------------------------<BR></P>
<P>并在图中所示行加上断点:</P>
<P><IMG height=59 src="第13章 函数(二).files/ls13.h1.gif" width=238
border=0></P>
<P> </P>
<P>现在按F9运行,程序在断点处停下,然后请看准了F7键,按下,发现在我们跟进了max()函数:</P>
<P><IMG height=68 src="第13章 函数(二).files/ls13.h2.gif" width=214
border=0></P>
<P>现在继续按F7或F8键,程序走到:if(a > b)
这一行,然后请将鼠标分别移到该行的a和b上,稍停片刻出现的浮动提示将显示a或b的当前值,相信你会明白很多,至少,你能知道程序下一步何去何从。看一看你想对了没有,再按一次F8或F7:</P>
<P><IMG height=71 src="第13章 函数(二).files/ls13.h3.gif" width=163
border=0></P>
<P> </P>
<P>现在程序即将运行return语句!再按一次F7或F8,再想一想程序将何去何从?</P>
<P> </P>
<P><IMG height=111 src="第13章 函数(二).files/ls13.h4.gif" width=275
border=0></P>
<P>现在,你若是再说不明白 return 在函数内的作用,就有点过份了吧?</P>
<P> </P>
<P>下面大家照我说的继续做两次实验:</P>
<P>第一,重做这个实验,但在第一次需要按F7处,改为按F8,看看事情起了什么变化?</P>
<P>第二,将代码中的: int c = max(10,7); 改为: int c = max(7,10);
然后重做这个实验,看看这回走的是哪一行的return 语句?</P>
<P> </P>
<P>现在我们明白,在跟踪的过程,如果当前代码调用了一个函数,而你想进入这个函数跟踪,最直接的方法就是在调用函数的代码处按F7。</P>
<P>而关于F8与F7键所起的作用,名称为:F7单步进入();F8单步越过。它们分别对应于主菜单上 Run 下的 Trace Into 和 Step
Over。如果当前行代码并没有调用函数,则二者的功能完全一样。以后我们讲到无区分的单步跟踪时,将只说按F8。</P>
<P> </P>
<P>如果你需要频繁地跟踪某一函数,这种方法并不方便,你可以在设置断点,直接设置在那个函数的定义代码上。然后按F9,程序即可直接停在断点。比如,你可以将断点设置在这一行:int
max(int a, int b)。</P>
<P> </P>
<H3><A name=13.2>13.2</A> 函数的参数</H3>
<P> </P>
<P>讲完函数的类型及返回值,我们来看函数另一重点及难点:参数。</P>
<P>不知上一章关于“修理工需要一台电视”的比喻,有没有在一定程度上帮助大家理解参数对于一个函数的作用。那时我们只是要大家从概念上明白:参数是调用者给出去的,被调用进接来过使用的数据,就像我们给修理工一台电视,供也修理一样。你只有明白了这点,才可以在下面继续学习参数的具体知识点;否则你应该复习<A
href="http://www.d2school.com/bcyl/bhcpp/newls/ls12.htm">上一章</A>。</P>
<P> </P>
<H4><A name=13.2.1>13.2.1</A> 形参和实参</H4>
<P> </P>
<P>隔壁小李开了家服装店,在往服装上贴价钱标签时,小李突发奇想:他决定直接往衣服上贴上和价钱相应的钞票!比如这条裤子值100元,小李就往贴一张百元大钞……</P>
<P>尽管我们无法否认小李是一个非常具有创意的人,但听说最近他一直在招保安,才10来平方的小店里,挤满了一堆保安,不干别的事,就盯着那些贴在衣服上的钱。</P>
<P>这当然只是一个笑话……</P>
<P> </P>
<P>上一章我们说过,一个函数它需要什么类型的参数,需要多少参数,这都由函数本身决定。这就像一件商品需要多少钱,是由商人来决定,商人认为某件衣服需要100元,他就往上面贴个写着"¥100"价钱的标签,而一张真正百元钞票。</P>
<P> </P>
<P>函数也一样,它需要什么样的参数?这需要在声明和定义时写好。</P>
<P><B>所以,所谓的形参就是:函数在声明或定义时,所写出的参数定义。</B></P>
<P> </P>
<P>比如有这么一段代码:</P>
<P> </P>
<P><IMG height=295 src="第13章 函数(二).files/ls13.h5.gif" width=226
border=0></P>
<P> </P>
<P>由于形参只是形式上参数,所以在声明一个函数时,你甚至可以不写形参的变量名:</P>
<P>如<B>声明</B>某个函数:</P>
<P>int max(int a, int b);</P>
<P>你完全可以这么写:</P>
<P>int max(int ,int );</P>
<P> </P>
<P> </P>
<P>现在再说<B>实参:实际调用时,传给函数的实际参数,是为实参。</B>请参看上图有关“调用”函数时的参数。</P>
<P> </P>
<H4><A name=13.2.2>13.2.2</A> 参数的传递方式</H4>
<P> </P>
<P>参数是调用函数的代码,传给函数的数据,在C,C++中,参数有两种传递方式:传值方式和传址方式。这两个名词分别指:传递“参数的值”和传递“参数的地址”。</P>
<P> </P>
<H5><A name=13.2.2.1>13.2.2.1</A> 传值方式</H5>
<P> </P>
<P>如果你是第一次学习程序语言,下面代码的执行结果可能让你出乎意料。</P>
<P> </P>
<P><B>例二:</B>传值方式演示</P>
<P> </P>
<P>//定义函数F:</P>
<P>void F(int a)</P>
<P>{</P>
<P> a = 10; //函数F只做一件事:让参数a等于10</P>
<P>}</P>
<P> </P>
<P>int main(int argc, char* argv[])</P>
<P>{</P>
<P> //初始化a值为0: </P>
<P> int a = 0;</P>
<P> </P>
<P> //调用函数F:</P>
<P> F(a);</P>
<P> </P>
<P> //输出a的结果:</P>
<P> cout << a << endl;</P>
<P>}</P>
<P> </P>
<P>想一想,屏幕上打出的a的值是什么? 如果你猜“10”,呵呵,恭喜你猜<B>错</B>了。猜错了是好事,它可以加深你对本节内容的记忆。</P>
<P>如果你不服,立即打开CB将上面代码付诸实际,然后查看结果,那就更是好事!</P>
<P>正确答案是:a打出来将是“0”。</P>
<P><IMG height=70 src="第13章 函数(二).files/ls13.h6.gif" width=443
border=0></P>
<P> </P>
<P>代码不是明明将参数a传给函数F了吗?</P>
<P>而函数F不是明明让传来的a等于10了吗?</P>
<P>为什么打出的a却还是原来的值:0呢?</P>
<P> </P>
<P>这就是C,C++传递参数的方法之一:值传递。它是程序中最常见的传递参数的方法。</P>
<P> </P>
<P><B>传值方式:向函数传递参数时,先复制一份参数,然后才将复制品传给参数</B>。这样,函数中所有对参数的操作,就只是在使用复制品。不会对改变传递前的参数本身。</P>
<P> </P>
<P>我曾经说过(不是在课程说的),你要学习编程,可以没有任何编程基础,但你至少会要对普通的电脑的操作很熟练。是该考一考你的电脑操作水平了。</P>
<P> </P>
<P>以下是某用户在电脑上的操作过程,请仔细阅读,然后回答问题。</P>
<P> </P>
<P>操作一:用户在C盘上找一个文本文件;</P>
<P>操作二:用户使用鼠标右键拖动该文件到D盘,松开后,出现右键菜单,用户选择“复制到当前位置”,如图:</P>
<P><IMG height=87 src="第13章 函数(二).files/ls13.h10.gif" width=194
border=0></P>
<P>操作三:用户双击打开复制到D盘的该文件,进行编辑,最后存盘。</P>
<P> </P>
<P>请问:C盘上的文件内容是否在该过程受到修改?</P>
<P> </P>
<P>答案:不会,因为D盘文件仅是C盘文件的复制品,修改一个复制文件不会造成原文件也受到改动。</P>
<P> </P>
<P>前面关于a值为什么不会变,道理和此相同:a被复制了一份。然后才传递给函数F();</P>
<P> </P>
<P>请看参数传值方式的图解:</P>
<P> </P>
<P><IMG height=222 src="第13章 函数(二).files/ls13.h7.gif" width=319
border=0></P>
<P> </P>
<H5><A name=13.2.2.2>13.2.2.2</A> 传址方式</H5>
<P>即:传递参数地址</P>
<P> </P>
<P>“地址”?是啊,我们第三次说到它。请大家先复习一下以前的内容:</P>
<P><A
href="http://www.d2school.com/bcyl/bhcpp/newls/ls03.htm#3.4.1">第三章:3.4.1
内存地址</A></P>
<P><A href="http://www.d2school.com/bcyl/bhcpp/newls/ls05.htm#5.2">第五章:5.2
变量与内存地址</A> </P>
<P> </P>
<P>地址传递和值传递正好相反,这种方式可以将<B>参数本身</B>传给函数。从而,函数对参数的操作,将直接改变实参的值。</P>
<P>那么,如何才能指定让某个函数的某个参数采用“地址传送”的方式呢?方法很简单,只要在定义时函数时,在需要使用地址传送的参数名之前,加上符号:&。</P>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -