真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

c++指針詳解-創(chuàng)新互聯(lián)

文章目錄
    • 指針
      • 1、 使用指針遍歷[數(shù)組](https://blog.csdn.net/m0_62870588/article/details/123787052)
      • 2、指針的概念與理解
      • 3、指針的創(chuàng)建與初始化
      • 4、指針的基本操作
      • 5、指針的算數(shù)操作
      • 6、[const](https://blog.csdn.net/m0_62870588/article/details/123399735)指針
      • 7、指針的[數(shù)組和數(shù)組](https://blog.csdn.net/m0_62870588/article/details/123787052)的指針
      • 8、指針的指針
      • 9、const_cast 與reinterpret_cast

10年積累的成都網(wǎng)站制作、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)經(jīng)驗(yàn),可以快速應(yīng)對(duì)客戶(hù)對(duì)網(wǎng)站的新想法和需求。提供各種問(wèn)題對(duì)應(yīng)的解決方案。讓選擇我們的客戶(hù)得到更好、更有力的網(wǎng)絡(luò)服務(wù)。我雖然不認(rèn)識(shí)你,你也不認(rèn)識(shí)我。但先網(wǎng)站設(shè)計(jì)制作后付款的網(wǎng)站建設(shè)流程,更有儀征免費(fèi)網(wǎng)站建設(shè)讓你可以放心的選擇與我們合作。指針

指針是c++中的一個(gè)核心概念,是一名c++程序員可以直接對(duì)內(nèi)存進(jìn)行操作的一種工具,這樣的工具就是一把雙刃劍,一面可以實(shí)現(xiàn)一些非常優(yōu)化的程序,另一方面也會(huì)導(dǎo)致一些難以調(diào)試的錯(cuò)誤。


1、 使用指針遍歷數(shù)組

示例:

#includeusing namespace std;

//使用指針遍歷數(shù)組

int main()
{int arr[5] = {0, 1, 2, 3, 4 };
	int *ptr = arr;
	for (int i = 0;i< 5 ;i++)
	{cout<< *ptr<< " ";
		ptr++;
		//也可以直接寫(xiě)成 cout<< *(ptr++)<< " ";
		}
	cout<< endl;
	return 0 ;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
示例中涉及指針的初始化、解引用操作以及自增,看一個(gè)有趣的語(yǔ)句“int *ptr = arr;”,該語(yǔ)句用數(shù)組名初始化指針。在這里數(shù)組名代表的是數(shù)組第一個(gè)元素的地址,之后在循環(huán)內(nèi)程序會(huì)遞增指針以指向數(shù)組的后面幾個(gè)元素。


2、指針的概念與理解

指針(Pointer),從其英文字面上來(lái)理解就是一個(gè)指向某一物件的東西,在程序中就是指向數(shù)據(jù)的地址(Address)。計(jì)算機(jī)的內(nèi)存可以看作是一個(gè)緊密排列的數(shù)據(jù)序列,每一小塊數(shù)據(jù)序列,每一小塊數(shù)據(jù)(也就是字節(jié))的旁邊都有一個(gè)編號(hào)代表數(shù)據(jù)地址。這在現(xiàn)實(shí)中可以用房屋的地址來(lái)理解,我們可以說(shuō)這一棟房子是小李家,也可以說(shuō)一棟房子是xx路xxx號(hào)(指針表示)。對(duì)于上面的示例可以用一個(gè)圖來(lái)理解ptr 和 arr 到底指的是什么。

arrptr
203204205206207
01234
假設(shè)arr的地址是203,那么數(shù)組后面幾個(gè)元素的地址依次遞增(這個(gè)例子中因?yàn)閿?shù)組的類(lèi)型為 int ,所以 其實(shí)真是的地址需要依次增加4個(gè)字節(jié))。指針實(shí)際上就是內(nèi)存地址,所以arr的值就是203,而當(dāng)ptr指向數(shù)組最后一個(gè)元素的時(shí)候,它的值為207.如果我們想要獲取某一個(gè)地址下存儲(chǔ)的數(shù)據(jù),就可以使用ptr來(lái)獲得。

指針的含義:

#includeusing namespace std;

//指針的含義

int main()
{int arr[5] = {0, 1, 2, 3, 4 };
	int *ptr = arr;
	for (int i = 0; i< 5 ; i++)
	{cout<< *ptr<< " ";
		cout<< "地址:"<< ptr<

運(yùn)行結(jié)果:
 指針代表地址
可以看到,數(shù)組的第一個(gè)元素的十六進(jìn)制地址是:0x7ffd83fdbcd0
(不同計(jì)算機(jī)以及同一計(jì)算機(jī)每次運(yùn)行該程序得到的地址都有可能與示例中的地址不同),第二個(gè)元素的地址是:0x7ffd83fdbcd4
,每個(gè)元素之間的距離正好是 int 的大小-----4 字節(jié)。


3、指針的創(chuàng)建與初始化

指針的創(chuàng)建與初始化示例:

#includeusing namespace std;

//指針的創(chuàng)建和初始化

int main()
{float *floatPtr = NULL;
	string *strPtr;
	int *intPtr1, *intPtr2;
	int* intPtr3,  intPtr4; //intPtr4只是一個(gè)整數(shù)
       return 0 ;
}

通過(guò)示例可以看到,指針的聲明就是在變量類(lèi)型名和變量名之間加上星號(hào)(*),并可以并可以任意選擇讓星號(hào)緊貼類(lèi)型名
(int * intPtr3,)或者變量名
(float *floatPtr = NULL; string *strPtr; int *intPtr1, *intPtr2;)的代碼風(fēng)格。然而緊貼類(lèi)型名的代碼風(fēng)格會(huì)給人造成“int *”是一個(gè)整體的感覺(jué),初學(xué)者很容易在聲明多個(gè)指針的時(shí)候遺漏后面變量名前的星號(hào),就像intPtr4一樣,感覺(jué)像是定義了一個(gè)指針,其實(shí)只是一個(gè)整型。正確的語(yǔ)法是像intPtr2那樣在前面加上一個(gè)星號(hào),不管與星號(hào)之間有沒(méi)有空格。

此外,示例中只有第一樣的floatPtr初始化了,但是實(shí)際編程中我們一定要初始化所有指針,就跟變量一樣。floatPtr的初始值NULL是一個(gè)宏定義,它的實(shí)際數(shù)值是0,也就是地址:0x00000000.一般我們都會(huì)把指針初始化為NULL,也叫做空指針,這給我們一個(gè)統(tǒng)一可管理的異常值。在程序中,我們只要檢查指針是否為空就知道指針是否指向有效數(shù)據(jù)了。

**提示:**如果指針沒(méi)有初始化,它可能指向一個(gè)未知的地址,那么我們?cè)趪L試讀取數(shù)據(jù)的時(shí)候就可能造成程序崩潰。此外,在指針初始化的時(shí)候,不能使用0以外的整型給指針賦值。

除了例子中的指針類(lèi)型外,c++還有一種通用的void*指針。我們知道指針就是地址,指針的類(lèi)型不過(guò)表示了地址指向的位置所存儲(chǔ)的數(shù)據(jù)類(lèi)型。如果我們將int * 指針轉(zhuǎn)換為float * 指針,那么程序也只是將數(shù)據(jù)重新解讀為浮點(diǎn)類(lèi)型。所以這里void * 只是代表了一個(gè)地址,而我們不知道它所指向的數(shù)據(jù)類(lèi)型,但我們也可以重新定義它所指向的數(shù)據(jù)類(lèi)型。void * 一般會(huì)在一些內(nèi)存處理的系統(tǒng)函數(shù)時(shí)候使用。


4、指針的基本操作

對(duì)于指針來(lái)說(shuō),解引用和取地址是最重要的兩個(gè)操作符。
指針的基本操作

#includeusing namespace std;

//指針的基本操作

int main()
{int num = 4 ;
	int *intPtr = #
	cout<< "num的地址是:"<< &num<< endl;
	cout<< "指針的值是:"<< intPtr<< endl;
	if ( intPtr )
	{//檢查指針是否為空
		cout<< "指針?biāo)傅臄?shù)字是:"<< *intPtr<< endl;
	}
	return 0 ;
}

運(yùn)算結(jié)果:
在這里插入圖片描述
可以看到,符號(hào)“&”表示了取地址的操作,它可以獲得變量的內(nèi)存地址。將其賦值給我們的指針intPtr后,打印&num和intPtr將同時(shí)獲得num的地址。而當(dāng)我們使用解引用操作符“ * ”的時(shí)候,* intPtr將會(huì)得到intPtr所指向的地址中的數(shù)據(jù),也就是num的值。

在示例中,還加上了一個(gè)條件來(lái)檢查指針是否為NULL,以此保證對(duì)intPtr解引用一定是安全的。這里利用了數(shù)值與布爾值之間的隱性轉(zhuǎn)換,只寫(xiě)了intPtr作為條件,因?yàn)閕ntPtr為空的話(huà)值會(huì)轉(zhuǎn)化為false。條件intPtr也可以寫(xiě)成“intPtr != NULL”。
例子中用解引用操作符讀取了指針指向的數(shù)據(jù),而解引用操作符也可以用來(lái)作為賦值語(yǔ)句的左值以修改為數(shù)據(jù)。

左值解引用:

#includeusing namespace std;

//左值解引用

int main()
{int num = 4 ;
	int *intPtr = #
	if ( intPtr )
	{//檢查指針是否為空
		cout<< "指針?biāo)傅臄?shù)字是:"<< *intPtr<< endl;
		cout<< "num的值是: "<< num<< endl;
		*intPtr = 3;
		cout<< "修改后,指針?biāo)傅臄?shù)字是: "<< *intPtr<< endl;
		cout<< "num的值是:"<< num<< endl;
	}
	return 0 ;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
示例中,使用了左值解引用操作將指向num的指針中的數(shù)據(jù)修改為3,由于指針與num的地址相同,因此num也會(huì)變成3.指針的這一種行為可能會(huì)讓初學(xué)者感到困惑,接下來(lái)我們是用圖片來(lái)直觀地解釋指針解引用、取地址和左值解引用的行為。


5、指針的算數(shù)操作

指針可以像整形那樣進(jìn)行一部分算數(shù)操作,我還可以對(duì)地址進(jìn)行修改。因?yàn)橛?jì)算后的指針不一定會(huì)指向具有有效數(shù)據(jù)的地址,所以在進(jìn)行指針?biāo)銛?shù)操作的時(shí)候需要格外小心。

