欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++中傳值、傳地址和傳引用究竟有哪些區(qū)別

 更新時間:2021年07月27日 11:39:40   作者:小一!  
指針是一個變量,只不過這個變量存儲的是一個地址,指向內(nèi)存的一個存儲單元,而引用跟原來的變量實質(zhì)上是同一個東西,只不過是原變量的一個別名而已,這篇文章主要給大家介紹了關于C++中傳值、傳地址和傳引用究竟有哪些區(qū)別的相關資料,需要的朋友可以參考下

傳引用定義

傳值與傳地址,相信大家都了如指掌了,在這里先介紹一下什么是引用?

引用不是新定義一個變量,而是給已存在變量取了一個別名,編譯器不會為引用變量開辟內(nèi)存空間,它和它引用的變量共用同一塊內(nèi)存空間。

說白了,引用就是給變量起外號,比如一個人可以有乳名,有學名,有筆名,其實就都是一個人而已。

例:林沖,江湖上人稱“豹子頭"

類型& 引用變量名(對象名) = 引用實體;

void TestRef()
{
int a = 10;
int& ra = a;  //<====定義引用類型
printf("%p\n", &a);
printf("%p\n", &ra);
}

可以看出a 和ra地址是一樣的,足以證明,引用就是變量本身。

注意:引用類型必須和引用實體是同種類型的

意思是:對象用 int 定義的,那么引用必須是 int&

引用特性

1. 引用在定義時必須初始化

#include<iostream>
using namespace std;

void TestRef()
{
	int a = 10;
	int& ra;  // 該條語句編譯時會出錯
	int& ra = a;
	int& rra = a;
	printf("%p %p %p\n", &a, &ra, &rra);
}

int main()
{
	TestRef();
	
	return 0;
}

int ra&; // 不賦初值,會報錯

2、一個變量可以有多個引用,一個人可以有多個外號

#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、引用一旦引用一個實體,再不能引用其他實體,意思是,raa 的引用后,就不能再引用別的對象

傳引用與傳值的區(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;
}

注意: 返回時,c會將自己的值,復制給一個臨時變量,ret接收的其實是c的拷貝,c在 Add 函數(shù)調(diào)用結(jié)束后,隨著棧幀的銷毀,而銷毀。

c的拷貝變量一般開在,調(diào)用c所在函數(shù)的函數(shù)中,此例就是在main函數(shù)中開辟,當返回變量較小時,業(yè)可能在寄存器中開辟空間存放返回變量的拷貝

傳引用返回:

#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é)果是隨機值,這是為什么呢?

因為返回的是 c 的引用,也就是 c本身,而 c 變量是存儲在棧幀中,隨著函數(shù)的結(jié)束,棧幀銷毀,c也隨著銷毀,空間釋放,這時就造成非法引用,值為隨機值。

那怎么辦呢?

不將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;
}


再來一個有趣的題,下面代碼的結(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;
}

很多人會以為是 3

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

調(diào)用Add(1,2)后,將結(jié)果返回ret,ret此時是3,棧幀銷毀,釋放空間,后又調(diào)用Add(5,7),重新開辟棧幀,此時開辟的棧幀和上次銷毀的是一個地方。ret還指向上一個c的位置,此時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;
}

此時輸出是隨機值,是因為,又調(diào)用了printf函數(shù),占用了釋放的空間,ret雖然還指向原來c所在的空間,但是,值已經(jīng)是隨機值了。

2、傳值、傳引用效率比較

以值作為參數(shù)或者返回值類型,在傳參和返回期間,函數(shù)不會直接傳遞實參或者將變量本身直接返回,而是傳遞實參或者返回變量的一份臨時的拷貝,因此用值作為參數(shù)或者返回值類型,效率是非常低下的,尤其是當參數(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();

	// 分別計算兩個函數(shù)運行結(jié)束后的時間
	cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;
	cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}

int main()
{
	TestRefAndValue();

	return 0;
}

可以看出傳引用的效率,遠勝于傳值

下面?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ù)的返回值類型
	size_t begin1 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc1();
	size_t end1 = clock();

	// 以引用作為函數(shù)的返回值類型
	size_t begin2 = clock();
	for (size_t i = 0; i < 100000; ++i)
		TestFunc2();
	size_t end2 = clock();

	// 計算兩個函數(shù)運算完成之后的時間
	cout << "TestFunc1 time:" << end1 - begin1 << endl;
	cout << "TestFunc2 time:" << end2 - begin2 << endl;
}


int main()
{
	TestReturnByRefOrValue();

	return 0;
}

可以看出傳引用返回的效率,遠勝于傳值

所以,可以 傳引用的時候要傳引用,效率更高,但要注意,局部變量不可以傳引用,出了函數(shù),棧幀銷毀,就會越界訪問。

傳指針(地址)與傳引用的區(qū)別

語法概念上引用就是一個別名,沒有獨立空間,和其引用實體共用同一塊空間。

