C++中傳值、傳地址和傳引用究竟有哪些區(qū)別
傳引用定義
傳值與傳地址,相信大家都了如指掌了,在這里先介紹一下什么是引用?
引用不是新定義一個(gè)變量,而是給已存在變量取了一個(gè)別名,編譯器不會(huì)為引用變量開(kāi)辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。
說(shuō)白了,引用就是給變量起外號(hào),比如一個(gè)人可以有乳名,有學(xué)名,有筆名,其實(shí)就都是一個(gè)人而已。
例:林沖,江湖上人稱(chēng)“豹子頭"
類(lèi)型& 引用變量名(對(duì)象名) = 引用實(shí)體;
void TestRef()
{
int a = 10;
int& ra = a; //<====定義引用類(lèi)型
printf("%p\n", &a);
printf("%p\n", &ra);
}

可以看出a 和ra地址是一樣的,足以證明,引用就是變量本身。
注意:引用類(lèi)型必須和引用實(shí)體是同種類(lèi)型的
意思是:對(duì)象用 int 定義的,那么引用必須是 int&
引用特性
1. 引用在定義時(shí)必須初始化
#include<iostream>
using namespace std;
void TestRef()
{
int a = 10;
int& ra; // 該條語(yǔ)句編譯時(shí)會(huì)出錯(cuò)
int& ra = a;
int& rra = a;
printf("%p %p %p\n", &a, &ra, &rra);
}
int main()
{
TestRef();
return 0;
}

int ra&; // 不賦初值,會(huì)報(bào)錯(cuò)
2、一個(gè)變量可以有多個(gè)引用,一個(gè)人可以有多個(gè)外號(hào)
#include<iostream>
using namespace std;
void TestRef()
{
int a = 10;
int& ra = a;
int& rra = a;
printf("%p\n%p\n%p\n", &a, &ra, &rra);
}
int main()
{
TestRef();
return 0;
}

3、引用一旦引用一個(gè)實(shí)體,再不能引用其他實(shí)體,意思是,ra是 a 的引用后,就不能再引用別的對(duì)象
傳引用與傳值的區(qū)別
1、 傳值、傳引用返回的比較
傳值返回:
#include<iostream>
using namespace std;
int Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int ret=Add(1,2);
cout << "ret:" << ret << endl;
return 0;
}

注意: 返回時(shí),c會(huì)將自己的值,復(fù)制給一個(gè)臨時(shí)變量,ret接收的其實(shí)是c的拷貝,c在 Add 函數(shù)調(diào)用結(jié)束后,隨著棧幀的銷(xiāo)毀,而銷(xiāo)毀。
c的拷貝變量一般開(kāi)在,調(diào)用c所在函數(shù)的函數(shù)中,此例就是在main函數(shù)中開(kāi)辟,當(dāng)返回變量較小時(shí),業(yè)可能在寄存器中開(kāi)辟空間存放返回變量的拷貝
傳引用返回:
#include<iostream>
using namespace std;
int& Add(int a, int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret=Add(1,2);
cout << "ret:" << ret << endl;
return 0;
}
大家猜猜結(jié)果是什么呢?
是 3 嗎?

結(jié)果是隨機(jī)值,這是為什么呢?
因?yàn)榉祷氐氖?c 的引用,也就是 c本身,而 c 變量是存儲(chǔ)在棧幀中,隨著函數(shù)的結(jié)束,棧幀銷(xiāo)毀,c也隨著銷(xiāo)毀,空間釋放,這時(shí)就造成非法引用,值為隨機(jī)值。
那怎么辦呢?
不將c放到棧幀中就可以了,將c放到 靜態(tài)區(qū)
#include<iostream>
using namespace std;
int& Add(int a, int b)
{
static int c = a + b;
return c;
}
int main()
{
int& ret=Add(1,2);
cout << "ret:" << ret << endl;
return 0;
}


再來(lái)一個(gè)有趣的題,下面代碼的結(jié)果是什么呢?
#include<iostream>
using namespace std;
int& Add(int a,int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(5, 7);
cout << ret << endl;
return 0;
}
很多人會(huì)以為是 3 吧

結(jié)果是 12 ,可是并沒(méi)有輸出 Add(5,7) 。為什么會(huì)是12呢

調(diào)用Add(1,2)后,將結(jié)果返回ret,ret此時(shí)是3,棧幀銷(xiāo)毀,釋放空間,后又調(diào)用Add(5,7),重新開(kāi)辟棧幀,此時(shí)開(kāi)辟的棧幀和上次銷(xiāo)毀的是一個(gè)地方。ret還指向上一個(gè)c的位置,此時(shí)c=5+7;
#include<iostream>
using namespace std;
int& Add(int a,int b)
{
int c = a + b;
return c;
}
int main()
{
int& ret = Add(1, 2);
Add(5, 7);
printf("你是真狗\n");
cout << ret << endl;
return 0;
}
此時(shí)輸出是隨機(jī)值,是因?yàn)?,又調(diào)用了printf函數(shù),占用了釋放的空間,ret雖然還指向原來(lái)c所在的空間,但是,值已經(jīng)是隨機(jī)值了。

2、傳值、傳引用效率比較
以值作為參數(shù)或者返回值類(lèi)型,在傳參和返回期間,函數(shù)不會(huì)直接傳遞實(shí)參或者將變量本身直接返回,而是傳遞實(shí)參或者返回變量的一份臨時(shí)的拷貝,因此用值作為參數(shù)或者返回值類(lèi)型,效率是非常低下的,尤其是當(dāng)參數(shù)或者返回值類(lèi)型非常大時(shí),效率就更低
#include<iostream>
#include<time.h>
using namespace std;
struct A{ int a[10000]; };
void TestFunc1(A a){}
void TestFunc2(A& a){}
void TestRefAndValue()
{
A aa;
// 以值作為函數(shù)參數(shù)
size_t begin1 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc1(aa);
size_t end1 = clock();
// 以引用作為函數(shù)參數(shù)
size_t begin2 = clock();
for (size_t i = 0; i < 10000; ++i)
TestFunc2(aa);
size_t end2 = clock();
// 分別計(jì)算兩個(gè)函數(shù)運(yùn)行結(jié)束后的時(shí)間
cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}
int main()
{
TestRefAndValue();
return 0;
}

