對C++的指針總覺得和引用差不多,其實還是挺有差別的。程式先看一個小程式: int a = 1; int& ra = a; int* pa = &ra; printf("&a = %02X\n", &a); //3EFCD0<< printf("a = %d\n", a...
對C++的指針總覺得和引用差不多,其實還是挺有差別的。
程式
先看一個小程式:
int a = 1; int& ra = a; int* pa = &ra; printf("&a = %02X\n", &a); //3EFCD0<< printf("a = %d\n", a); //1 printf("&ra = %02X\n", &ra); //3EFCD0<< printf("ra = %d\n", ra); //1 printf("&pa = %02X\n", &pa); //3EFCB8 printf("pa = %02X\n", pa); //3EFCD0<< printf("*pa = %d\n", *pa); //1
記憶體示意圖
編譯器的規則
電腦裡面是一個城市,
城市裡面有很多間房子,每個房子都有編號,每個房子裡面會放具體的材料。
城市裡面還有一個派出所,派出所裡面有很多小盒子,每個小盒子都有編號,盒子裡面放的就是城市裡面的門牌號碼。
程式員可以給房子盒子取名字,然後通過名字來得到他們。
房子:引用;盒子:指針;名字:變數名;門牌號,盒子編號:地址。
&得到門牌號或者盒子編號,*去到盒子裡面找到門牌號,找到對應房子裡面的東西。
程式編譯成下麵的故事
===註冊===
程式員:這裡有一個材料(1),幫忙找個房子放一下,
城市管理機構:找到一個門牌號(3EFCD0)的空房子,就用這個房子吧
程式員:好的,以後我就叫這個房子a吧
程式員:一個名字a還不夠,我還想給他取個名字叫做ra,留著備用
程式員:申請一個派出所的盒子,
城市管理機構:找到一個編號為(3EFCB8)的空盒子,就用這盒子吧
程式員:好的,以後我就叫這個盒子pa吧
程式員:這個盒子裡面放進剛纔那個房子ra門牌號吧。(當然也可以告訴他們用a門牌號)
===使用===
程式員:告訴我房子a的編號
程式員:告訴我房子a裡面裝了什麼
程式員:告訴我房子ra的編號
程式員:告訴我房子ra裡面裝了什麼
程式員:告訴我盒子pa的編號
程式員:告訴我盒子pa裡面裝了什麼(當然是那個門牌號)
程式員:告訴我盒子pa裡面裝門牌號碼對應房子裡面裝了什麼。
這樣看來指針(盒子)和引用(房子)還是有挺大差別的吧。
潛規則:
讓人討厭的就是這些潛規則 -___-||,但是記住會更加安全。
- 房子申請了必須放東西(引用必須初始化),否則城市管理機構不幹(編譯不過),所以永遠不會存在空引用(對於C#er而言很難理解,C#的引用鑒於C++指針和引用之間),這樣省去了null check,更加高效。
int & ra; //error C2530: “ra”: 必須初始化引用
- 盒子申請可以不放東西(盒子不值錢,編譯沒有問題),但是要小心,在使用盒子前要自己先把門牌號放進去(運行時有問題),否則就要看城市管理機構心情,他們不會幫你清理盒子。
int * pa;//運行時,使用沒有初始化的pa,會有這樣的異常:讀取位置 0xCCCCCCCC 時發生訪問衝突。
Q&A
Q: int a;可以嗎?
A: 編譯沒有問題,但是和指針一樣的問題,這個時候房子申請到了, 你不放材料進去,不知道城市管理機構會放什麼東西進去。所以總結而言:你申請東西的時候(房子或者盒子)的時候,最好初始化它,或者不要太久以後再去初始化,沒有壞處的,兄弟。
Q: 房子一旦申請就不能改變(引用不能改變),盒子卻可以改變裡面放在房子門牌號,怎麼理解?
A: 其實房子和盒子沒有本質的區別(怎麼又繞回來了@_@),因為他們都是一種東西,當你關註房子的時候,房子和盒子不一樣:房子不能變,盒子卻很靈活;但是如果你站在房子角度看房子,站在盒子的角度看盒子,是一樣的,盒子一旦申請盒子編號也是不能再改變了,盒子只能是那個盒子。換種說法吧,有些時候你可以吧盒子的編號放在另外的盒子裡面,被放進去的盒子就是和房子一樣的地位了。(指針的指針,忽然覺得還有好長的路...)
Q:下麵輸出是多少
int a = 1; int& ra = a; a = 2; printf("ra = %d\n", ra);
A: "ra = 2"//因為ra和a就是同一個房子的兩個名字。