?? 第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;的例子?!eturn 甚至也可以接一個函數。</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 + -