《C指標全解》讓你不再害怕指標
前言:複雜型別說明
要了解指標,多多少少會出現一些比較複雜的型別,所以我先介紹一下如何完全理解一個複雜型別,要理解複雜型別其實很簡單,一個型別裡會出現很多運算子,他們也像普通的表示式一樣,有優先順序,其優先順序和運算優先順序一樣,所以我總結了一下其原則:從變數名處起,根據運算子優先順序結合,一步一步分析.下面讓我們先從簡單的型別開始慢慢分析吧:
表示式 | 含義 |
---|---|
int p; | 這是一個普通的整型變數 |
int *p; | 首先從P處開始,先與*結合,所以說明P是一個指標,然後再與int結合,說明指標所指向的內容的型別為int型.所以P是一個返回整型資料的指標 |
int p[3]; | 首先從P處開始,先與[]結合,說明P是一個數組,然後與int結合,說明數組裡的元素是整型的,所以P是一個由整型資料組成的陣列 |
int *p[3]; | 首先從P處開始,先與[]結合,因為其優先順序比較高,所以P是一個數組,然後再與*結合,說明數組裡的元素是指標型別,然後再與int結合,說明指標所指向的內容的型別是整型的,所以P是一個由返回整型資料的指標所組成的陣列 |
int (*p)[3]; | 首先從P處開始,先與*結合,說明P是一個指標然後再與[]結合(與"()"這步可以忽略,只是為了改變優先順序),說明指標所指向的內容是一個數組,然後再與int結合,說明數組裡的元素是整型的.所以P是一個指向由整型資料組成的陣列的指標 |
int **p; | 首先從P開始,先與*結合,說是P是一個指標,然後再與*結合,說明指標所指向的元素是指標,然後再與int結合,說明該指標所指向的元素是整型資料.由於二級指標以及更高階的指標極少用在複雜的型別中,所以後面更復雜的型別我們就不考慮多級指標了,最多隻考慮一級指標. |
int p(int); | 從P處起,先與()結合,說明P是一個函式,然後進入()裡分析,說明該函式有一個整型變數的引數然後再與外面的int結合,說明函式的返回值是一個整型資料 |
int (*p)(int); | 從P處開始,先與指標結合,說明P是一個指標,然後與()結合,說明指標指向的是一個函式,然後再與()裡的int結合,說明函式有一個int型的引數,再與最外層的int結合,說明函式的返回型別是整型,所以P是一個指向有一個整型引數且返回型別為整型的函式的指標 |
int *(*p(int))[3]; | 從P開始,先與()結合,說明P是一個函式,然後進入()裡面,與int結合,說明函式有一個整型變數引數,然後再與外面的*結合,說明函式返回的是一個指標,然後到最外面一層,先與[]結合,說明返回的指標指向的是一個數組,然後再與*結合,說明數組裡的元素是指標,然後再與int結合,說明指標指向的內容是整型資料.所以P是一個引數為一個整資料且返回一個指向由整型指標變數組 成的陣列的指標變數的函式. |
說到這裡也就差不多了,我們的任務也就這麼多,理解了這幾個型別,其它的型別對我們來說也是小菜了,不過我們一般不會用太複雜的型別,那樣會大大減小程式的可讀性,請慎用,這上面的幾種型別已經足夠我們用了.
細說指標
指標的型別
指標所指向的型別
指標的值
指標本身所佔據的記憶體區
指標的算術運算
運算子&和*
指標表示式
陣列和指標的關係
指標和結構型別的關係
指標和函式的關係
指標型別轉換
指標的安全問題
看下面的例子:
例十八:
char s='a';
int *ptr;
ptr=(int*)&s;
*ptr=1298;
指標ptr是一個int*型別的指標,它指向的型別是int。它指向的地址就是s的首地址。在32位程式中,s佔一個位元組,int型別佔四個位元組。最後一條語句不但改變了s所佔的一個位元組,還把和s相臨的高地址方向的三個位元組也改變了。這三個位元組是幹什麼的?只有編譯程式知道,而寫程式的人是不太可能知道的。也許這三個位元組裡儲存了非常重要的資料,也許這三個位元組里正好是程式的一條程式碼,而由於你對指標的馬虎應用,這三個位元組的值被改變了!這會造成崩潰性的錯誤。
讓我們再來看一例:
例十九:
char a;
int *ptr=&a;
ptr++;
*ptr=115;
該例子完全可以通過編譯,並能執行。但是看到沒有?第3句對指標ptr進行自加1運算後,ptr指向了和整形變數a相鄰的高地址方向
的一塊儲存區。這塊儲存區裡是什麼?我們不知道。有可能它是一個非常重要的資料,甚至可能是一條程式碼。而第4句竟然往這片儲存區裡寫入一個數據!這是嚴重的錯誤。所以在使用指標時,程式設計師心裡必須非常清楚:我的指標究竟指向了哪裡。在用指標訪問陣列的時候,也要注意不要超出陣列的低端和高階界限,否則也會造成類似的錯誤。在指標的強制型別轉換:ptr1=(TYPE*)ptr2中,如果sizeof(ptr2的型別)大於sizeof(ptr1的型別),那麼在使用指標ptr1來訪問ptr2所指向的儲存區 時是安全的。如 果sizeof(ptr2的型別)小 於sizeof(ptr1的型別),那麼在使用指標ptr1來訪問ptr2所指向的儲存區時是不安全的。至於為什麼,讀者結合例十八來想一想,應該會明白的。