近期對C/C++裡指標的一些認識
C語言系最大的特點就是指標
在C語言系裡,指標實際上就是一個地址。
int num = 0;
int *ip = #
printf("pointer: 0x%.8lx address: 0x%.8lx",ip, &num);
這裡打印出來的pointer
,address
將會是一樣的值,如果在64位機器上執行,可以將精度調成更高的。
指標的運算
我聽說以前C語言沒有泛型指標,也就是現在的void,當時用char*
可以表示指向任意一個型別的指標。
為什麼可以這樣呢?以下面的程式碼為例
int num = 0;
int *ip = #
char *cp = (char *)#
那麼cp
和ip
的值實際上是一樣的,但是他們又不一樣的地方:
- 這裡有一點需要說明的是下面敘述中
&num+4
在程式裡實際上是和指標運算一樣的,我這裡當做地址加減,純粹的地址加減。
- 對
ip
進行運算,比如ip++
將會得到&num + sizeof(int)
,而對cp
進行運算,同樣的,cp++
,得到的是&num + sizeof(char)
,也就是指標運算不一樣 &ip[1]
,&cp[1]
,也是不一樣的,這個就和第一點類似
也就是最主要的就是對地址的解釋不一樣(我是這麼理解的),那麼在返回char*後,可以使用casting,強制轉換型別,既然返回的地址是一樣的,那麼我把這個地址按照我想要的方式去解釋,然後再把地址裡的內容取出來就是我想要的東西。
更直觀的看看下面的程式碼
int *ip = (int *)malloc(2*sizeof(int));
char *p = (char*)ip;
*ip = 1;
*((int *)p+1) = 2;
printf("ip[0]:%d ip[1]%d",ip[0],ip[1]);
將會輸出一下結果ip[0]:1 ip[1]2
,程式碼中把ip
地址首先按照char*
解釋,賦值給了p
,然後在第四行,又將p
地址按照int*
來解釋,那麼p+1
自然就到了&ip[0]+4
的位置。
指標和陣列的聯絡
稍微瞭解一點C語言的人都知道,陣列和指標是不分家的,陣列名就是一個指標,也是陣列的起始地址,一個數組既可以通過下標訪問,又可以通過指標訪問。在程式實際執行過程中,指標訪問是要快一點的,下標訪問每次迭代出下標後,程式會根據下標運算出地址,實際上做了重複運算,這裡不重點敘述。
一個數組array[5]
array
,也是&array[0]
,array[i]
,*array+i
,*&array[0]+i
都是等價的。
多維陣列
看看下面的程式碼:
int array[4][5];
int *p = (array+1);
int *end = &array[3][4];
while(p != end){
*p = 1;
p++;
}
要想看懂這段程式碼,唯一的關鍵就是理解
int *p = (array + 1);
在幹什麼,實際上這句程式碼和下面這句程式碼是等效的
int *p = array[1];
array
是一個4元素陣列,每個元素由5 int陣列構成,所以array[1]
是一個5 int 陣列的名稱,也就是首地址,和array+1
, 相當於&array[0]+sizeof(int[5])
,所以上面的程式碼就做了一件事,遍歷了array[1] [0]
之後的所有元素,賦值為1。
總結
陣列名稱是首地址,也是指標,對它進行運算就是相當於首地址加上其中元素長度。
指標和陣列還有函式的優先順序
指標的優先順序比陣列[]還有函式()都低,因此在宣告一個函式指標時必須這樣:
int (*p)(int arg);
這裡p是一個指標,指向一個函式,函式接收一個int的引數,返回一個int 值
再來看看指標和陣列的優先順序
int *p[5];
int (*p)[5];
第一行大家都比較熟悉,是一個數組,有5個int*
的元素
第二行可能就比較陌生了,p是一個指標,指向一個擁有5個int元素的陣列
陣列和指標的區別
- 最明顯的區別應該就在size上了,比如下面的程式碼
char arr[5];
char *p;
第一行聲明瞭一個5元素的字元陣列,sizeof(arr)
將會返回5,而sizeof(p)
將會返回8(在64位機器上)
這裡又要提到一個很不常見的宣告:
char arr[0];
聲明瞭一個0元素的陣列,那麼sizeof(arr)
是多少呢,如果你實驗一下就會發現,居然是0,這個可以當做指標來用的居然不佔空間,也是很奇特的。