在底層實現(xiàn)上,引用和地址是一樣的,在底層實現(xiàn)上實際是有空間的,因為引用是按照指針方式來實現(xiàn)的。

#include<iostream>
#include<time.h>
using namespace std;

int main()
{
	int a = 10;

	// 在語法上,這里給a這塊空間取了一個別名,沒有新開空間
	int& ra = a;
	ra = 20;

	// 在語法上,這里定義個pa指針變量,開了4個字節(jié),存儲a的地址
	int* pa = &a;
	*pa = 20;

	int b = 10;
	int*& rpa = pa;
	rpa = &b;

	return 0;
}

可以看出,引用和指針在匯編實現(xiàn)上是一樣的。那么他們的效率也是一樣的。

指針和引用的區(qū)別:

  1. 引用在定義時必須初始化,指針沒有要求
  2. 引用在初始化時引用一個實體后,就不能再引用其他實體而指針可以在任何時候指向任何,一個同類型實體
  3. 沒有NULL引用,但有NULL指針
  4. 在sizeof中含義不同:引用結(jié)果為引用類型的大小,但指始終是地址空間所占字節(jié)個數(shù)(32位平臺下占4個字節(jié))
  5. 引用自加即引用的實體增加1,指針自加即指針向后偏移一個類型的大小
  6. 有多級指針,但是沒有多級引用
  7. 訪問實體方式不同,指針需要顯式解引用,引用編譯器自己處理
  8. 引用比指針使用起來相對更安全

總結(jié)

到此這篇關于C++中傳值、傳地址和傳引用區(qū)別的文章就介紹到這了,更多相關C++傳值、傳地址和傳引用區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • C++超詳細實現(xiàn)二叉樹的遍歷

    C++超詳細實現(xiàn)二叉樹的遍歷

    本章將會詳細講解二叉樹遍歷的四種方式,分別為前序遍歷、中序遍歷、后續(xù)遍歷和層序遍歷。在學習遍歷之前,會先帶大家回顧一下二叉樹的基本概念
    2022-05-05
  • C語言高效實現(xiàn)向量循環(huán)移位

    C語言高效實現(xiàn)向量循環(huán)移位

    這篇文章主要為大家詳細介紹了C語言高效實現(xiàn)向量循環(huán)移位,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • 使用C語言操作樹莓派GPIO的詳細步驟

    使用C語言操作樹莓派GPIO的詳細步驟

    今天抽空給大家普及使用C語言操作樹莓派GPIO的詳細步驟,本文大概分五步給大家介紹樹莓派GPIO安裝步驟,首先需要安裝GPIO庫然后進行一步步設置,具體操作方法跟隨小編一起學習吧
    2021-06-06
  • 用C語言實現(xiàn)簡單五子棋小游戲

    用C語言實現(xiàn)簡單五子棋小游戲

    這篇文章主要為大家詳細介紹了用C語言實現(xiàn)簡單五子棋小游戲,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • C\C++實現(xiàn)讀寫二進制文件的方法詳解

    C\C++實現(xiàn)讀寫二進制文件的方法詳解

    這篇文章主要為大家詳細介紹了C\C++實現(xiàn)讀寫二進制文件的方法,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以了解一下
    2023-03-03
  • C++小知識:盡可能使用枚舉類

    C++小知識:盡可能使用枚舉類

    今天小編就為大家分享一篇關于C++小知識:盡可能使用枚舉類,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • C語言編寫基于TCP和UDP協(xié)議的Socket通信程序示例

    C語言編寫基于TCP和UDP協(xié)議的Socket通信程序示例

    這篇文章主要介紹了C語言編寫基于TCP和UDP協(xié)議的Socket通信程序示例,其中TCP的客戶端與服務器端采用多線程實現(xiàn),需要的朋友可以參考下
    2016-03-03
  • C語言詳細分析講解struct與union使用方法

    C語言詳細分析講解struct與union使用方法

    最近開始自學C語言,從最基礎部分的開始學起。今天看書的時候注意到了struct和union似乎很像,除了名字不同,看起來幾乎沒有區(qū)別。<BR>既然C中定義了struct和union兩個關鍵字,那么它們肯定是有區(qū)別的,在查了一些資料之后我來總結(jié)一下他們的使用
    2022-04-04
  • 基于C++實現(xiàn)去除字符串頭尾指定字符功能

    基于C++實現(xiàn)去除字符串頭尾指定字符功能

    編程時我們經(jīng)常需要對字符串進行操作,其中有一項操作就是去除字符串的頭(尾)指定的字符,比如空格。本文為大家詳細介紹了如何利用C++實現(xiàn)這一效果,需要的可以參考一下
    2022-04-04
  • C++20中的std::span詳解

    C++20中的std::span詳解

    span就是一個連續(xù)對象存儲的觀察者,類似std::string_view是string的觀察者,這篇文章主要介紹了C++20?std::span,需要的朋友可以參考下
    2023-03-03

最新評論