C語(yǔ)言進(jìn)階:指針的進(jìn)階(2)
數(shù)組指針
由前面的例子,不難得出,數(shù)組指針是指向數(shù)組的指針,是指針而非數(shù)組。
數(shù)組指針的定義
char ch = 'w'; char* pch = &ch;//字符地址存放在字符指針中 int a = 10; int* pint = &a;//整型地址存放在整型指針中 float f = 0.0; float* pf = &f;//浮點(diǎn)型地址存放在浮點(diǎn)型指針中
什么變量的地址存放在什么指針中。指針指向變量的類型,決定了指針的類型。顧名思義,數(shù)組指針指向的是數(shù)組。
遞推可得,數(shù)組的地址存放在數(shù)組指針中。且數(shù)組指針的類型為數(shù)組的類型再加個(gè)* 。
下面那種定義方法是對(duì)的呢?
int arr[10] = { 0 };
//1.
int* pa = arr;
//2.
&arr;//整個(gè)數(shù)組的地址
int* parr = &arr;
//3.
int* parr[10] = &arr;
//4.
int(*parr)[10] = &arr;
取出的是首元素的地址,而非整個(gè)數(shù)組的地址
整型指針應(yīng)存放整型變量的地址,數(shù)組的地址無法存入整型指針中。
[]的優(yōu)先級(jí)比*高,故parr先與[]結(jié)合成數(shù)組名,所以parr是個(gè)指針數(shù)組。
數(shù)組指針的類型由數(shù)組類型決定,先找出數(shù)組的類型int[10](去掉名就是類型)。且不能讓[]先與parr結(jié)合,所以用()先將parr和*結(jié)合,即成int(*parr)[10]。
C語(yǔ)言規(guī)定[]必須再最后面,所以不可寫成
int[10](*parr)。
int* parr[10];//指針數(shù)組 int(*parr)[10];//數(shù)組指針
我們前面強(qiáng)調(diào)過,去掉名字就是類型。所以int[10]是整型數(shù)組的類型,int*[10]是指針數(shù)組的類型,int(*)[10]是數(shù)組指針的類型。
&數(shù)組名和數(shù)組名
之前介紹過不止一遍,所以這次只說重點(diǎn)。
指針類型決定了指針±整數(shù)的步長(zhǎng)。
//首元素地址+1
printf("%p\n", arr);//0073FCA4
printf("%p\n", arr + 1);//0073FCA8
//整個(gè)數(shù)組地址+1
printf("%p\n", &arr);//0073FCA4
printf("%p\n", &arr + 1);//0073FCCC
1.首元素地址就是整型指針+1,自然只能向后訪問4shou個(gè)字節(jié)
2.整個(gè)數(shù)組地址+1,即int(*)[10]型指針+1,向后訪問了 i n t × 10 int×10 int×10即40個(gè)字節(jié)。
sizeof(arr)也代表整個(gè)數(shù)組,現(xiàn)在去理解為什么sizeof里數(shù)組名代表的是整個(gè)數(shù)組呢?數(shù)組這種結(jié)構(gòu)保存了數(shù)組的大小,sizeof求所占空間的長(zhǎng)度,那自然要嚴(yán)謹(jǐn)一些了。
數(shù)組指針的使用
遍歷數(shù)組,使用數(shù)組或是指針作形參接收就行了。且所謂的用數(shù)組接收僅是理解層面,本質(zhì)上都是指針。
void Print1(int arr[], int sz) {
for (int i = 0; i < sz; i++) {
//printf("%d ", arr[i]);
printf("%d ", *(arr + i));
}
}
void Print2(int* arr, int sz) {
for (int i = 0; i < sz; i++) {
printf("%d ", arr[i]);
//printf("%d ", *(arr + i));
}
}
int main() {
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
int sz = sizeof(arr) / sizeof(arr[0]);
Print1(arr, sz);
Print2(arr, sz);
return 0;
}
反面用例
數(shù)組作實(shí)參,用數(shù)組或指針接收即可。數(shù)組指針使用對(duì)了很好用,但如果隨便用可能會(huì)很別扭。下面先介紹強(qiáng)行使用數(shù)組指針的用法。
//錯(cuò)誤示范
void Print3(int(*pa)[10], int sz) {
for (int i = 0; i < sz; i++) {
//printf("%d ", pa[i]);
printf("%d ", *(pa + i));
}
}
將整個(gè)數(shù)組地址傳過去,則用數(shù)組指針接收,然后呢,直接對(duì)pa解引用嗎?

結(jié)果顯然是錯(cuò)誤的,從結(jié)果中也可以看出打印的是十進(jìn)制下的地址,+1跳過40個(gè)字節(jié)。
這里筆者在學(xué)習(xí)的時(shí)候產(chǎn)生了個(gè)疑問,傳過去數(shù)組的地址,為什么解一層引用后還是地址呢?
&arr解引用*后相當(dāng)于找到首元素的地址,可以理解為&和*相互抵消只剩下arr不就是首元素的地址嘛~
void Print4(int(*pa)[10], int sz) {
for (int i = 0; i < sz; i++) {
printf("%d ", *(*(pa)+j));
}
}
倘若我們把一維數(shù)組看作是二維數(shù)組第一行。由于二維數(shù)組在內(nèi)存中是連續(xù)存放的,我們只打印二維數(shù)組的第一行,便可以避免上面的錯(cuò)誤。