可以看出傳引用的效率,遠(yuǎn)勝于傳值
下面?zhèn)髦捣祷嘏c傳引用返回比較
#include<iostream>
#include<time.h>
using namespace std;
struct A { int a[10000]; };
A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{
// 以值作為函數(shù)的返回值類(lèi)型
size_t begin1 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc1();
size_t end1 = clock();
// 以引用作為函數(shù)的返回值類(lèi)型
size_t begin2 = clock();
for (size_t i = 0; i < 100000; ++i)
TestFunc2();
size_t end2 = clock();
// 計(jì)算兩個(gè)函數(shù)運(yùn)算完成之后的時(shí)間
cout << "TestFunc1 time:" << end1 - begin1 << endl;
cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{
TestReturnByRefOrValue();
return 0;
}

可以看出傳引用返回的效率,遠(yuǎn)勝于傳值
所以,可以 傳引用的時(shí)候要傳引用,效率更高,但要注意,局部變量不可以傳引用,出了函數(shù),棧幀銷(xiāo)毀,就會(huì)越界訪(fǎng)問(wèn)。
傳指針(地址)與傳引用的區(qū)別
在語(yǔ)法概念上引用就是一個(gè)別名,沒(méi)有獨(dú)立空間,和其引用實(shí)體共用同一塊空間。
在底層實(shí)現(xiàn)上,引用和地址是一樣的,在底層實(shí)現(xiàn)上實(shí)際是有空間的,因?yàn)橐檬前凑罩羔樂(lè)绞絹?lái)實(shí)現(xiàn)的。
#include<iostream>
#include<time.h>
using namespace std;
int main()
{
int a = 10;
// 在語(yǔ)法上,這里給a這塊空間取了一個(gè)別名,沒(méi)有新開(kāi)空間
int& ra = a;
ra = 20;
// 在語(yǔ)法上,這里定義個(gè)pa指針變量,開(kāi)了4個(gè)字節(jié),存儲(chǔ)a的地址
int* pa = &a;
*pa = 20;
int b = 10;
int*& rpa = pa;
rpa = &b;
return 0;
}

可以看出,引用和指針在匯編實(shí)現(xiàn)上是一樣的。那么他們的效率也是一樣的。
指針和引用的區(qū)別:
- 引用在定義時(shí)必須初始化,指針沒(méi)有要求
- 引用在初始化時(shí)引用一個(gè)實(shí)體后,就不能再引用其他實(shí)體而指針可以在任何時(shí)候指向任何,一個(gè)同類(lèi)型實(shí)體
- 沒(méi)有NULL引用,但有NULL指針
- 在sizeof中含義不同:引用結(jié)果為引用類(lèi)型的大小,但指始終是地址空間所占字節(jié)個(gè)數(shù)(32位平臺(tái)下占4個(gè)字節(jié))
- 引用自加即引用的實(shí)體增加1,指針自加即指針向后偏移一個(gè)類(lèi)型的大小
- 有多級(jí)指針,但是沒(méi)有多級(jí)引用
- 訪(fǎng)問(wèn)實(shí)體方式不同,指針需要顯式解引用,引用編譯器自己處理
- 引用比指針使用起來(lái)相對(duì)更安全
總結(jié)
到此這篇關(guān)于C++中傳值、傳地址和傳引用區(qū)別的文章就介紹到這了,更多相關(guān)C++傳值、傳地址和傳引用區(qū)別內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++調(diào)用C函數(shù)報(bào)錯(cuò)無(wú)法解析的外部命令/無(wú)法解析的外部符號(hào)問(wèn)題
這篇文章主要介紹了C++調(diào)用C函數(shù)報(bào)錯(cuò)無(wú)法解析的外部命令/無(wú)法解析的外部符號(hào)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-08-08
c++訪(fǎng)問(wèn)私有private成員變量的常用方法
這篇文章主要介紹了c++訪(fǎng)問(wèn)私有private成員變量的常用方法,需要的朋友可以參考下2020-08-08
C語(yǔ)言SetConsoleCursorPosition函數(shù)使用方法
這篇文章介紹了C語(yǔ)言SetConsoleCursorPosition函數(shù)的使用方法,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-12-12
C++實(shí)現(xiàn)LeetCode(101.判斷對(duì)稱(chēng)樹(shù))
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(101.判斷對(duì)稱(chēng)樹(shù)),本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
C語(yǔ)言實(shí)現(xiàn)圖書(shū)管理系統(tǒng)開(kāi)發(fā)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)圖書(shū)管理系統(tǒng)開(kāi)發(fā),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08
C++?超詳細(xì)分析數(shù)據(jù)結(jié)構(gòu)中的時(shí)間復(fù)雜度
時(shí)間復(fù)雜度一般指時(shí)間復(fù)雜性。?在計(jì)算機(jī)科學(xué)中,時(shí)間復(fù)雜性,又稱(chēng)時(shí)間復(fù)雜度,算法的時(shí)間復(fù)雜度是一個(gè)函數(shù),它定性描述該算法的運(yùn)行時(shí)間2022-03-03
C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義
這篇文章主要介紹了C++程序中main(int argc, char *argv[])函數(shù)的參數(shù)意義,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-09-09

