本篇我主要寫了以下四點關於指針的問題
- 字符指針與字符串
- 指針數組
- 多級指針
- void 和const 指針
首先感謝大家的觀看,如果大家能有所收穫,那真是榮幸之至
一、字符指針與字符串
-
C語言通過使用字符數組來處理字符串,通常,我們把char數據類型的指針變量稱爲字符指針變量。字符指針變量與字符數組有着密切關係,它也被用來處理字符串。
-
初始化字符指針是把內存中字符串的首地址賦予指針,並不是把該字符串複製到指針中,此時可以通過指針來修改字符串的內容
char str[] = “Hello World”;
char *p = str;
printf("&str=%p %s\n",&str,str);
*p='h'; *(p+1)='E';
printf("p=%p %s\n",p,p);
由此可以看出,p指向的str的首地址,可以根據p指針來修改字符串的值。如果有人對上述用*p修改有疑問,可以參考我上一篇博客,C語言指針簡介與相關的難點
非常重要
- 在C編程中,當一個字符指針指向一個字符串常量時,不能修改指針指向的對象的值。當你直接將字符串賦值給指針時,該字符串會被認爲是常量,會被存放在靜態區域,所以此時不能修改。
char *p = "Hello World";
*p = 'h'; // 錯誤, 字符串常量不能修改
char *p1 = "Hello World";
char *p2 = "Hello World";
printf("%p\n",&"Hello World");
printf("&p1=%p p1=%p %s\n",&p1,p1,p1);
printf("&p2=%p p2=%p %s\n",&p2,p2,p2);
由結果可知,兩個不同指針被賦予相同的字符串被認爲是一個常量存放在靜態區,兩指針都指向的是該常量的地址
- 使用指針完成字符串的鏈接操作
#include<stdio.h>
int main(){
char ch[50] = "Hello";
char *p = "World";
int i = 0;
while( ch[i]!='\0') //找到原字符串的末尾
i++;
while( *p != '\0'){ //鏈接
*(ch+i) = *p;
i++; p++;
}
*(ch+i) = *p; //在字符串末尾加上結束符
puts(ch);
}
二、指針數組
- 所謂指針數組是指由若干個具有相同存儲類型和數據類型的指針變量構成的集合
- 指針數組的一般說明形式:
<數據類型> *<指針數組名>[<大小>];
指針數組名錶示該指針數組的起始地址
//聲明一個指針數組:
double * pa[2] ,a[2][3];
//把一維數組a[0]和a[1]的首地址分別賦予指針變量數組的數組元數pa[0]和pa[1]:
pa[0]=a[0] ; // 等價pa[0] = &a[0][0];
pa[1]=a[1]; // 等價pa[1] = &a[1][0];
//此時pa[0]指向了一維數組a[0]的第一個元素a[0][0], 而pa[1]指向了一維數組a[1]的第一個元素a[1][0]。
//則a[0][1]就可以用 p[0]+1表示;
指針數組名是個什麼指針?
int *p[2];
q = &p[0] ; //q的定義是什麼?
由指針數據的定義的格式可知指針q的定義如下: <數據類型> * q
該<數據類型>取決於目標的類型,及p的類型,而p的類型爲int *所以q的定義爲: int ** q;這是一個二級指針。
三、多級指針
-
多級指針的定義
把一個指向指針變量的指針變量,稱爲多級指針變量
對於指向處理數據的指針變量稱爲一級指針變量,簡稱一級指針
而把指向一級指針變量的指針變量稱爲二級指針變量,簡稱二級指針 -
二級指針變量的說明形式如下
<數據類型> ** <指針名> ; -
多級指針的運算
- 指針變量加1,是向地址大的方向移動一個目標數據。類似的道理,多級指針運算也是以其目標變量爲單位進行偏移。
- 比如,int **p;p+1移動一個int *變量所佔的內存空間。再比如int ***p,p+1移動一個int **所佔的內存空間。
int a[] = {3, 6, 9};
int *p[2] = {&a[0], &a[1]};
int **q;
q = &p[0]; //等價爲q=a;
printf("%d %d %d\n",a[0],*p[0],**q); //a[0]的表示方法
printf("%d %d %d\n",a[1],*p[1],**(q+1));//a[1]的表示方法
printf("%d %d %d\n",a[2],*(p[1]+1),*(*(q+1)+1));//a[2]的表示方法
- 由圖可知,p[0],p[1]存的是a[0],a[1]的地址,所以p[0]表示a[0]的存的值,q存的是p[0]的地址,故q就表示p[0]的值,及a[0]的地址,所以**q就表示a[0]的值。
- a[3]的地址可由a[2]的地址+1表示,即p[1]+1;同理,p[1]的地址可由q+1表示。所以a[3]的地址等價於 *(q+1)+1。
- 不要問我爲什麼a[3]不能用q+2表示,這說明你還是沒有理解,上面這個圖的結果是從右往左推出來的,而不是從左往右推的,實在理解不了,自己畫個圖理解下或者自己編程看看q+2的地址是啥
四、void和const指針
1. void指針
是一種不確定數據類型的指針變量,它可以通過強制類型轉換讓該變量指向任何數據類型的變量
一般形式爲: void * <指針變量名稱> ;
對於void指針,在沒有強制類型轉換之前,不能進行任何指針的算術運算。
2. const修飾指針
關於const修飾,總之記住一句話:const修飾誰,誰不能改變。
1)常量化指針目標表達式
- 一般說明形式如下:
const <數據類型> * <指針變量名稱>[= <指針運算表達式>] ;
常量化指針目標是限制通過指針改變其目標的數值 ,但<指針變量>存儲的地址值可以修改
int m=10;
const int *p = &m;
p = &n; //right
(*p)++; //error, const修飾*p ,所以*p不能改
2)常量化指針變量
- 一般說明形式如下:
<數據類型> * const <指針變量名稱>[= <指針運算表達式>] ;
使得<指針變量>存儲的地址值不能修改。但可以通過*<指針變量名稱> 可以修改指針所指向變量的數值
int m = 10;
int * const q = &m ;
(*q)++; //right
q = &m; //error ,只能在定義時初始化
3)常量化指針變量及其目標表達式
- 一般說明形式如下:
const <數據類型> * const <指針變量名> = <指針運算表達式> ;
常量化指針變量及其目標表達式,使得既不可以修改<指針變量>的地址,也不可以通過*<指針變量名稱>修改指針所指向變量的值