在C語言中,對變數的使用實質上是對電腦記憶體中儲存內容的訪問,通過對記憶體空間的引用來實現寫入和讀取。(註:C中有一個特殊的關鍵字register,
用來聲明非儲存在記憶體當中的變數,register用來要求將變數儲存在電腦的寄存器當中,這樣的變數主要的目的是加快CPU訪問的速率)REGISTER關鍵字是
特定時期的產物,在記憶體訪問速度很慢的時代用register定義的變數,確實儲存在電腦CPU的寄存器當中,現在來說由於記憶體的訪問速率也很快,很多編譯器在
編譯的時候,會將register變數也儲存在記憶體當中。這裡主要討論簡介引用和解析引用,因此對register就不再討論。
間接引用是指在組合語言指令中不直接指出記憶體的地址,而是通過一個寄存器或者一個記憶體空間來訪問另外一個記憶體空間。
Exp:
mov ax,[bx]
這樣就實現了一個間接引用,這條語句並不是直接的訪問bx寄存器,而是訪問bx指向的記憶體空間。在C中我們通過指標來實現間接引用。
Exp:
int var1;
int *pvar=NULL;
pvar=&var1;
*pvar=10;
這樣就實現了一個間接引用,通過一個記憶體空間來訪問另一個記憶體空間,於是就實現了間接引用。在電腦的世界裡面間接引用也叫做間接定址。
上面的C語言實現翻譯成彙編指令可能為下面的形式:
mov [ax], 10 ;ax中儲存的內容就是變數var1的記憶體位址,實際上還可能涉及到物理地址的位移量計算
組合語言與C語言的最大區別就是可以顯式的訪問寄存器和直接計算得到某個記憶體位址,其他的像迴圈語句等其他C語言控制結構在彙編中一樣可以實現,
在組合語言中可以顯式的指定程式執行的開始地址,可以通過ORG指令來實現,具體就不討論了。
1、間接引用
我們可以通過幾個執行個體來看看間接引用:
int var1;
int var2;
int *pvar1=NULL;
int **pvar=NULL;
pvar1=&var1; //間接引用的必須條件,通過 & 運算子來實現將一個記憶體空間的地址放到另外一個記憶體空間中。
pvar=&pvar1; //間接引用, 因為pvar1也是一個變數,指標變數,因此在C中也有一個與之對應的記憶體空間,
*pvar1=10; //這裡的意思就是將整型字面值放到*pvar1指向的記憶體空間,
pvar=&var2, // 這裡是不對的,雖然我們也可以通過一定的方式使之可以順利的運行,但是如果那樣做的話,可能會引入未知的錯誤。
如果實在想通過pvar來間接引用var2的話,怎麼辦呢? 那就和下面一樣:
*pvar=&var2;
然後像下面這樣來引用var2;
*(*pvar)=10; //var2=10
2、解析引用
我也不知道這麼說是否恰當,但是 * 運算在對地址進行運算的時候,很多權威的文檔都這麼說,我也就跟著說了,其實*的解釋沒有什麼
特別的,那就是:
* 取出的是儲存在一個記憶體空間地區(記憶體地區1)的內容,並且將取出的內容解釋為另外一塊記憶體地區(記憶體地區2)。然後我們就可以對
記憶體地區2進行訪問。
如果進行多重的解析運算,那麼就會涉及到更多的記憶體地區, 就像前面所說的:
Exp:
int var1; //var1 記憶體空間1,這裡可以簡單理解為 var1這個標示符指向記憶體空間1,雖然我們並沒顯式的指出這個指向
int var2; //var2 記憶體空間 2
int *pvar1=NULL; //pvar1 記憶體空間3
int **pvar=NULL;// pvar 記憶體空間4
pvar1=&var1; // 將記憶體空間1的位置放置到記憶體空間3裡面,形成了一個指向關係
pvar1=10; //將整型字面值10,放置到記憶體空間3指向的記憶體空間 1 裡面。
*pvar=&pvar1, // 形成一個多重指向,pvar 指向 pvar1, 而**pvar將指向 記憶體空間1
3、 關於定義指標變數解析運算子的位置
Exp:
int *p;
和
int* p;
上面的兩種定義的方式在本質上沒有區別, 但是如果涉及到更多的變數定義的話就可能引起誤解。
我的習慣是每個變數定義單獨佔用一行:
Exp:
int *p1,
*p2;
這樣就很清楚了。
如果涉及到typedef的話,那麼就會另外的情形了,
Exp:
typedef int *INT;
INT var1;
INT *var2;
很不幸的是很多人在這個地方會犯錯, 我也曾經犯過錯,原本想聲明一個指向int變數的指標var2,結果是定義了一個指向int *類型的指標
變數。
現在我的習慣是:
1、在非typedef定義時*運算子靠近變數
2、在typedef定義新的的類型標示符時*靠近原來的類型標識符。
Exp:
int *p, *pp;
typedef int* PINT;
這樣意圖就很明顯了,並且不容易引起誤解。
4、指標的四則運算
兩個指標變數相加是未定義的行為,
兩個指標變數想減的結果返回兩個記憶體空間的距離,
兩個指標變數相稱是未定義的行為,
兩個指標變數相除是未定義的行為,
指標變數和整型值相加減是指標移動其指向的位置。
指標變數和整型值相乘除是未定義的行為。
Exp:
size_t (strlen)(const char *str)
{
char *start;
start=str;
while(*start)
{
start++;
}
return (start-str);
}
5、 理解指標
理解指標最主要的是要有指向的概念,如果單純的從變數儲存的角度來理解,可能會遇到很多疑問。
指向這個詞還真有點特殊,關鍵是要明白間接引用。