指針與整形的算數(shù)操作:

#includeusing namespace std;

//指針與整型的算數(shù)操作

int main()
{int arr[5] = {0, 1, 2, 3, 4 };
	int *ptr = arr;
	cout<< "arr + 4:"<< *(arr + 4 )<< endl;
	cout<< "ptr + 4:"<< *(ptr + 4 )<< endl;
	cout<< "ptr: "<< ptr + 2<< endl;
	cout<< "++ptr: "<< ++ptr<< endl;
	cout<< "ptr - 2: "<< ptr - 2<< endl;
	cout<< " --ptr:"<< --ptr<< endl;
	return 0;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
可以看到,指針與整型的算數(shù)操作不同于一般的數(shù)字加減,而是與指針類(lèi)型綁定的。由于一個(gè)int 的大小是4字節(jié),那么ptr+2 會(huì)將地址加上8,在組中就指向第三個(gè)元素。在示例中,除了指針ptr,我們也對(duì)數(shù)組arr做了加法,得到的結(jié)果都是第五元素的值。此外,示例末尾的ox7ffd4207fe80 已經(jīng)比數(shù)組的第一個(gè)元素地址還小了,如果對(duì)這個(gè)地址進(jìn)行解引用,可能會(huì)使程序崩潰。

提示數(shù)組名其實(shí)可以看做是指向數(shù)組第一個(gè)元素的指針。指針的各種操作都適用于數(shù)組名但只有一點(diǎn)區(qū)別,那就是數(shù)組名不能被重新賦值。這樣是很容易理解的,因?yàn)閿?shù)組是靜態(tài)的,數(shù)組名代表了當(dāng)前作用域唯一的一個(gè)數(shù)組,不可能先指針那樣指向其他地址。