style=“zoom:80%;” />
*(pa)相當(dāng)于數(shù)組指針?biāo)赶驍?shù)組的數(shù)組名。數(shù)組指針指向整個(gè)數(shù)組,將其看作二維數(shù)組并解引用得到一行的首元素,從而遍歷訪問。
正面用例
從上面的例子也可以看出,用數(shù)組指針訪問二維數(shù)組時(shí),效果便不錯(cuò)。
//二維數(shù)組傳參,用二維數(shù)組接收
void Print1(int arr[3][5], int r, int c) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
//printf("%d ", arr[i][j]);
printf("%d ", *(*(arr + i) + j));
}
printf("\n");
}
}
上面的例子,是正常二維數(shù)組傳參,二維數(shù)組接收的情況。下面我們用數(shù)組指針接收。
//二維數(shù)組傳參,用數(shù)組指針接收
void Print2(int(*pa)[5], int r, int c) {
for (int i = 0; i < r; i++) {
for (int j = 0; j < c; j++) {
//1.
printf("%d ", pa[i][j]);
//2.
printf("%d ", *(*(pa + i) + j));
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7 };
Print2(arr, 3, 5);//二維數(shù)組首元素是首行
return 0;
}
- 把二維數(shù)組想象成一個(gè)擁有三個(gè)元素的一維數(shù)組(每個(gè)元素也為一維數(shù)組),即一維數(shù)組的一維數(shù)組。
- 由于其每個(gè)元素是有5個(gè)元素的一維數(shù)組,數(shù)組指針定義為int(*p)[5],指向首行這個(gè)“一維數(shù)組”。(傳參穿的是數(shù)組名)
- 第一層循環(huán)用于“跳行”,即每次跳過5個(gè)元素。第二層循環(huán)遍歷每行“一維數(shù)組”。

用二維數(shù)組和數(shù)組指針接收的都是首行地址。
數(shù)組指針的類型int(*)[5],和二維數(shù)組首元素地址的類型相同。
故可得,二維數(shù)組首元素地址和數(shù)組指針是等價(jià)的,即數(shù)組指針pa就是數(shù)組名。
二維數(shù)組首元素為其首行,相當(dāng)于一個(gè)一維數(shù)組,該一維數(shù)組的地址類型為int(*)[5]。且實(shí)參為二維數(shù)組名,降級(jí)為指向首行的指針,所以它是數(shù)組指針,類型為int(*)[5]。
數(shù)組指針指向二維數(shù)組,才是使用數(shù)組指針的正確示范。
Example
下列示例分別是什么?
//1. int arr[5]; //2. int *pa1[5]; //3. int (*pa2)[10]; //4. int (*pa3[10])[5];
1.整型數(shù)組
2.存放整型指針的數(shù)組
*靠左靠右無所謂,pa1先和[]結(jié)合為數(shù)組,剩下int*為數(shù)組元素類型。
3.指向整型數(shù)組的指針
(*pa2),*先和pa2結(jié)合為指針,剩下int[10],指向的是元素個(gè)數(shù)為10的整型數(shù)組。
4.存放數(shù)組指針的數(shù)組
pa3先和[10]結(jié)合為數(shù)組,剩下int(*)[5]是指向數(shù)組的指針為數(shù)組的元素。所以是個(gè)元素個(gè)數(shù)為10的數(shù)組指針數(shù)組。
逆向思考,有整型數(shù)組arr[5]和指向該數(shù)組的類型為int(*)[5]的數(shù)組指針,還有數(shù)組指針數(shù)組pa3[10]用于存放該數(shù)組指針。

類型辨別方法
1.若名稱先和[]結(jié)合為數(shù)組,只去掉數(shù)組名就是數(shù)組類型,去掉[n]和數(shù)組名便是其元素的類型。
2.若名稱先和*結(jié)合為指針,只去掉指針名就是指針類型,去掉*和指針名便是指向的變量的類型。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
C語(yǔ)言使用深度優(yōu)先搜索算法解決迷宮問題(堆棧)
這篇文章主要介紹了C語(yǔ)言使用深度優(yōu)先搜索算法解決迷宮問題,涉及C語(yǔ)言堆棧的使用與深度優(yōu)先算法解決迷宮問題的相關(guān)操作技巧,需要的朋友可以參考下2017-09-09
C++集體數(shù)據(jù)交換實(shí)現(xiàn)示例講解
這篇文章主要介紹了C++集體數(shù)據(jù)交換實(shí)現(xiàn)示例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧2022-11-11
C++實(shí)現(xiàn)LeetCode(10.正則表達(dá)式匹配)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(10.正則表達(dá)式匹配),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07
opencv+arduino實(shí)現(xiàn)物體點(diǎn)追蹤效果
這篇文章主要為大家詳細(xì)介紹了opencv+arduino實(shí)現(xiàn)物體點(diǎn)追蹤效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01
C++ Qt開發(fā)之使用QTcpSocket實(shí)現(xiàn)TCP網(wǎng)絡(luò)通信
Qt 是一個(gè)跨平臺(tái)C++圖形界面開發(fā)庫(kù),利用Qt可以快速開發(fā)跨平臺(tái)窗體應(yīng)用程序,本文主要為大家介紹了如何運(yùn)用QTcpSocket組件實(shí)現(xiàn)基于TCP的網(wǎng)絡(luò)通信功能,需要的可以參考下2024-03-03
C語(yǔ)言實(shí)現(xiàn)通訊錄系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)通訊錄系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-02-02
C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)自動(dòng)存取款機(jī)模擬系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05

