1. 指針運算
1.1 算術運算
- 加減
+
草慧、-
指針與整數(shù)相加:表示指針指向下個變量。
指針與整數(shù)相減:表示指針指向上個變量高镐。
指針與指針相減:兩個指針的元素間隔個數(shù)。
int arr[]={100,101,102,103,104,105};
int* p = arr;
int* q;
for(int i=0;i<5;++i){
q = p+i;
printf("%d\n",*q);
}
for(int i=0;i<5;++i){
p = q-i;
printf("%d\n",*p);
}
printf("q-p=%d\n",q-p);
- 自增自減
++
脾拆、--
指針能夠算術運算嫉髓,必然能夠自增自減混稽。
int arr[]={100,101,102,103,104,105};
int* p = arr;
for(int i=0;i<5;++i){
printf("%d\n",*p++);
}
for(int i=0;i<5;++i){
printf("%d\n",*p--);
}
*p++
/*p--
操作說明
- 操作數(shù)是指針
- 自增自減
++
、--
優(yōu)先級高于解引用*
計算過程
- 運算
++
/--
宝当,返回的是p
的值(地址),然后p
自加/自減胆萧。 - 運算
*
庆揩,獲取p
指向的值俐东。
等價于
*p;
p=p+1;
自增自減 | 相當于 |
---|---|
*q++ |
*(q++) |
*q-- |
*(q--) |
*++p
/*--p
操作說明
- 操作數(shù)是指針
- 前綴自增自減
++
、--
和解引用*
的結合律是自右向左订晌。 - 前綴自增自減
++
虏辫、--
在解引用*
的右邊,優(yōu)先計算锈拨。
計算過程
- 運算
++
/--
砌庄,p
自加/自減,返回的是p
自加/自減后的值(地址)奕枢。 - 運算
*
娄昆,獲取p
指向的值。
自增自減 | 相當于 |
---|---|
*++q |
*(++q) |
*--q |
*(--q) |
++*q
/--*q
操作說明
-
*
操作數(shù)是指針缝彬,前綴自增自減++
萌焰、--
操作數(shù)是指針指向的值。 - 前綴自增自減
++
谷浅、--
和解引用*
的結合律是自右向左扒俯。 - 解引用
*
在前綴自增自減++
、--
的右邊一疯,優(yōu)先計算撼玄。
計算過程
- 運算
*
,獲取p
指向的值墩邀。 - 運算
++
/--
掌猛,p
指向的值自加/自減。
自增自減 | 相當于 |
---|---|
++*q |
++(*q) |
--*q |
--(*q) |
如果一個表達式里有多個運算符磕蒲,則先進行優(yōu)先級比較留潦,先執(zhí)行優(yōu)先級高的運算符;如果優(yōu)先級相同辣往,那就看結合性兔院,根據(jù)結合方向來做運算。
- 問題
指針與指針可以相加嗎站削?
在不同數(shù)組中可以執(zhí)行上面的操作嗎坊萝?
試一下編譯下面程序
#include <stdio.h>
int main () {
int arr[]={100,101,102,103,104,105};
for(i=0;i<5;++i){
printf("%p\n",arr++);
}
return 0;
}
1.2 比較運算符
==
、!=
许起、<
十偶、<=
、>
园细、>=
本質是比較內存中的地址惦积。
#include <stdio.h>
int main () {
int arr[]={100,101,102,103,104,105};
int* p = arr;
for(int i=0;i<5;++i){
printf("%p\n",p++);
}
return 0;
}
數(shù)組中的元素地址線性遞增。
1.3 單位長度
從上面可以看到猛频,指針的加1減1狮崩,地址并非加1減1蛛勉。
int iarr[] = {1,2,3,4,5,6};
int* p = iarr;
for(int i=0;i<5;++i){
printf("%p\n",p++);
}
char carr[] = {1,2,3,4,5,6};
char* q=carr;
for(int i=0;i<5;++i){
printf("%p\n",p++);
}
- 應用范圍
指針的算術運算表示在一片連續(xù)空間上的移動。
指針的比較運算也是用于一片連續(xù)空間的地址比較睦柴。
常用于數(shù)組等連續(xù)內存诽凌。
2. 指針類型
- 無論指向什么類型,所有指針的大小都是一樣的坦敌,都是地址的大小侣诵。
char* str;
short* ps;
int* pn;
long* pl;
long long* pll;
float* pf;
double* pd;
long double* pld;
- 指針類型轉換
指向不同類型的指針不能直接相互賦值(特例void*
),需要強制類型轉換狱窘。
char* str = "abcd";
int* p = str;
指針類型轉換沒有改變指針內的地址杜顺,也沒有改變指針指向的值,只是改變了移動的單位長度训柴。
#include <stdio.h>
int main(){
char* str = "abcdef";
int* p=(int*)str;
p++;
char* q = (char*)p;
printf("%c\n",*q);
}
-
void
類型的指針
void*
是一種很特別的指針哑舒,表示指向未知類型的指針,并不指定它是指向哪一種類型的數(shù)據(jù)幻馁,而是根據(jù)需要轉換為所需數(shù)據(jù)類型洗鸵。
int n = 0;
int* p = &n;
void* q = p;
int* k = (int*) q;
指針作用小結
- 較大數(shù)據(jù)結構體傳入時做參數(shù)。
- 傳入數(shù)組后仗嗦,對數(shù)組做操作膘滨。
- 函數(shù)需要多個返回值時,作為返回值參數(shù)稀拐。
- 動態(tài)申請內存火邓。
- 避免使用未初始化指針、空指針和野指針德撬。
3. 數(shù)組指針 vs 指針數(shù)組
3.1 數(shù)組指針
指向一個數(shù)組指針稱為數(shù)組指針铲咨。
int n = 0;
int* p = &n;
int arr[] = {1,2,3,4,5,6};
int* q = arr;
3.2 指針數(shù)組
指針是一個類型,也可以組成一個數(shù)組蜓洪,這樣的數(shù)組稱為指針數(shù)組纤勒。
#include <stdio.h>
int main(){
int a = 1;
int b = 2;
int c = 3;
int* p[] = {&a,&b,&c};
for(int i=0;i<3;++i){
printf("%d\n",*p[i]);
}
for(int i=0;i<3;++i){
printf("%d\n",**(p+i));
}
}
[]
的優(yōu)先級高于*
,那么p
先和[]
結合隆檀,說明這是一個數(shù)組摇天。再和int*
結合,說明這個數(shù)組里的每個元素都是一個指針恐仑,每個元素都能保存一個地址泉坐。
4. 常量指針 vs 指針常量
4.1 常量指針const int *p
可以寫作int const *p
,p
是int*
類型裳仆,const
修飾的是*p
腕让,所以*p
是常量,表示p
指向的地址里的值不可修改歧斟,也就是說纯丸,p
里的值不能再重新賦值了司训,但是可以修改p
指向的地址。
int a = 10;
int b = 20;
const int *p = &a;
p = &b; // 可以
*p = 100; // 錯誤
4.2 指針常量int * const p
p
是int*
類型液南,那么const
修飾的是p
,所以p
是常量勾徽,表示p
指向的地址不可修改滑凉,即p
不能再指向別的地方了,但是可以修改p
指向的這個地址里的值喘帚。
int a = 10;
int b = 20;
int * const p = &a;
p = &b; // 錯誤
*p = 100; // 允許
4.3 常量指針常量const int * const p
p
是int*
類型畅姊,兩個const
分別修飾了p
和*p
, 所以p
和*p
都是常量吹由,表示p
指向的地址不可修改若未,同時p
指向的地址里的值也不可修改。
int a = 10;
int b = 20;
const int *const p = &a;
p = &b; // 錯誤
*p = 100; // 錯誤
自由的代價倾鲫,是永遠的警惕粗合。-- C Primer Plus
你定義了一個指針,那就一定要知道這個指針指向的什么地方乌昔,而且你要保證這個指針是真實有效的隙疚,否則我就用程序崩潰來懲罰你。
No. | 例子 | 名稱 | 指向的值 | 地址 |
---|---|---|---|---|
1 |
const int *p /int const *p
|
常量指針 | 不可改變 | 可改變 |
2 | int* const p |
指針常量 | 可改變 | 不可改變 |
3 | const int * const p |
常量指針常量 | 不可改變 | 不可改變 |
*
之前的const
修飾指向的變量磕道,*
之后的const
修飾指針供屉。
問題
下面的q
是什么類型指針?
const int *p,*q;
int const *p,*q;
int* const p,*q;
const int * const p,*q;
0地址
#include <stdio.h>
int main(){
int *p = 0;
printf("%d\n",*p);
}
0
地址是內存中不能訪問的地址溺蕉。在C語言中伶丐,標準庫定義NULL
表示0
地址。
通常用來表示如下:
- 指針沒有初始化
- 返回指針無效