指針除了與整型的算數(shù)操作以外,還可以進(jìn)行指針相減
指針相減

#includeusing namespace std;
int main()
{int arr[5] = {0, 1, 2, 3, 4 };
	int *ptr1 = arr + 1;
	int *ptr2 = arr + 3;
	cout<< "ptr1:"<< ptr1<< endl;
	cout<< "ptr2:"<< ptr2<< endl;
	cout<< "ptr2 - ptr1: "<< ptr2 - ptr1<< endl;
	cout<< "ptr1 - ptr2: "<< ptr1 - ptr2<< endl;
	return 0 ;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
指針相減返回的是指針地址之間的距離,并且是分正負(fù)的。這個(gè)距離也與類(lèi)型綁定,單位是該類(lèi)型數(shù)據(jù)的個(gè)數(shù)。指針之間不存在加法,每個(gè)指針代表的地址在計(jì)算機(jī)中都是唯一確定的,相加沒(méi)有任何意義。這就好像是門(mén)牌號(hào)32減掉30得到2,表示他們之間,隔著兩戶(hù),而32加上30卻不能表示什么。


6、const指針

之前有使用左值解引用來(lái)修改指針指向的原變量的例子,但如果變量是const,值是不能被修改的,因此我們也需要有一種特殊的指針來(lái)保證原變量不會(huì)被修改,這就是指向const對(duì)象的指針。

指向const對(duì)象的指針

#includeusing namespace std;

//指向const對(duì)象的指針

int main()
{const int num = 3;
	//普通指針不能指向const變量
	//int *ptr1 = &num;
	const int *ptr2 = #
	cout<< "*ptr2:"<< *ptr2<< endl;
	//指向const對(duì)象的指針不能修改解引用后的值
	//*ptr2 = 4;
	//指向const對(duì)象的指針可以修改指向的地址
	const int num1 = 4;
	ptr2 = &num1;
	cout<< "*ptr2: "<< *ptr2<< endl;
	//指向const對(duì)象的指針也可以指向普通變量
	int num2 = 5;
	ptr2 = &num2;
	cout<< "*ptr2 : "<< *ptr2<< endl;
	return 0 ;
}

運(yùn)行結(jié)果:

要定義一個(gè)指向const對(duì)象的指針,就要在const對(duì)象類(lèi)型名后加上星號(hào)?!癷nt* ptr1 = &num;”這一行如果去掉注釋?zhuān)幾g器就會(huì)報(bào)錯(cuò),因?yàn)槠胀ㄖ羔槻荒苤赶騝onst對(duì)象?!?* ptr2 =4;”這一行如果去掉注釋相當(dāng)于修改const對(duì)象的值,編譯器也會(huì)報(bào)錯(cuò)。

