C++中指標和引用的區別
1、指標和引用的本質(是什麼)
(1)指標是存放記憶體地址的一種變數,特殊的地方就在它存放的是記憶體地址。 因此,指標的大小不會像其他變數一樣變化,只跟當前平臺相關——不同平臺記憶體地址的範圍是不一樣的,32位平臺下,記憶體最大為4GB,因此只需要32bit就可以存下,所以sizeof(pointer)的大小是4位元組。64位平臺下,32位就不夠用了,要想記憶體地址能夠都一一表示,就需要64bit(但是目前應該沒有這麼大的記憶體吧?),因此sizeof(pointer)是8。
(2)引用的本質是“變數的別名” ,就是給變數又重新起了一個名字,既然是“別名”,那麼就一定要有本體。
2、宣告和初始化時的區別
指標指向的是一個記憶體地址, 因此可以指向一塊為0x00000000的地址,宣告時可以暫時不初始化(不推薦),即pointer = NULL;
引用是變數的別名,別名就一定對應著一個“本名”,因此必須在宣告時就初始化,且不能初始化為空。
3、使用時區別
(1)根據宣告和初始化時二者的區別,指標在宣告週期內隨時可能會為Null,所以使用時一定要做檢查,防止出現空指標、野指標的情況;而引用則不用再操這個心,只要初始化了,在哪裡都可以直接使用,再也不用擔心它會不會為空什麼的了。
(2)指標因為自己存的是一個記憶體地址,既然可以存初始化(或者賦值)的地址,那麼在指標生命週期內就可以存其他的地址,只要你是同一型別(不同型別這個對應的型別偏移不一樣)的變數,對於指標都OK。
引用作為一個變數AA的別名,在它的整個生命週期內,它只能“從一而終”,始終是第一次初始化它的那個變數的別名,在這期間任何對它的操作,都等同於對變數AA的操作。
Talk is cheap,show you my code.
/** 指標和引用的例子 **/ std::string s1 = "蘿蔔"; std::string s2 = "青菜"; std::string s3 = "雞蛋"; std::string s4 = "西紅柿"; /** 指標可以初始化為空 **/ std::string *p_Str = NULL; /** 引用一開始必須初始化 **/ std::string& r_Str = s1; p_Str = &s2; std::cout<<"我是指標"<<*p_Str<<std::endl; /** 青菜 **/ std::cout<<"我是引用"<<r_Str<<std::endl;/** 蘿蔔 **/ std::cout<<std::endl; std::cout<<"*********分別修改指標和引用***********"<<std::endl; /** 分別修改指標和引用 **/ r_Str = s3;/** 試圖讓r_Str為s3的別名 **/ p_Str = &s4; /** p_Str重新指向了s4 **/ std::cout<<"我是指標"<<*p_Str<<std::endl;/** 西紅柿 **/ std::cout<<"我是引用"<<r_Str<<std::endl;/** 雞蛋 **/ std::cout<<std::endl; std::cout<<"*********檢視剛剛的修改對最初初始化的影響***********"<<std::endl; /** 貌似成功了,都按照意圖修改了,但是,稍等 **/ std::cout<<"我是s1"<<s1<<std::endl;/** 雞蛋 !!!注意 !!!**/ std::cout<<"我是s2"<<s2<<std::endl;/** 青菜 **/ std::cout<<"我是s3"<<s3<<std::endl;/** 雞蛋 **/ std::cout<<"我是s4"<<s4<<std::endl;/** 西紅柿 **/ /** 發現s1 "蘿蔔"被變成了和s3一樣的"青菜",這也說明了任何對引用的操作都等同於操作原先的變數本身 相比較之下,指標就自由度很高了,想指向誰就指向誰,並不會影響任何之前指向過的變數 驚不驚喜,意不意外 :) **/
4、總結
一個不大恰當的比喻是,指標就像是一個可以(注意是可以,但未必一定)到處沾花惹草(可以隨時指向任意地址)的“渣男”;而引用則像是一個只能“從一(誰初始化就跟誰)而終”的“老實人”。
另外,根據Scott Meyers在《More Effective C++》上所講,只有當你確定需要一開始就初始化,並且不需要再指向其他型別時 使用引用,否則你都應該使用指標。
小弟認識粗鄙淺薄,有不當之處,請大佬輕拍。