函式引數
一道簡單問題引發思考
keyword:
函式引數,傳值,傳址
abstract
函式引數的傳遞我們經常的使用,從基本型別到各個自定義的型別或型別的傳遞,不同的應用有著不同的使用方法,今天我們就來深入的討論一下有關函式引數傳遞方面比較細節的地方。
有這樣一道題
void getstring (char* p)
char* p = 0x0;
getstring(p);
cout << p <
可能很多人都知道這道題的答案,是的很簡單,字串指標依然為空,在試圖輸出的時候編譯器出錯。下面我們將整個過程分解成四個步驟來看一下整個過程中的各個變數在其生存週期過程中都幹了些什麼。
首先,初始化字元產指標
p指向如下語句:
char* p = 0x0
。如下圖所示:
接著,呼叫函式
getstring(p)
,但是在呼叫發生後還未進入函式體內部之前,編譯器為我們自動生成了乙個基於原引數的臨時的引數
_p,也就是他的副本,該臨時引數的值與原引數的值一樣,由於p等於
0故
-p也等於
0。如下圖所示:
然後,進行記憶體的申請和賦值操作,執行如下的語句:
p = new char[10];
strcpy(p,」world!」);
但其實上並不是我們看到的那樣,應該是如下的格式:
_p = new char[10];
strcpy(_p,」world!」);
所有的操作都不是針對於字串指標
p進行的,而是針對他的副本
_p進行的。如下圖所示:
最後,當函式返回後,臨時引數
_p也被刪除了,從而使得指向字串
」world!」
的區域丟失,無法再進行釋放,從而造成了記憶體洩露。
我們進一步將這個問題引伸,討論一下較為複雜的關於類的傳值操作,假設存在這樣乙個類:
class ca
~ca()
ca& operator = (const ca& other)
………
void print()
};
有如下的執行語句:
void testcase(caa)
caa(「hello!」);
testcase(a);
a. print();
你猜猜輸出的是什麼?是「
hello!」嗎?
,還是其他的什麼東西
,有的朋友可能已經知道正確的結果:程式出錯!是的,程式出錯,就出在
~ca()。
讓我跟蹤一下,明明
pstr
有資料但是為什麼在執行
delete pstr
是程式會丟擲異常呢?接下來我們將整個流程**化,看看到底都發生了什麼。
首先,第乙個執行語句就有很大的玄機:
caa(「hello!」)
,相當於執行了如下的幾步操作:
//c++
偽**
char noname = ;
注意:編譯器自動產生乙個匿名的字串
, 字串從進入其所在的函式(不必執行到該語句)就已經申請的儲存空間,並且其位址和內容不能改變,直道其所在的函式結束才消失。而不是在其所在的語句
caa(「hello!」)
結束後消失。
ca(char* _ noname)//
此處產生
noname
的副本_ noname;
在執行完
ca的建構函式後,「
hello
!」產生了乙個副本,由
a.pstr
指向它。執行結果如下圖:
然後我們看一下
testcase(a)
,同樣就像我們一開始**的值符串指標一樣,編譯器幫我們構造了乙個
a的副本我們暫且叫他
_a,在尚未進行
testcase
函式體內部程式之前的儲存是什麼樣的呢?我們看一下圖:
然後程式執行完畢,撤銷臨時變數
_a,調
_a的析構函式並刪除
pstr
,等一下!
_a.pstr
指向的正是編譯器產生的匿名陣列的內容,由於其在其所在的函式執行期內不可變,於是編譯器就會丟擲錯誤來,於是程式就此打住了。
其實解決方法很簡單,我們只需新增乙個拷貝建構函式就行了。
ca(const ca& other)
這樣的話,程式在進行
a的副本建立時,自動執行了副本的拷貝建構函式,然後由建構函式為其製作了乙個「
hello
」的副本,而這乙份副本是可以刪除的,程式在執行到析構函式時就不會出錯了。當然對原資料沒有產生任何的影響,完全是在被呼叫函式內部自生自滅。
其實,有很多的原因使得我們不贊成使用這種傳遞具體值的方式:首先從效率上而言,這種方式要進行自身的構造和析構,而構造和析構具有一定的時間和空間成本,從而使執行時的效率大大折扣;其次儘管我們知道它在被呼叫函式的任何修改都不會影響返回結果,但是我們還有更好的解決方法:只需為傳遞引數新增乙個簡單的
const
修飾符就可以解決這個問題,就像這樣「
const ca& a
」一樣問題就可以解決j。
一道演算法題,引發的思考
引言 有人問我這樣乙個問題,希望寫出 實現 有p0,p1兩點座標,組成乙個線段,求此線段與x點的的距離 我並不知道,如何完全的實現此功能,因為求點與線的公式,我記得是高中知識,但是我已經忘得差不多了,只是知道勾股定理算兩點間距離,直線方程有個斜率,如果給我時間去細想的話,應該可以理出頭緒,得到個寫此...
一道面試題引發的思考
首先我們給出這道面試題的 以及題目 lista new arraylist list.add 1 list.add 2 for string item list 問 上段 執行會報錯嗎?如果把 1 換成 2 會報錯嗎?為什麼?首先給出答案 上面這段 執行不會報錯。把 1 換成 2 再執行就會報錯。為...
java 與 一道小題引發的思考
第一眼看這個題,以為會編譯不通過,結果正確答案會輸出 true。ps 是乙個賦值運算子,賦給某個變數乙個具體的值。是乙個比較運算子 1 基本型和基本型進行 運算子的比較,直接比較兩個值 2 基本型和封裝型進行 運算子的比較,封裝型將會自動拆箱變為基本型後再進行比較 3 封裝型和封裝型進行 運算子的比...