注意雖然ptr2指向的地址不能修改,但是它本身指向的地址可以修改。示例中,我們先后又讓它指向了另外兩個(gè)變量,其中也有一個(gè)非const的變量,指向非const變量的這一種指針也不能修改解引用后的值。
既然指向const對(duì)象的指針還可以修改地址的,那么應(yīng)該也有另外一種不能修改地址的指針,也就是const指針。

const指針

#includeusing namespace std;

//const指針

int main()
{int num1 = 3 ;
	int num2 = 4 ;
	int *const ptr1 = &num1;
	//const指針不能修改指向地址
	ptr1 = &num2 ;
	const int num3 = 5 ;
	const int num4 = 6 ;
	//指向const對(duì)象的const指針既不能修改地址,也不能修改值
	const int *const ptr2 = num3;
	ptr2 = num4;
	return 0 ;
}

示例展示了嘗試修改const指針而導(dǎo)致的編譯錯(cuò)誤。const指針的創(chuàng)建語(yǔ)法是將const移動(dòng)到了星號(hào)后面,一開(kāi)始ptr1指向num1,而當(dāng)我們嘗試把num2的地址賦值給ptr1的時(shí)候編譯器報(bào)錯(cuò)。一個(gè)指向const對(duì)象的const指針ptr2 ,這個(gè)指針只能指向const int變量,它指向的地址也不能改變。


