C++ 函数参数传递:传值,传指针,传引用
PS:首先理解形參 ? 實參概念。形參是在函數定義的括號內定義的專用變量,它們的目的是保存按實參傳遞給它們的信息,實參被列在函數調用語句的括號內。
int func(int x)//x是形參
{return x*x;
}
int main(void)
{int a = 3;func(a);//a是實參return 0;
}
上面的代碼中,x是形參,a是實參。形參x是實參a的一個拷貝
1.C++ ?? 按值傳遞
采用按值傳遞的方式,當信息被傳遞給一個函數時,這意味著形參接收的是傳遞給它的值的副本。如果形參的值在函數內部被改變,那么它對原始實參是沒有影響的。
#include <iostream>
using namespace std;
// 函數聲明
void changeMe(int aValue);
int main()
{int number = 12;// 輸出number的值 此處輸出為 12cout << "In main number is " << number << endl;//調用changeMe()函數,將number中的值作為參數傳遞changeMe(number); //此處調用函數內部有一個輸出為 0// 調用函數之后,再次輸出number的值 此處輸出為 12cout << "Back in main again, number is still " << number << endl;return 0;
}
void changeMe(int myValue)
{//改變 myValue 的值為 0myValue = 0;//輸出 myValue的值 此處輸出為 0cout << "In changeMe, the value has been changed to " << myValue << endl;
}
程序輸出結果:
In main number is 12
In changeMe, the value has been changed to 0
Back in main again, number is still 12
當函數原型列出變量名稱和數據類型時,它使用的名稱只是虛擬名稱,編譯器實際上并不使用它們,并且不必在函數頭中使用一致的名稱。第 5 行中的 changeMe 函數原型和第 19 行中的 changeMe 函數頭都指定該函數具有一個 int 形參,但它們使用了不同的名稱。
并且,即使在 changeMe 函數中形參變量 myValue 已更改,實參 number 也不會被修改。這是因為 myValue 變量只包含了 number 變量的副本。只是這個副本被改變,而不是原來的。changeMe 函數無法訪問原始實參。圖 1 說明了形參變量在內存中的存儲位置與原始實參的存儲位置是分開的。
2.C++ ?? 指針傳遞
傳指針就是把實參的地址傳遞給函數。傳指針可以修改實參的值,在C++里也不會存在調用對象的拷貝構造函數的問題, 傳指針的效率比傳值要高。所以,如果需要修改實參的值,就不能傳值,而需要傳指針等。但是,傳指針比傳值復雜,指針計算一旦移動出了正常范圍,會造成程序的非法訪問等。
void func(int *x)//func采用了傳指針的形式
{*x = *x+1;printf("*x=%d\n", *x);
}
int main(void)
{int a = 0;func(&a);//把實參a的地址傳遞給了函數funcprintf("a=%d\n", a);return 0;
}
分析:傳指針可以修改實參的值。根據指針的定義,*x就是a,所以,*x=*x+1,即為a = a+1,所以上面的代碼輸出結果為:
*x=1
a=1
C/C++ 禁止在函數調用時直接傳遞數組的內容,而是強制傳遞數組指針
而對于結構體和對象沒有這種限制,調用函數時既可以傳遞指針,也可以直接傳遞內容;為了提高效率,我曾建議傳遞指針,這樣做在大部分情況下并沒有什么不妥,讀者可以點擊《C語言結構體指針》進行回顧。
在 C++ 中,我們有了一種比指針更加便捷的傳遞聚合類型數據的方式,那就是引用(Reference)。
3.C++ ? 引用傳遞
引用介紹參照博客https://blog.csdn.net/m0_37957160/article/details/104705220
前面講過,實參通常是通過值傳遞給函數的,這意味著形參接收的只是發送給它們的值的副本,它們存儲在函數的本地內存中。對形參值進行的任何更改都不會影響原始實參的值。然而,有時候可能會希望一個函數能夠改變正在調用中的函數(即調用它的函數)中的一個值,這可以通過引用傳遞的方式來完成。
我們知道,變量是可以保存數據的內存位置的名稱。當使用變量時,實際上就是訪問存儲在分配給它的內存位置的數據。引用變量是變量的另一個別名,它沒有自己的存儲數據的內存位置,它訪問的是另一個變量的內存位置。對引用變量作出的任何更改,實際上都是對它所引用的變量內存位置中存儲數據的更改。
當使用引用變量作為形參時,它將變為實參列表中相應變量的別名,對形參進行的任何更改都將真正更改正在調用它的函數中的變量。當以這種方式將數據傳遞給形參時,該實參被稱為按引用傳遞。
在定義或聲明函數時,我們可以將函數的形參指定為引用的形式,這樣在調用函數時就會將實參和形參綁定在一起,讓它們都指代同一份數據。如此一來,如果在函數體中修改了形參的數據,那么實參的數據也會被修改,從而擁有“在函數內部影響函數外部數據”的效果。
引用變量的定義方法和常規變量類似,但是其數據類型和名稱之間有一個 & 符號。例如,以下函數定義使形參 refVar 成為引用變量:
void doubleNum(int& refVar)
{refVar *= 2;
}
注意,變量 refVar 被稱為“對 int 的引用”。
該函數將 refVar 乘以 2,因為 refVar 是引用變量,所以該操作實際上將對作為實參傳遞給函數的變量執行。
具有引用形參的函數的原型也必須具有 & 符號。與函數頭一樣,它在數據類型和變量名之間。如果原型中省略了變量名,那么 & 符號將跟在數據類型后面。以下所有 doubleNum 函數的原型都是正確的:
void doubleNum(int &refVar);
void doubleNum(int& refVar);
void doubleNum(int &);
void doubleNum(int&);
注意,& 符號必須出現在使用引用變量作為形參的任何函數的原型和函數頭中。它不會出現在函數調用中。
#include <iostream>
using namespace std;
// Function prototype. The parameter is a reference variable.
void doubleNum(int SrefVar);
int main()
{int value = 4;cout << "In main, value is " << value << endl; //輸出4cout << "Now calling doubleNum..." << endl;doubleNum(value); cout << "Now back in main, value is "<< value << endl; //輸出4return 0;
}
void doubleNum (int SrefVar)
{refVar *= 2;
}
程序輸出結果:
In main, value is 4
Now calling doubleNum...
Now back in main, value is 8
此程序中的形參 refVar “指向”函數 main 中的 value 變量。當程序使用一個引用變量時,它實際上是使用它所引用或指向的變量,(引用變量實際上指向的是被它引用的變量)
當函數的目的是接收調用它的函數存儲在變量中的輸入值時,使用引用變量作為函數 形參特別有用。另外,引用形參還可以用于必須從函數發回多個值的情形。如果函數將計算并發回單個值,通常認為使用返回值的函數更合適,可以使用 return 語句返回值。
下面程序是對之前程序的修改。它添加了一個函數 getNum,該函數接收用戶的輸入并將其存儲在 userNum 中,但是,形參 userNum 是對 main 的變量 value 的引用,所以這是實際存儲輸入數據的位置。
#include <iostream>
using namespace std;//Function prototypes
void getNum(int &);
int doubleNum(int);int main()
{int value;// Call getNum to get a number and store it in valuegetNum(value);value = doubleNum(value); //調用函數后,將value變為24// Display the resulting numbercout << "That value doubled is " << value << endl; //最后輸出 24return 0;
}
void getNum(int &userNum)
{cout << "Enter a number: ";cin >> userNum; //輸入12
}
int doubleNum (int number)
{return number *2;
}
程序輸出結果:
Enter a number: 12
That value doubled is 24
注意,只有變量才能按引用傳遞。如果嘗試將非變量實參(例如常數、常量或表達式)傳遞到引用形參中,將導致錯誤。
如果一個函數有多個形參是引用變量,則必須在原型和函數頭中為每個形參使用 & 符號。以下是使用 4 個引用變量形參的函數的原型:
void addThree(int& num1, int& num2, int& num3, int& sum);
以下是函數定義:
void addThree(int& numl, int& num2, int& num3, int& sum)
{cout << "Enter three integer values: ";cin >> num1 >> num2 >> num3;sum = num1 + num2 + num3;
}
但是請注意,addThree 函數只需要一個引用形參 sum,其他 3 個形參可以通過值接收它們的實參,因為在此處的函數中沒有改變它們。
提示:應該僅在絕對需要時才使用引用變量。任何時候允許一個函數來改變函數之外的變量,其實都是在創建潛在的調試問題。
文章轉自C語言中文網:http://c.biancheng.net/view/2251.html
引用的本質:
在定義或聲明函數時,我們可以將函數的形參指定為引用的形式,這樣在調用函數時就會將實參和形參綁定在一起,讓它們都指代同一份數據。如此一來,如果在函數體中修改了形參的數據,那么實參的數據也會被修改,從而擁有“在函數內部影響函數外部數據”的效果。
總之:傳值不能修改實參,且如果是對象,效率較低;傳指針能夠修改實參,效率較高,但容易出錯;傳引用能夠修改實參,效率較高,而且不易出錯。
一個能夠展現按引用傳參的優勢的例子就是交換兩個數的值,如下所示:
#include <iostream>
using namespace std;void swap1(int a, int b);
void swap2(int *p1, int *p2);
void swap3(int &r1, int &r2);int main() {int num1, num2;cout << "Input two integers: ";cin >> num1 >> num2;swap1(num1, num2);cout << num1 << " " << num2 << endl; //輸出與輸入相同,因為值傳遞,不能改變原始數據cout << "Input two integers: ";cin >> num1 >> num2;swap2(&num1, &num2);cout << num1 << " " << num2 << endl; //輸出與輸入相反,指針傳遞可以改變原始數據cout << "Input two integers: ";cin >> num1 >> num2;swap3(num1, num2);cout << num1 << " " << num2 << endl; //輸出與輸入相反,因為引用傳遞,可以改變原始數據return 0;
}//直接傳遞參數內容
void swap1(int a, int b) {int temp = a;a = b;b = temp;
}//傳遞指針
void swap2(int *p1, int *p2) {int temp = *p1;*p1 = *p2;*p2 = temp;
}//按引用傳參
void swap3(int &r1, int &r2) {int temp = r1;r1 = r2;r2 = temp;
}
運行結果:
Input two integers: 12 34↙
12 34
Input two integers: 88 99↙
99 88
Input two integers: 100 200↙
200 100
本例演示了三種交換變量的值的方法:
1) swap1() 直接傳遞參數的內容,不能達到交換兩個數的值的目的。對于 swap1() 來說,a、b 是形參,是作用范圍僅限于函數內部的局部變量,它們有自己獨立的內存,和 num1、num2 指代的數據不一樣。調用函數時分別將 num1、num2 的值傳遞給 a、b,此后 num1、num2 和 a、b 再無任何關系,在 swap1() 內部修改 a、b 的值不會影響函數外部的 num1、num2,更不會改變 num1、num2 的值。
2) swap2() 傳遞的是指針,能夠達到交換兩個數的值的目的。調用函數時,分別將 num1、num2 的指針傳遞給 p1、p2,此后 p1、p2 指向 a、b 所代表的數據,在函數內部可以通過指針間接地修改 a、b 的值。我們在《C語言指針變量作為函數參數》中也對比過第 1)、2) 中方式的區別。
2) swap3() 是按引用傳遞,能夠達到交換兩個數的值的目的。調用函數時,分別將 r1、r2 綁定到 num1、num2 所指代的數據,此后 r1 和 num1、r2 和 num2 就都代表同一份數據了,通過 r1 修改數據后會影響 num1,通過 r2 修改數據后也會影響 num2。
從以上代碼的編寫中可以發現,按引用傳參在使用形式上比指針更加直觀。在以后的 C++ 編程中,我鼓勵讀者大量使用引用,它一般可以代替指針(當然指針在C++中也不可或缺),C++ 標準庫也是這樣做的。
?
總結
以上是生活随笔為你收集整理的C++ 函数参数传递:传值,传指针,传引用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PCL基础4:PCLVisualizer
- 下一篇: C++ 随笔