函數的調用方法

來源:互聯網
上載者:User

0.概述

如果你能很清楚的理解下面這個程式,那麼本篇文章就不用看了。班門弄斧而已。

void GetMemory(char* p){p = new char[100];}void main(){char *str = "1234";GetMemory(str);strcpy(str, "hi"); //出錯! str = NULL!printf("%s\n", str);}

看不懂的話,可以好好學習一下。對於初學者來說,C/C++的參數傳遞的確讓人感覺非常困惑。“傳地址”,“傳值”,“傳引用”,“傳指標”等等,功能又似乎很相似,實在難以區分。本文就C/C++參數傳遞問題做以總結。

一.錯誤認識:

很多人把C/C++中函數的調用方式分為兩種:一種是傳值的,一種傳地址的。傳值比較常見,形參變實參不變。 而傳地址形參實參都變,而且有兩種實現方式:指標和引用。除了福士意義上的指標和引用的區別(一個可變一個不可變)外,其他視為一樣。

如果你也有這上面的錯誤認識,那你可要認真看下面的文章了。上面這段程式,主函數中調用GetMemory(str),只是把一個str指向的地址傳遞到子函數的參數p,即p指向str所指向的地址,你可以修改p指向值的內容,但你不可以讓p指向別的地方。比如你讓p指向了一個新的char數組。那麼主函數中的實參str指向的那個地址的值是不會改變的。:


如果你寫成以下這樣就可以了:

void GetMemory(char* &p){p = new char[100];}void main(){char *str;GetMemory(str);strcpy(str, "hi"); //OK!printf("%s\n", str);}

因為p是主函數str的一個引用,可以說就是str,所以你改變p的指向,也就是改變了str的指向。

所以我之前最大的錯誤就是對調用方式頭腦中的分類不正確。我所謂的指標傳地址仍舊屬於傳值調用。同時我也對指標和引用的區別搞的不清楚。

二:總結

1:類型

變數裡面存取的東西稱為值,我們可以存普通數值123,也可以123所在記憶體中的地址;可以存對象A,也可以存對象A在記憶體中的地址。所以值有兩種:普通值和地址值。用於存取普通值的變數就是我們經常說的變數,用於存取地址值的變數就是指標變數(地址值變數)。

C語言:有普通值變數,也有指標變數。

C++語言:有普通值變數,指標變數,還有引用。所謂引用就是給一個變數起個別名。同理,可以給普通值變數起別名,也可以給指標變數起別名。

JAVA語言:只有基本類型可以顯示的使用普通值變數,對象只能用引用(JAVA裡面的引用是指標變數)來使用。

例如:

C++:Mytype A;定義了一個Mytype對象,A就是一個普通變數。

Java:Mytype A;定義了一個指向Mytype對象的引用(指標)。

注意JAVA和C++的不同。

2:只有兩種調用方式:
(1): 傳值調用:分為傳值和傳地址。注意這句話中第一個“值”有兩種意思。
(2): 引用調用:同理,你引用的可以是值,可以是地址,可以使指標。

下面再檢驗一下是否過關吧!看下面代碼:

void Change(char *p){    *p = 'b';    p = NULL;}main(){    char a = 'a';    char* p = &a;    Change(p);    printf("%c\n", a);           //值a改變!}
三:代碼
/* * 對於所有的參數傳遞你都可以理解為把實參賦給形參。代碼中將以此理念講解。 * 首先C++的參數傳遞包括兩類:傳"值"和傳"引用"。C語言只有傳值,因為C語言沒有引用這個東西。 * 值有兩種:A.普通的值 B.地址 * 引用也有兩種:A.引用一個普通值 B.引用一個指標 * 注意區分以下測試 *///測試1:傳普通值void fun1(int value){    value = 10;}//測試2:傳地址值(俗稱指標傳遞方式,指標不就是一個地址麼,指標變數不就是一個可變地址麼)void fun2(int* value){    *value = 10;}//測試3:傳地址值void fun3(int* value){    value = new int(10);}//測試4: 傳地址值void fun4(int* value){    int a = 10;    value = &a;}//測試5: 傳引用void fun5(int &value){    value = 10;}//測試6: 傳引用void fun6(int* &value){    value = new int(10);}int main(){    //測試1調用    int v1 = 2;    fun1(v1); //相當於int value(形參:基本類型) = v(實參:基本類型);換句話說把數字2交給函數fun的形參,讓fun處理一些工作。當然不會造成value的改變了。    cout << v1 << endl;    //測試2調用    int v2 = 2;    fun2(&v2); //相當於int* value(形參:指標類型) = &v2(實參:一個地址);     cout << v2 << endl;//實參把他的地址交給形參value後,此時value為實參v2的地址。那麼對*value(value指向的內容)的修改,當然會導致實參的改變。    //測試3調用    int v3 = 2;    fun3(&v3); //相當於int* value(形參:指標類型) = &v3(實參:一個地址)    cout << v3 << endl;//此時value為實參v3的地址。可是函數fun3又讓value指向了一塊新開闢的地方(value = new int(10)); 那麼對這塊新開闢地方的修改                                  //當然不會影響到實參了。    //測試4調用    int v4 = 2;    fun4(&v4); //同測試3    cout << v4 << endl;    //測試5調用    int v5 = 2;    fun5(v5); //相當於int &value(形參:參考型別) = v5(實參:基本類型); 一個引用一旦被賦值就完全代表了他引用的變數。    cout << v5 << endl;//value此時就成了v5的另一個名字。對value的任何修改都會引起value的改變。    //測試6調用    int a = 2;    int *v6 = &a;    fun6(v6); //這個有難度啊。是引用調用,但是是一個指標類型的引用。上面是基本類型的引用。理解理解。    cout << *v6 << endl;    return 0;}
四. 疑惑

指標的用法非常靈活,引用其實就是一個常量指標,如int &p其實就是int* const p,一旦確定指向就不能再指向別的了。那麼完全可以不需要引用這種方式嗎?這就要從曆史的角度理解了。指標是C語言的一個十分重要的概念,而C++語言是C語言的的超集,當然可以使用指標了。而C++語言雖然可以使用指標,但是它並沒有像C語言中那樣重要,因為在C++語言中又引進了引用的概念,引用佔據了指標的一些作用,而使指標的功能相對地減弱了。
引用這個概念看起來更加簡單,使用起來不像指標那麼難,容易出錯。因此這個概念變得重要且被廣泛使用。到Java語言的時,引用被使用進來,可是Java中的引用變得更加靈活了,靈活的又像當年的指標一樣,可以指來指去。而且作為Java語言傳參的主體。如果希望只指向一次,那就加上const就行了。
這應該就是參數傳遞的發展淵源,似乎又繞回去了,不過使用起來更加簡化了。



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.