7、指針的數(shù)組和數(shù)組的指針

標(biāo)題看似是兩個(gè)類(lèi)似的概念,二者卻截然不同。指針作為一種變量類(lèi)型,當(dāng)然可以被聲明為數(shù)組,而數(shù)組作為一種變量類(lèi)型,也可以有指向它的指針。指針的數(shù)組是一種數(shù)組,而數(shù)組的指針則是一種指針。

指針的數(shù)組和數(shù)組的指針

#includeusing namespace std;

//指針的數(shù)組和數(shù)組的指針

int main()
{int arr[5] = {0, 1, 2, 3, 4 };
	//數(shù)組的指針
	int (*arrPtr)[5] = &arr;
	//指針的數(shù)組
	int *ptrArr[5] = {&arr[0], &arr[1], &arr[2], &arr[3], &arr[4] };
	cout<< "arrPtr: "<< arrPtr<< endl;
	cout<< "*arrPtr:"<< *arrPtr<< endl;
	for (int i = 0; i< 5;i++)
	{cout<< ( *arrPtr ) [i]<< " ";
		cout<< ptrArr[i]<< " ";
		cout<< *(ptrArr[i] )<< " "<< endl;
	}
	return 0 ;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
可以看到,數(shù)組的指針和指針的數(shù)組的語(yǔ)法區(qū)別在于:數(shù)組的指針需要在星號(hào)和變量名外面加一個(gè)括號(hào),而指針的數(shù)組卻沒(méi)有。這一點(diǎn)其實(shí)很好理解,因?yàn)槁暶鲾?shù)組的時(shí)候元素類(lèi)型名int和數(shù)組大小[5] 就是被變量名隔開(kāi)的,在這里我們添加一個(gè)星號(hào),并用括號(hào)括起來(lái),表示這個(gè)指針int( * arrPtr)[5]是指向整個(gè)數(shù)組的;如果不加括號(hào),編譯器就只會(huì)將星號(hào)聯(lián)系到前面的類(lèi)型名int,所以ptrArr就只是聲明了一個(gè)數(shù)組,數(shù)組的元素類(lèi)型就是int*。

在聲明arrPtr的時(shí)候,我們把數(shù)組的地址賦值給他作為初值,由于數(shù)組的指針解引用以后就相當(dāng)于數(shù)組,我們可以用( * arrPtr)[i]來(lái)讀取數(shù)組的元素。
ptr Arr是一個(gè)指針的數(shù)組,它的每一個(gè)元素都是一個(gè)指針,這里就將數(shù)組的每個(gè)元素的地址分別賦值,而在遍歷的時(shí)候使用 * (ptrArr[i])來(lái)讀取數(shù)組中某一個(gè)指針指向的元素值。
由于這里比較不直觀的一點(diǎn)arrPtr和*arrPtr代表的地址完全一樣,為了解釋這一點(diǎn),再看一個(gè)示例

#includeusing namespace std;

//數(shù)組的指針的地址

int main()
{int arr1[5] = {0, 1, 2, 3, 4 };
	//數(shù)組的指針
	int (*arrPtr)[5] = &arr1;
	cout<<"arrPtr: "<< arrPtr<< endl;
	cout<<"*arrPtr:"<< *arrPtr<< endl;
	int arr2[5] = {0, 1, 2, 3, 6 };
	//數(shù)組的指針必須指向大小相同的數(shù)組
	arrPtr = &arr2;
	cout<< "arrPtr: "<< arrPtr<< endl;
	cout<< "*arrPtr:"<< *arrPtr<< endl;
	//數(shù)組的指針指向數(shù)組,而數(shù)組是不可修改的
	//*arrPtr = arr1
	return 0 ;
}

