參考自以下內(nèi)容输枯,侵刪:
不同之處
- 不存在空引用铅鲤。引用必須連接到一塊合法的內(nèi)存。存在空指針NULL。
- 一旦引用被初始化為一個(gè)對(duì)象谐宙,就不能被指向到另一個(gè)對(duì)象。指針可以在任何時(shí)候指向到另一個(gè)對(duì)象分衫。
- 引用必須在創(chuàng)建時(shí)被初始化据德。指針可以在任何時(shí)間被初始化。
函數(shù)參數(shù)傳遞
- 值傳遞傳遞的是變量的拷貝蔽豺。
- 引用傳遞傳遞的是同一個(gè)變量区丑。
- 指針傳遞傳遞的是變量的地址的拷貝(本質(zhì)上也是值傳遞)。
可以看到值傳遞和指針傳遞都會(huì)發(fā)生拷貝修陡,而引用傳遞避免了拷貝沧侥。
復(fù)雜一點(diǎn):
#include "stdio.h"
void f1( int*&p){
printf("\n---f1---\n");
printf("指針p的地址:%p",&p);
printf("\n指針p的值%p",p);
printf("\n指針p指向的內(nèi)容:%x\n",*p);
*p=0xff;
}
void f2( int* p){
printf("\n---f2---\n");
printf("指針p的地址:%p",&p);
printf("\n指針p的值%p",p);
printf("\n指針p指向的內(nèi)容:%x\n",*p);
*p=0xff;
}
int main()
{
int a=0x10;
printf("a的地址:%p\n",&a);
printf("a的值:%x\n\n",a);
int *b=&a;
printf("指針b的地址:%p\n",&b);
printf("指針b的值:%p\n",b);
printf("指針b指向的內(nèi)容:%x\n",*b);
f1(b);
printf("\n試圖在函數(shù)f1中改變a的之后a的值:%x\n",a);
a = 0x10;
f2(b);
printf("\n試圖在函數(shù)f2中改變a的之后a的值:%x\n",a);
}
執(zhí)行的結(jié)果是:
a的地址:0x7fff50d8bbac
a的值:10
指針b的地址:0x7fff50d8bba0
指針b的值:0x7fff50d8bbac
指針b指向的內(nèi)容:10
---f1---
指針p的地址:0x7fff50d8bba0
指針p的值0x7fff50d8bbac
指針p指向的內(nèi)容:10
試圖在函數(shù)f1中改變a的之后a的值:ff
---f2---
指針p的地址:0x7fff50d8bb68
指針p的值0x7fff50d8bbac
指針p指向的內(nèi)容:10
試圖在函數(shù)f2中改變a的之后a的值:ff
雖然f1和f2都可以改變a的值。但是魄鸦,函數(shù)f1由于傳入的是指針的引用宴杀,所以從b到p沒有發(fā)生指針的復(fù)制。而f2由于傳入的是指針本身号杏,所以還是會(huì)復(fù)制指針(b和p的地址不一樣)婴氮。
舉個(gè)栗子
#include "stdio.h"
class A{
public:
A(int value):m_value(value)
{}
int m_value;
};
void f(A /*這里寫什么?*/_a) { //這里參數(shù)傳遞使用什么呢盾致?
// 我們希望可以創(chuàng)建在main函數(shù)中聲明的實(shí)例 a
_a = new A(5);
printf("%d\n", _a->m_value);
}
int main() {
A* a;
f(a); //傳入指針
printf("%d\n", a->m_value);
}
-
(A* _a)
可否主经?答案是:不行!因?yàn)檫@時(shí)候指針_a是a的復(fù)制庭惜,兩個(gè)指針的地址是不同:
5
-125990072
-
(A*& _a)
可否罩驻?答案是:可以!因?yàn)檫@時(shí)候傳入的是指針的引用护赊,即指針本身惠遏,所以沒有問題。
5
5
從上面的例子發(fā)現(xiàn)骏啰,可以在主函數(shù)中聲明一個(gè)實(shí)例的空指針节吮,然后通過其他函數(shù)來對(duì)它進(jìn)行創(chuàng)建和銷毀。(有什么用判耕?)
為什么使用指針/引用透绩?
參數(shù)傳遞中,如果參數(shù)是大型對(duì)象,引用和指針相比于直接傳值有效率優(yōu)勢(但引用和指針的優(yōu)劣我不太明白帚豪,個(gè)人感覺指針只是復(fù)制了一遍指針的大刑季埂(32位機(jī)子就是4個(gè)字節(jié)的空間),還可以接受吧……):
- 引用不產(chǎn)生副本
- 指針只復(fù)制指針本身狸臣,而不是整個(gè)對(duì)象
另外莹桅,因?yàn)楹瘮?shù)只能返回一個(gè)數(shù)值。如果使用引用或指針作為參數(shù)烛亦,則可以在函數(shù)中改變多個(gè)變量(可變參數(shù))诈泼。
函數(shù)參數(shù)傳遞用指針?還是引用此洲?
只能使用引用
有些函數(shù)只能傳遞引用厂汗,如重載運(yùn)算符。因?yàn)?strong>指針的運(yùn)算符是語言預(yù)定義好的呜师,無法重載娶桦。比如:
const maxCard=100;
Class Set
{
int elems[maxCard]; // 集和中的元素,maxCard 表示集合中元素個(gè)數(shù)的最大值汁汗。
int card; // 集合中元素的個(gè)數(shù)衷畦。
public:
Set () {card=0;} //構(gòu)造函數(shù)
friend Set operator * (Set ,Set ) ; //重載運(yùn)算符號(hào)*,用于計(jì)算集合的交集 用對(duì)象作為傳值參數(shù)知牌,復(fù)制連個(gè)set祈争,效率低下
// friend Set operator * (Set & ,Set & ) 重載運(yùn)算符號(hào)*,用于計(jì)算集合的交集 用對(duì)象的引用作為傳值參數(shù)角寸,不發(fā)生復(fù)制菩混,效率很高!
...
}
先考慮集合交集的實(shí)現(xiàn)
Set operator *( Set Set1,Set Set2)
{
Set res;
for(int i=0;i<Set1.card;++i)
for(int j=0;j>Set2.card;++j)
if(Set1.elems[i]==Set2.elems[j])
{
res.elems[res.card++]=Set1.elems[i];
break;
}
return res;
}
其他情況下的一些準(zhǔn)則
來自這里:
相比起引用扁藕,指針有這些特點(diǎn):
- 指針變量可以被重復(fù)賦值或更改(引用則不行沮峡,一經(jīng)賦值不能再改)
- 指針變量可以為空(可以傳入一個(gè)空的指針)
里面還有于洋的神的回答,因?yàn)椴蛔屴D(zhuǎn)載亿柑,就不貼了邢疙,想看再點(diǎn)鏈接吧。大概就是想要改變變量的數(shù)值望薄,使用指針疟游;如果傳入不可變的變量,用const+引用痕支。
函數(shù)返回引用
通過使用引用來替代指針颁虐,會(huì)使Cpp程序更容易閱讀和維護(hù)。Cpp函數(shù)可以返回一個(gè)引用卧须,方式與返回一個(gè)指針類似另绩。
當(dāng)函數(shù)返回一個(gè)引用時(shí)瞬痘,則返回一個(gè)指向返回值的隱式指針。這樣板熊,函數(shù)就可以放在賦值語句的左邊。
double &max(double &d1,double &d2)
{
return d1>d2?d1:d2;
}
由于max()函數(shù)返回一個(gè)對(duì)雙精度數(shù)的引用察绷,那么我們就可以用max() 來對(duì)其中較大的雙精度數(shù)加1:
max(x,y)+=1.0
;