1.1 定義
在計算機內部存儲器(簡稱內存)中,每一個字節單元,都有一個編號,稱為地址。在C語言中,內存單元的地址稱為指針,專門用來存放地址的變量,稱為指針變量(pointer variable)。在不影響理解的情況下,把地址、指針、指針變量,都叫指針。
1.2 指針類型
1.2.1 構成
目標類型 *
-------- -
| |
| +----->數據為地址
+----------->任何類型
1.2.2 編碼結構;無符號整數
1.2.3 長度:與機器位數有關
1.2.4 字面常量:NULL (void *)0 //表示指針變量中存的內容為0
注意: izeof(指針)一定是等于計算機的位數,與目標類型無關。
1.3 定義指針變量
1.31 定義指針變量的方法:
(1) 確定目標(變量)類型:char
(2) 確定指針類型:char *
(3) 定義指針變量:char *p;
實例:
實例:針對c[2][3]
1.3.2 認識指針變量
認識指針變量類型 ---> 認識目標類型
1.3.3 語法原理(注意觀察)
變量 變量的指針類型 指向變量的指針變量定義
int a; int * int *pl
int a[3]; int (*)[3] int (*pr)[3];
char *a[3] char *(*)[3] char *(*p)[3];
1.4 取地址運算
語法:
&a(變量, 數組, 函數)
1.5 賦值運算
1.5.1 語法:p = a;
1.5.2 操作數類型:a和p類型相同
1.5.3 運算法則
(1) a的類型和p不相同時,編譯器嘗試自動轉換:
a的類型轉為p類型, 但p最好是void * 所有的編譯器都行
(2) a--->p
1.5.4 結果:p的值,結果的類型是a的類型。
1.5.5 寫運算的思路
(1) 確定運算符
(2) 確定操作數(類型)
1.5.6 看運算的思路:
(1) 確定操作數類型
(2) 確定運算法則
1.6 求目標
1.6.1 語法:*p
1.6.2 操作數類型:p必須為指針類型,但不能是void*。
1.6.3 法則:如果p = &a; 則 *p 就是a
1.6.4 結果:a
總結:px — 指針變量,它的內容是地址量。
*px — 指針所指向的對象,它的內容是數據。
&px — 指針變量占用的存儲區域的地址,是個常量。
1.7 移動指向
1.7.1語法
p + n
p - n
p++, p--, ++p, --p
實例:
1.7.2操作數類型
p:p必須為指針,最好為非void*類型,gcc允許對void*的指針進行移動指向,但是其他編譯器不一定可以
n:n必須為整數
1.7.3 運算法則
p + n
向地址增加方向移動n個目標, 即: p中的地址 + sizeof(目標類型也就是*p) * n
注意:sizeof(p)的大小一直為4.注意是sizeof(*p)
gcc允許p為void*,p + n表示將p中的地址加n
p - n
向地址減小方向移動n個目標, 即: p中的地址 - sizeof(目標類型) * n
p++
取p的值,作為結果,然后p = p + 1
++p
p = p + 1,然后取p的值,作為結果
p—
取p的值,作為結果,然后p = p - 1
--p
p = p – 1,然后取p的值,作為結果
注意:函數類型的指針不能做加減運算。
實例:
1.8 求指針之間的目標個數
1.8.1 語法
p1 - p2
1.8.2 操作數類型
p1和p2必須為相同類型的指針
如果p1和p2的類型都為void * 運算前都會被自動轉換為long類型
1.8.3. 運算法則
(1) p1和p2類型為非void * 時
(p1中的地址 - p2中的地址) / sizeof(目標類型)
(2) p1和p2的類型為void *時(可能會有編譯器不支持)
p1中的地址 - p2中的地址
1.8.4 結果
目標個數
實例:
1.9 關系運算
>, >=, <, <=, ==, !=
都可以用到指針類型數據, 但通常只用== 和 !=
1 語法
p1 == p2
2. 操作數類型
p1和p2類型相同
3. 運算法則
比較p1和p2中的地址
4. 結果
布爾值
注意:指針的[]運算
1.語法:p[n]
2.操作數類型:p 必須為指針或數組,n 必須為整數
3.運算法則:p[n] <==> *(p + n)
1.10指針常量
1.10.1定義:只讀的指針變量
例子:
int a = 0;
int * const p1 = &a;(1)
const int *p2 = &a; (2)
int const *p3 = &a; (3)
const int * const p4 = &a; (4)
(1)中p1鎖定,不能p++,或者p=p+1等操作
(2)中 int被鎖定,a的值不能被修改,但p可以操作
(3)同(1)
(4)同(1)+(2)
注意:const int i;
int *const p = &i;//出現警告,因為是常量,但p認為,他的目標是可讀可寫,權限增加
1.11 數組 vs 指針
1.11.1 概念
指針數組: int * pa[5]; //實質是數組,數組的元素是指針
數組指針: int (*pa)[5]; //實質是指針,目標類型是個數組
數組的指針:數組的指針是指數組在內存中的起始地址,即第一個數組元素的地址。
1.11.2 一維數組 vs 指針
(1) 數組名, 在運算中(定義和聲明除外都其他情況都是運算,但sizeof和&運算外), 可以被理解成指向第1個元素的指針(常量)
(2) a[n] 等價于 *(a + n)
(3) &a[n] 等價于 a + n
總結:數組類型和指針類型都可以做[]運算
指針變量和數組在訪問數組中元素時,一定條件下其具有相同的形式,因為指針變量和數組名都是地址量。但指針變量和數組的指針(或叫數組名)在本質上不同,指針變量是地址變量,而數組的指針是地址常量
理解:由a[n]是一維數組可以得到:
(1) &a[n][0] 等價于 a[n]
即: a[n], 在運算中, 可以被理解成a[n][0]的指針
即: int *pl = a[n]; 語法正確
(2) a[n][m] 等價于 *(a[n] + m)
1.12字符指針與字符串
初始化字符指針是把內存中字符串的首地址賦予指針,并不是把該字符串復制到指針中。
注意:在C編程中,當一個字符指針指向一個字符串常量時,不能修改指針指向的對象的值。
補充:多級指針:指向指針的指針