
此文為指針系列第二篇:
C語言精要總結-指針系列(一)C語言精要總結-指針系列(二)
指針運算
前面提到過指針的解引用運算,除此之外,指針還能進行部分算數運算、關系運算
指針能進行的有意義的算術運算包括加減法運算,但不包括乘除運算。并且運算存在諸多限制。
加法運算
指針加法運算隻适合指針與整數,不能用在指針與指針。
指針加上或者減去一個整數n,是存儲的位址值加上或者減去n*指針指向類型的空間大小。也就是
結果指針 = 指針 ± n * 指針指向類型空間大小。
例如int類型的整數指針+1,運算結果依然是一個整型指針,其存儲的位址值為原指針值+1*4,這是因為整型變量占用4個位元組的空間。這個計算結果,恰好在目前指針指向基礎上,向下偏移指向下一個相同類型的空間。如下圖
指針與整數的加減法一般用在疊代連續的記憶體空間-數組,如果運算得到的指針指向第一個元素之前或者最後一個元素之後,可能會産生非法讀寫記憶體中斷,就像引用一個未初始化的指針一樣不可預知。
指針除了可以與整數做加減運算,連個指針之間還可以做減法運算(不能做加法運算)且必須是同類型的指針。運算結果為兩個指針指向位址之間,可以存放多少此類型的變量數(或其相反數),類型為ptrdiif_t類型(一種有符号整數類型)。
1 int * p1 = (int *) 0x100;
2 int * p2 = (int *) 0x10c;
3 printf("p2-p1 : %d\n",p1 - p2); // -3
如上程式将輸出-3,也如上圖所示,這3個空間存放着 10、80、6三個整型變量。
指針與指針相減,一般也用在連續位址空間-數組中。此時兩個指針相減跟下标索引相減是等價的。
1 int arr[5] ;
2 printf("%d\n",&arr[4] - &arr[0] == 4 - 0); // 1
常量指針與指針常量
常量指針表示通過此指針,不能修改其指向的記憶體區域的内容,指針本身的值是可以修改為指向另一個變量,雖然可以修改指向另一個變量,但是依然不允許修改指向變量裡的内容。常量指針一般用在函數一些函數參數中,以隻讀的方式傳遞函數參數。這裡說明一點C語言除了宏定義常量和枚舉之外,是不能定義普通常量的,隻可用const定義隻讀變量,而常量指針指向的是就是一個隻讀變量。隻讀變量是不能修改的變量。
1 const int readOnlyVar = 10;
2 int * pROVar = (int *) & readOnlyVar;
3 * pROVar = 11;
4 printf("%d\n",readOnlyVar);
而指針常量表示指針本身的内容不可變(指向不可變),是以,定義指針常量時必須同時初始化一個位址值。
定義指針常量和定義常量指針的方式差別在于const關鍵字的位置
int const * p1 ;
const int * p2 ;
int * const p3 = NULL;
const int * const p4 = NULL;
以*号為界限,看cosnt修飾的是誰,如果修飾的是類型關鍵字,表示指向常量類型——常量指針,如果修飾的是指針辨別符,表示指針常量。顯然p1、p2是常量指針,p3是指針常量,p4既是常量指針,又是指針常量。
指針數組
指針數組指元素由指針組成的數組,一般用在存儲字元串組,例如下面的程式
1 char * options[5] = {
2 "--list",
3 "--prefix",
4 "--with"
5 };
6 for (i = 0 ; i < 5 ;i ++)
7 {
8 if (NULL != options[i]){
9 printf("%s\n",options[i]);
10 }
11 }
此時指針數組前三個成員指向靜态區的三個字元串常量,而後兩個指針被預設初始化為0(NULL)
C語言中出現的字元串字面量,實際是存儲在靜态資料區的字元串常量。當一個字元串出現在C語言表達式中,其實際值是一個指針常量。如下面聲明一個指針常量的代碼
char * str = "hello";
可以用另一段代碼來描述,即先在某處為字元串配置設定空間,記錄指向第一個字元的一個指針常量,并将字元拷貝進去。代碼如下
char * const strBuff = (char * ) malloc (6);
strcpy(strBuff,"hello");
char * str = strBuff;
free(strBuff);
既然明确字元串常量在代碼中實際是一個指針常量,是以其也可以參與運算。代碼如下
printf("%c\n",* "hello"); // h
printf("%s\n", "hello" + 1);// ello
常量指針“hello”+1後得到一個新的指針,按指針運算的規則将指向下一個e,是以以字元串形式輸出ello
除此之外指針輸在還用在處理許多多元數組的地方,這在後續的章節中會提到。
常量指針數組與指針常量數組
常量指針數組表示元素都指向常量的數組。定義方式如下
1 const char * options[5] = {
2 "--list",
3 "--prefix",
4 "--with"
5 };
當然,這裡的例子,const加與不加沒太大差別,因為即便不加const關鍵字,options中的每一個元素依然是指向一個字元串常量,是不能修改的。例如要将“--list”中的第2個‘-’換成'+'号,下面的代碼是行不通的,方法隻有讓指針指向一個全新的字元串常量(因為是常量指針,是以指針本身的内容可以修改)
* (options[0] + 1) = '+';
加上const的好處是,讓編譯器或者IDE工具在運作之前便告知你此類代碼存在的問題。關于字元串常量,下面的異常代碼可能更易懂一些
char * str = "hello";
*(str + 3) = 'w';
指針常量數組表示每個指針元素都是不可修改的(指向固定了),但是其指向内容,視情況是可以修改的。
1 char * const options[5] = {
2 "--list",
3 "--prefix",
4 "--with"
5 };
當然,因為字元串常量的緣故,上面的代碼定義了一個指針元素、指針元素指向區域内都不可變的指針數組。例如,像下面的代碼都是非法的
1 options[0] = tmpStr; // 修改指針指向新的字元串常量
2 *(options[0]) = '+'; // 修改第一個元素指向區域的内容
下一系列将用一兩個複雜的案例詳細講解指針與數組的關系。