運(yùn)算結(jié)果:
在這里插入圖片描述
我們可以看到,數(shù)組的指針必須指向相同大小的數(shù)組,如果arr2只有4個(gè)元素,“ arrPtr = &arr2; ”的賦值機(jī)會(huì)產(chǎn)生編譯錯(cuò)誤,并且由于數(shù)組的指針指向是不可修改的數(shù)組,我們不能把arrPtr作為左值修改。

至于為什么arrPtr和 * arrPtr的地址一樣,可以看做是編譯器不得已的安排。數(shù)組名arr1代表著數(shù)組首元素的地址,而一般的變化量比如int1就放著一個(gè)數(shù)值,而&int1才放著int1 的地址。由于數(shù)組的這一特殊性,導(dǎo)致了&arr得到的數(shù)組地址與arr代表的數(shù)組地址是一樣的,因此相應(yīng)的arrPtr和 * arrPtr的地址也只能是一樣的,* arrPtr也要搭配下標(biāo)操作符才能取得數(shù)組的對(duì)應(yīng)元素。


8、指針的指針

指針可以指向任何變量或者對(duì)象,所以也可以指向指針。

#includeusing namespace std;

//指針的指針

int main()
{int num = 3 ;
	int *numPtr = #
	int **numPtrPtr = &numPtr;
	cout<< "num: "<< num<< endl;
	cout<< "*numPtr: "<< *numPtr<< endl;
	cout<< "numPtr: "<< numPtr<< endl;
	cout<< "*numPtrPtr: "<< *numPtrPtr<< endl;
	cout<< "numPtrPtr: "<< numPtrPtr<< endl;
	return 0;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
可以看出,指針的指針聲明就多加了一個(gè)星號(hào),以表示指針指向的指針類(lèi)型,因此將numPtr的地址賦值給它。
指針的指針一般用于函數(shù)傳參數(shù)時(shí)修改傳入的指針。


9、const_cast 與reinterpret_cast

const_cast的作用是將一個(gè)變量轉(zhuǎn)換成const限定的常量。

const_cast

#includeusing namespace std;

//const_cast

int main()
{int intNum = 2 ;
	intNum = 3;
	//const_cast后面必須跟引用或指針類(lèi)型
	const int &consIntNum = const_cast(intNum);
	//轉(zhuǎn)換以后數(shù)字不能在修改
	//constIntNum = 2;
	return 0 ;
}

示例中,可以看到intNum在轉(zhuǎn)換前是可以修改的變量,在轉(zhuǎn)換以后就變成常量,不能再進(jìn)行修改了。

reinterpret_cast 比較特殊。reinterpret 的意思是重新解讀,而reinterpret_cast 就是將一段數(shù)據(jù)按照二進(jìn)制表示重新解讀成另一種數(shù)據(jù),所以他并沒(méi)有對(duì)數(shù)據(jù)做任何改變,只是改變了類(lèi)型。

reinterpret_cast

#includeusing namespace std;

//reinterpret_cast

int main()
{int intNum = 0x00646362;
	int *intPtr = &intNum;
	char *str = reinterpret_cast(intPtr);
	cout<< "str的值為:"<< str<< endl;
	return 0;
}

運(yùn)行結(jié)果:
在這里插入圖片描述
在示例中,可以看到熱interpret_cast將一個(gè)指向整數(shù)的指針轉(zhuǎn)換成了指向字符的指針,也就是c風(fēng)格的字符串,十六進(jìn)制的62、63、64在ASCLL碼中分別代表b、c、d,所以打印了“bcd”。
reinterpret_cast 的作用就是將一個(gè)類(lèi)型的指針轉(zhuǎn)換成另一個(gè)類(lèi)型的指針,而指針指向的內(nèi)存將被原封不動(dòng)地重新解讀。當(dāng)然這也是一種比較危險(xiǎn)的舉動(dòng)。

如果本文對(duì)您有幫助,請(qǐng)點(diǎn)贊支持一下~

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧


本文名稱(chēng):c++指針詳解-創(chuàng)新互聯(lián)
文章源于:http://weahome.cn/article/ecegi.html

其他資訊

在線(xiàn)咨詢(xún)

微信咨詢(xún)

電話(huà)咨詢(xún)

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部