首先,明確乙個概念,指標是什麼,一旦提到這個老生常談且富有爭議性的話題,那真是1000個人有1000種看法。
在國內的很多教材中,給出的定義一般就是"指標就是位址",從初步理解指標的角度來說,這種說法是最容易理解的,但是這種說法明顯有它的缺陷所在。
「指標就是位址"這種說法相當於"指標=字面值位址(或者說乙個具體的右值)」,這種說法的錯誤所在就是弄錯了指標的本質屬性:指標是變數!
試想一下,如果指標是位址成立,那麼二級指標怎麼理解呢?位址的位址嗎,這明顯是錯誤的。
下面我們從指標是變數這個原則出發,來分析什麼是指標:
在這裡,最容易弄混的就是指標本身的型別和指標的型別,指標本身的型別是int型,一般情況下同一平台上所有型別指標都是一樣的(注①),長度則是平台相關,一般情況下32位機中為4位元組,64位機中為8位元組,事實上,指標的大小由處理器中所使用的位址匯流排寬度決定,指標本身的型別有什麼意義呢?
(為什麼說一般情況下同一平台上所有型別指標都是一樣,而不是所有情況呢?事實上,在某些位址匯流排寬度與資料匯流排寬度不同的特殊機器上指標型別可能不一致)
記憶體的訪問是以位元組為單位的,同時指標的值為乙個位址,指標的型別就直接決定了指標的所能表示位址的上界和下界,32位指標訪問範圍為0~2^32位元組,所以是4gb。
注:以下討論中,對於指標指向資料的型別統一稱為指標的型別,這篇部落格主要討論指標的型別而非指標本身的型別
而指標指向資料的型別則是在定義時指定的,比如int ptr,char str,在這裡,ptr指標的資料型別就是int型,而str指標指向的型別是char型,區分指標指向資料的型別主要是用在對指標解引用時的不同,指標的值是具體的某乙個位置,指向資料的不同則代表解引用的時候所取資料的不同,當ptr為int*型別時,表示在ptr表示的位址處取sizeof(int)個資料,依次類推。
指標的操作
解引用:用*來獲取指標指向的資料,這個不用多說。
指標的運算:加減運算,需要注意的是,指標的加減運算的粒度是基於指標型別的長度,在下例中:
int *p = (int*)0x1000;
char *str = (char*)0x1000;
p++;
str++;
print("p=%d,str=%d\r\n",p,str);
輸出結果:
p=0x1004,str=0x1001
可以看到,p指向int型資料,p++就相當於p+sizeof(int),而str++就相當於str+sizeof(char).
關於指標定義的爭議
int ptr;
int ptr;
咋一看,這倆不是一樣嗎?如果你仔細觀察就可以發現其中的不同,第一種定義方法中靠近型別,而第二種靠近變數,看到這裡,有些朋友就要說了,你個槓精!這不就是個寫法問題嗎,至於這麼糾結嗎!
這還真不僅僅是個寫法問題。這兩種寫法背後代表著不同的邏輯:
int* p1,p2;
p2=p1;
我們來編譯這個例子,結果是這樣:
warning: assignment makes integer from pointer without a cast [-wint-conversion]
編譯資訊顯示,p2為普通int型變數,而p1是int型指標變數,這明顯違揹我們的初衷。如果要定義兩個指標變數,我們應該這麼做:
int p1,p2;
p2=p1;
相信到這裡,大家能夠看出來了,第一種寫法背後邏輯的缺陷所在。
所以現在越來越多的專業書籍都推薦第二種寫法,畢竟作為一門底層語言,嚴謹性比易讀性要重要。
廢話說了那麼多,我們來回到正題,看看指標和陣列。不得不說,指標和陣列就像孿生兄弟,有時候讓人分不清楚,這種情況主要發生在函式引數傳遞的時候,當乙個函式需要乙個陣列作為乙個引數時,我們並不會將整個陣列作為引數傳遞給函式,而是傳入乙個同型別指標p,然後在函式中就可以使用p[n]來訪問陣列中元素(這個大家都懂,就不放示例了)。
那麼,指標和陣列到底是不是同乙個東西呢?
我們來看看下面的例子:
file1.c:
int buf[10];
file2.c:
extern int *buf;
編譯結果:
error: conflicting types for 『buf』。
從這裡可以看出,陣列和指標並不相等。
資料訪問的本質區別
毫無疑問,我們經常使用指標的陣列,也經常混用。但是我們有沒有關注過它們背後的執行原理呢?我們看下面的**:
int buf[10] = ;
int *p = buf;
*p = 10;
首先,有必要來講講陣列的初始化,在定義時,如果我們不對陣列進行初始化操作,有兩種情況:
同時,我們可以對其進行初始化,可以全部初始化或者部分初始化,部分初始化時,未被初始化部分全部預設被初始化為0.所以我們常用buf[n]=來在定義時初始化乙個陣列。
根據c語言的規定,陣列名=陣列首元素指標,所以直接可以用陣列名的解引用buf來訪問第乙個元素,也可以使用(buf+n)來訪問第n個元素。
C語言中指標和陣列的區別
看 c專家程式設計 一書,看到陣列與指標並不相同一章,遂做了一段測試 include include int main void 輸出 可以看到這樣的輸出,結果很顯然 第乙個輸出的值,0028ff24,應該是符號表中p的位址。第二個值,00403000,是位址0028ff24中儲存的值,也就是指標p...
C語言中指標和陣列分析 上
事物的難度遠遠低於對事物的恐懼!這章我們來分析下指標和陣列,在前兩章我們談了陣列和指標,我們知道 陣列的本質 陣列是一段連續的記憶體空間 陣列的空間大小為sizeof array type array size 陣列名可看做指向陣列第乙個元素的常量指標 那麼我們來看乙個問題 對於乙個陣列 int a...
C語言中指標和陣列分析 下
事物的難度遠遠低於對事物的恐懼!陣列名可以當做常量指標使用,那指標是否也可以當做陣列名來使用呢?為了說明這個問題,我們先來看看陣列的兩種訪問方式,對於陣列int array 5 訪問方式有 下標形式 array 1 2 指標形式 array 1 2 兩種訪問方式的比較 指標以固定增量在陣列中移動是,...