指針相關(guān)內(nèi)容(C語言)-創(chuàng)新互聯(lián)

1、什么是指針

在內(nèi)存中,每一個自己單元,都要一個編號,稱為地址。在虛擬內(nèi)存中,也同樣如此。

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計、成都網(wǎng)站建設(shè)服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)北戴河免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了上千多家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(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)指針是一個地址值,可以進行關(guān)系運算。同理,不同類型的指針進行該運算沒有意義。

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]也能訪問對應(yīng)元素
	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ù)就應(yīng)該不需要說了。

然后?*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)換為相應(yīng)的指針聲明,比如使用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)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧

分享標題:指針相關(guān)內(nèi)容(C語言)-創(chuàng)新互聯(lián)
瀏覽地址:http://bm7419.com/article46/dgodeg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站改版、搜索引擎優(yōu)化、網(wǎng)站導(dǎo)航、外貿(mào)建站、動態(tài)網(wǎng)站、移動網(wǎng)站建設(shè)

廣告

聲明:本網(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)

成都定制網(wǎng)站網(wǎng)頁設(shè)計