在內(nèi)存中,每一個自己單元,都要一個編號,稱為地址。在虛擬內(nèi)存中,也同樣如此。
專注于為中小企業(yè)提供成都網(wǎng)站設計、成都網(wǎng)站建設服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)北戴河免費做網(wǎng)站提供優(yōu)質(zhì)的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千多家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。專門用來存放地址的變量稱為指針變量,簡稱指針。
不管是什么類型的指針變量,在32位機上,占4個字節(jié);在64位機上,占8個字節(jié)
2、指針運算(1)p是一個 指針變量;p + n 或者? p - n ,實際得到的地址量是
p + / - sizeof(* p)??*n
(2)不同數(shù)據(jù)類型的兩個指針進行加減運算是無意義的
p 、q 是兩個相同類型的指針變量;
p - q 得到的是 (p的地址在?- q的地址值)/sizeof(*p)
(3)指針是一個地址值,可以進行關系運算。同理,不同類型的指針進行該運算沒有意義。
3、指針和數(shù)組(1)本質(zhì)的區(qū)別是指針是指針是一個變量,用來儲存地址,數(shù)組名是地址常量;
數(shù)組名是地址常量,數(shù)組名的類型是數(shù)組元素的指針類型。
在把數(shù)組名當成一個地址使用的時候,和&數(shù)組名[0]是等價的。
更進一步的講,比如 int arr[5]={0};
arr+ i 和 &arr[i]是等價的,因此 *(arr + i) 和 arr[i]是等價的。對數(shù)組的下標操作本質(zhì)是地址操作,因此,i[arr] 和 arr[i] 其實是一樣的。
在把數(shù)組名當一個數(shù)組類型使用的時候,才更符合我們常規(guī)意義上的數(shù)組概念。
比如 sizeof(arr) 和 &arr。
#include#includeint main(void)
{
int arr[5] = {0,1,2,3,4};
int *p1 = arr; //arr作為地址使用,類型是 int *型 和 &arr[0] 等價
int *p2 = &arr[0];
printf("%p,%p\n",p1,p2);
printf("%d\n",sizeof(a));//arr作為數(shù)組類型使用
int (*p3)[5] = &arr;//arr作為數(shù)組類型使用,對arr取地址,得到的是一個指向數(shù)組的指針
printf("%p\n",p3);//值和&arr[0]相同,但類型是不一樣的
return 0;
}
(2)在說明多維數(shù)組和指針之前,得先區(qū)分一下數(shù)組指針和數(shù)組指針。
顧名思義,數(shù)組指針是一個指向數(shù)組的指針,形式如 int (*p)[5],
而數(shù)組指針是一個數(shù)組元素為指針的數(shù)組,形式如 int int *p[5].
#includeint main(void)
{
int arr[3][3]={{1,2,3},{4,5,6},{7,8,9}};
int (*p1)[3]=arr;//數(shù)組指針
printf("%p\n",p1);
for(int (*row)[3] = arr;row< arr+3; ++row){
printf("%p:",row);
for(int *line = *row;line< *row + 3; ++line){
printf("%d\t",*line);
}
printf("\n");
}
p1 = &arr[0];//arr作為地址,類型和值都和&arr[0]相同
printf("%p\n",p1);
for(int (*row)[3] = &arr[0];row< &arr[3]; ++row){
printf("%p:",row);
for(int *line = &(*row)[0];line< &(*row)[3]; ++line){
printf("%d\t",*line);
}
printf("\n");
}
//以上兩種方式直接通過指針變量的方式訪問多維數(shù)組元素
for(int i = 0; i< 3; i++){
printf("%p:",&arr[i]);
for(int j = 0; j< 3; j++){
printf("%d%d%d\t",arr[i][j],*(arr[i]+j),*(*(arr+i)+j));
}
printf("\n");
}
//所以,arr+i 和 &arr[i],*(arr + i)和 arr[i] 是等價的
//*(arr + i) + j、arr[i] + j、 &arr[i][j]是等價的
//*(*(arr+i)+j) 、 *(arr[i] + j) 、 arr[i][j]是等價的
//或者說,arr[i][j]的下標寫法只是對某個具體數(shù)數(shù)組元素的訪問更方便,
//本質(zhì)上編譯器其實對數(shù)組下標的寫法會自動變成地址操作
int arr1[3] = {1,2,3};
int arr2[3] = {4,5,6};
int arr3[3] = {7,8,9};
int *p2[3] = {arr1,arr2,arr3};//指針數(shù)組
printf("%p\n%p\n%p\n",p2[0],p2[1],p2[2]);
for(int i = 0; i<3 ;i++)
{
printf("%p:",*(p2 + i));
for(int *line = *(p2 + i); line< *(p2 + i) +3; ++line)
printf("%d\t",*line);
printf("\n");
}
return 0;
}
(3)多維數(shù)組的存儲方式
c語言本質(zhì)上其實只有一維數(shù)組,數(shù)組元素的訪問本質(zhì)都是數(shù)組元素地址的解引用
#includetypedef int (*ptr)[4];
int main(void)
{
int arr1[12] = {1,2,3,4,5,6,7,8,9,10,11,12};
int (*p1)[4] = NULL;
p1 = (ptr)arr1;//把 arr1類型強轉(zhuǎn),但其實不強轉(zhuǎn)程序運行結(jié)果也是一樣的,就是warning類型不一致
for(int i = 0;i< 3;i++){
for(int j = 0;j< 4;j++)
{
printf("%d,%d\t",*(*(p1+i)+j),p1[i][j]);
}
printf("\n");
}
//一、arr并不是二維數(shù)組,但是使用數(shù)組指針也能訪問數(shù)組元素
//二、p1并不是二維數(shù)組,但是使用p[i][j]也能訪問對應元素
int arr2[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
int *p2 = (int *)arr2;
for(int i = 0; i< 12; i++)
{
printf("%d,%d\t",p2[i],*(p2+i));
}
printf("\n");
return 0;
}
2、指針和函數(shù)(1)函數(shù)指針
函數(shù)的地址:如果在程序中定義了一個函數(shù),那么在編譯時,系統(tǒng)會為該函數(shù)代碼分配存儲空間,這段空間的首地址被稱為函數(shù)的地址,而且函數(shù)名表示的就是該地址。因此我們可以定義一個指針變量來存放函數(shù)地址,這個指針變量就叫函數(shù)指針變量,簡稱函數(shù)指針。
#includeint max(int ,int );
int main(void)
{
int (*fp)(int,int) = &max;
int a = (*fp)(1,2);
printf("%d\n",a);
int b = fp(1,2);
printf("%d\n",b);
int (*fp2)(int,int) = max;
int c = (*fp2)(1,2);
printf("%d\n",c);
printf("%p,%p\n",max,&max);
printf("%ld,%ld\n",sizeof(max),sizeof(&max));
return 0;
}
int max(int x,int y){
return x>y?x:y;
}
在程序中定義了?int (*fp)(int,int),
含義是:定義了一個指針變量fp,該指針變量可以指向返回值為int型,且有兩個整型參數(shù)的函數(shù),
fp的類型為 int(*)(int,int).
對函數(shù)指針變量賦值后,就可以通過解引用的方式調(diào)用fp所指向的函數(shù)了。ANSI C標準運行我們將將(*fp)(1,2)簡寫成fp(1,2),但要明白這種寫法只是一種簡寫形式。
另外,對指針變量進行賦值,可以直接使用函數(shù)名,也可以&函數(shù)名,因為地址值是相同的,怎么解釋這個地址只看函數(shù)指針變量的類型。就像在上個部分數(shù)組與指針,把不同類型的地址賦值給數(shù)組指針,程序運行結(jié)果并不會有不同,只是編譯會有警告提示。而在函數(shù)指針這里,并不會有警告。盡管max函數(shù)名是int(int,int)類型,而&max才是int(*)(int,int)類型。
(3)指針函數(shù)
指針函數(shù)就比較簡單了,就是返回值是一個地址類型的函數(shù)
#includeint *query(int *arr,int n);
int main(void)
{
static int arr_score[10] = {87,89,85,76,65,70,72,85,97,99};
for(int i = 0 ;i< 10; i++)
printf("%d\t", *query(arr_score,i));
printf("\n");
int *(*fp)(int *arr, int n) = &query;
for(int i = 0 ;i< 10; i++)
printf("%d\t", *(*fp)(arr_score,i));
printf("\n");
return 0;
}
int *query(int *arr,int n){
return arr + n;
}
這里對 int *(*fp)(int *arr, int n) = &query 指針函數(shù)的指針的定義
和*(*fp)(arr_score,i) 該指針的調(diào)用和解引用做一下解釋。
首先,()的優(yōu)先級是最高的,所以(*fp)說明 fp是一個指針變量,然后前面的int *說明表示這個指針變量可以指向返回值為int *的函數(shù);后面括號中的參數(shù)就應該不需要說了。
然后?*fp,首先fp是函數(shù)指針, *fp就是該指針所指向的函數(shù),由于函數(shù)運算符()的優(yōu)先級高于單目運算符*,所以先給函數(shù)傳遞函數(shù)參數(shù),然后對結(jié)果進行* 解引用。
3、指針和字符串在c語言中,并沒有字符串這個數(shù)據(jù)類型。通常借助于字符數(shù)組來存儲字符串。而字符指針可以存儲字符串的起始地址,并且和數(shù)組一樣,字符數(shù)組名就代表了字符串的起始地址。這樣,我們就可以用指針來處理字符串。
字符串或者說字符數(shù)組和數(shù)組在操作上有很多共同之處,但也自己的特殊性。
#includeint main(void)
{
char str[] = "hello,world!";
char *strp = "hello,world";
printf("%d\n",sizeof(str));
printf("%d\n",strlen(str));
int arr[] = {1,2,3,4,5};
printf("%d\n",sizeof(arr)/4);
return 0;
}
1、字符串數(shù)組默認以‘\0’作為字符串結(jié)束標志,所以會自動添加一個‘\0’字符在字符串末尾。
2、注意str 和 strp初始化的區(qū)別。詳細可以參考(25條消息) C 內(nèi)存管理(代碼區(qū)、數(shù)據(jù)區(qū)、堆區(qū)、棧區(qū))_熹微seesea的博客-博客
3、不能像對數(shù)組名取地址操作一樣對字符數(shù)組名取地址。
#includevoid tocapital(char *str);
int main(void)
{
char str[] = "hello,world!";
printf("%s\n",str);
tocapital(str);
printf("%s\n",str);
return 0;
}
void tocapital(char *str){
while(*str != '\0'){
if(*str >= 'a' && *str<= 'z')
*str -= 32;
str ++;
}
}
4、數(shù)組作為函數(shù)參數(shù)在c語言中,我們無法將一個數(shù)組(包括字符數(shù)組)作為函數(shù)參數(shù)直接傳遞。如果我們使用數(shù)組名作為參數(shù),那么數(shù)組名會被轉(zhuǎn)換為指向該數(shù)組第一個元素的指針。
例如,在3中的程序使用printf("%s\n",str)和使用printf(”%s\n“,&str[0])完全等效。
在寫自定義函數(shù)時,將數(shù)組作為函數(shù)參數(shù)毫無意義c語言中會自動地將作為參數(shù)的數(shù)組聲明轉(zhuǎn)換為相應的指針聲明,比如使用void tocapital(char str[])和使用void tocapital(char *str)是相同的。
一個常見的例子就是函數(shù)main的第二個參數(shù):
int main(int argc,char * argv[]){.....}和
int main(int argc,char **argv){......}是等價的
參考《c陷阱與缺陷》
5、野指針(25條消息) 野指針和常見的內(nèi)存錯誤_熹微seesea的博客-博客
6、常量指針,指向常量的指針和指向常量的常量指針(1)int * const p;
p是一個常量類型的指針,一旦初始化就不能修改指針的值,但是這個指針所指向的地址上存儲的值可以改變
(2)const int *p;
p是一個指向常量的指針,常量自然不能修改,但是可以改變指針變量的值
(3)const int *const p;
同時滿足(1)和(2)的內(nèi)容
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧
分享標題:指針相關內(nèi)容(C語言)-創(chuàng)新互聯(lián)
瀏覽地址:http://aaarwkj.com/article46/dgodeg.html
成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、搜索引擎優(yōu)化、網(wǎng)站導航、外貿(mào)建站、動態(tài)網(wǎng)站、移動網(wǎng)站建設
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容