C/C++ 系統(tǒng) 內(nèi)存分布圖
變量和內(nèi)存地址的關(guān)系
計(jì)算機(jī)存儲(chǔ)器位置具有地址并保存內(nèi)容蔚万。地址是一個(gè)數(shù)字(通常用十六進(jìn)制表示)岭妖,這對(duì)程序員來(lái)說(shuō)很難直接使用。通常笛坦,每個(gè)地址位置保持8位(即1字節(jié))數(shù)據(jù)区转。程序員完全可以解釋數(shù)據(jù)的含義,例如整數(shù)版扩,實(shí)數(shù)废离,字符或字符串。
為了減輕使用數(shù)字表示的內(nèi)存地址給程序員解釋數(shù)據(jù)的編程負(fù)擔(dān)礁芦,早期的編程語(yǔ)言(如C)引入了變量的概念蜻韭。變量就是為存儲(chǔ)特定類型值的內(nèi)存地址命令了一個(gè)對(duì)人具有可讀性的標(biāo)識(shí)符。變量名(或標(biāo)識(shí)符)附加到特定的地址中柿扣。tong此外肖方,類型(例如int,double未状,char)與數(shù)據(jù)內(nèi)容長(zhǎng)度相關(guān)聯(lián)俯画,以便于解釋數(shù)據(jù)。
每個(gè)地址位置通常保持8位(即1字節(jié))數(shù)據(jù)司草。 4字節(jié)的int值占用4個(gè)內(nèi)存位置艰垂。 32位系統(tǒng)通常使用32位地址泡仗。要存儲(chǔ)32位地址,需要4個(gè)存儲(chǔ)單元猜憎。
下圖說(shuō)明了計(jì)算機(jī)的內(nèi)存地址,數(shù)據(jù)內(nèi)容,變量的名稱娩怎,類型和程序員使用的值之間的關(guān)系。
引用(reference)
C++ Primer這本書(shū)并沒(méi)有對(duì)reference類型在內(nèi)存管理方面給出一個(gè)明確的結(jié)論.因此以下從其他資料摘錄了相關(guān)的定義
引用不是對(duì)象; 它們不一定占用存儲(chǔ)空間胰柑,盡管如果有必要實(shí)現(xiàn)所需的語(yǔ)義截亦,編譯器可以分配存儲(chǔ)空間(例如,引用類型的非靜態(tài)數(shù)據(jù)成員通常會(huì)增加類的大小以存儲(chǔ)存儲(chǔ)器地址所需的數(shù)量)柬讨。
--摘錄自https://en.cppreference.com/w/cpp/language/reference
根據(jù)Bjarne Stroustrup的說(shuō)法崩瓤,引用變量大多數(shù)時(shí)間都是優(yōu)化的,并且沒(méi)有為引用創(chuàng)建變量姐浮。 但是谷遂,在某些無(wú)法優(yōu)化引用變量的情況下,它實(shí)現(xiàn)為指向原始對(duì)象的4字節(jié)指針卖鲤。因此肾扰,在大多數(shù)情況下,編譯器在涉及引用的語(yǔ)句中使用實(shí)際對(duì)象而不是引用變量蛋逾。
--摘錄自《The C++ Programming Language》
對(duì)引用的總結(jié)
- 在C++中所謂的引用"reference"就是左值引用,可以比喻為對(duì)象(變量)起一個(gè)別名集晚。
- 初始化完成,引用將和它的初始值對(duì)象綁定在一起,無(wú)法重新綁定到另一個(gè)對(duì)象(變量)
- 引用不是對(duì)象,沒(méi)有實(shí)際地址,所以“不存在引用的引用或指向某個(gè)引用的指針”区匣。
- 引用只能綁定到對(duì)象,無(wú)法綁定到具體的字面量或某個(gè)表達(dá)式的計(jì)算結(jié)果
-
對(duì)引用變量取址(&)操作,大部份情況下引用變量所指向的對(duì)象的內(nèi)存地址偷拔。特殊情況下,引用變量會(huì)被編譯器識(shí)別為一個(gè)4字節(jié)長(zhǎng)度的指針。
如圖所示:0x????????表示引用不一定會(huì)產(chǎn)生內(nèi)存分配
指針
《征服C指針》這本書(shū)對(duì)指針剖析十分透徹亏钩,以下對(duì)C指針的理解方法大部份源于該書(shū)莲绰。
#include <iostream>
int **pp=nullptr;
int main(int argc, char const *argv[])
{
int b=734;
int *p=&b;
pp=&p;
std::cout<<"variable b address:"<<p<<std::endl;
std::cout<<*"pointer p address:"<<pp<<std::endl;
std::cout<<*"pointer pp address:"<<&pp<<std::endl;
return 0;
}
如圖所示所示指針關(guān)系
如何正確解讀函數(shù)指針
用英文來(lái)解讀指針,看如下幾個(gè)經(jīng)典的例子
int (*my_func)()
- 首先著眼于標(biāo)識(shí)符(變量名或者函數(shù)名)姑丑。
- 從距離標(biāo)識(shí)符最近的地方開(kāi)始蛤签,依照優(yōu)先順序解釋派生類型(指針、數(shù)組和函數(shù))栅哀。優(yōu)先順序說(shuō)明如下震肮,
1. 用于整理聲明內(nèi)容的括弧
2. 用于表示數(shù)組的[],用于表示函數(shù)的()
3. 用于表示指針的 * - 解釋完成派生類型留拾,使用“of”戳晌、“to”、“returning”將它們連接起來(lái)痴柔。
-
最后沦偎,追加數(shù)據(jù)類型修飾符(在左邊,int、double 等)豪嚎。
特殊的指針
- 空指針 c中為NULL,C++為nullptr
- void指針,也稱為萬(wàn)能指針,任何類型的指針都可以賦值給void指針
- 指向常量的指針:不能用指向常量的指針改變其所指對(duì)象的值鸿捧。
- 僅有指向常量的指針才能存放常量對(duì)象的地址。
- 指向常量的指針允許指向一個(gè)非常量的對(duì)象疙渣。
const double pi=3.14 //pi是個(gè)常量 //錯(cuò)誤:&p的指針類型是【double *p】和 【const double *p】不匹配 double *p=π //正確:指針的類型與pi的指針類型【const double *p】匹配 const double *pt=π //錯(cuò)誤:不能修改【指向常量的指針】所指向的對(duì)象 *pt=42.3; double dq=222.3; //正確:指向常量的指針允許指向一個(gè)非常量的對(duì)象。 pt=&dq;
- 常量指針
- 該指針存放其指向變量的地址值一經(jīng)初始法,就不能再改變.
- 常量指針?biāo)傅淖兞坎皇浅A?
示例1
示例2int a=123; int *const pr=&a; //后續(xù)一直指向變量a,無(wú)法修改.
const int c=777; //對(duì)應(yīng)的指針類型【const int *p】 //錯(cuò)誤:pr的指針類型【*const pr】和【const int *p】不匹配 int *const pr=&c;
5.指向常量的常量指針
- 該指針存放其指向變量的地址值一經(jīng)初始法,就不能再改變.
- 無(wú)法通過(guò)指向常量的常量指針修改所指的變量值,即便指向的值是非常量對(duì)象.
const int c=77; int b=734; const int *const pr1=&c; const int *const pr2=&b; //錯(cuò)誤:具體原因查看第二小點(diǎn) *pr1=723; //但變量修改自身,和指向常量的常量指針沒(méi)有關(guān)系 c=1024;
-
各種特殊指針的對(duì)比總結(jié)
指向指針的引用
引用不是一個(gè)對(duì)象堆巧,因此不能定義指向引用的指針妄荔,但指針是一個(gè)對(duì)象,所以可以定義對(duì)指針的引用。
int i=42;
int *p; //p is pointer to int 或p是一個(gè)指向int類型的指針
int *&r=p;
//英文解讀法:r is a reference **binding** pointer of int
//中文閱讀法: "r是綁定int指針的引用"
r=&i
要理解r 的類型到底是千| 么谍肤,最簡(jiǎn)單的辦法是從右向左閱讀r 的定義啦租。離變量名最近的符號(hào)( 此例中是&r 的符號(hào)&) 對(duì)變量的類型有最直接的影響,因此r 是一個(gè)引用荒揣。聲明符的其余部分用以確定r 引用的類型是什么篷角,此例中的符號(hào)* 說(shuō)明E 引用的是一個(gè)指針。最后系任,聲明的基本數(shù)據(jù)類型部分指出r 引用的是一個(gè)工nt 指針恳蹲。 ---《摘錄自c++ Primer 第五版》
yu