摘要:需要注意的是用矩陣形式如行列表示二維數(shù)組,是邏輯上的概念,能形象地表示出行列關(guān)系。再次強(qiáng)調(diào)二維數(shù)組名如是指向行的。一維數(shù)組名如是指向列元素的。
哈嘍!這里是一只派大鑫,不是派大星。本著基礎(chǔ)不牢,地動(dòng)山搖的學(xué)習(xí)態(tài)度,從基礎(chǔ)的C語言語法講到算法再到更高級(jí)的語法及框架的學(xué)習(xí)。更好地讓同樣熱愛編程(或是應(yīng)付期末考試 狗頭.jpg)的大家能夠在學(xué)習(xí)階段找到好的方法、路線,讓天下沒有難學(xué)的程序(只有禿頭的程序員 2333),學(xué)會(huì)程序和算法,走遍天下都不怕!
目錄
?三、?通過指向數(shù)組元素的指針變量來引用多維數(shù)組?
?4.1 指向 由m個(gè)元素組成的一維數(shù)組 的指針變量
本文通過從二維數(shù)組的介紹開始,講解什么是二維數(shù)組——>怎么定義和使用二維數(shù)組——>怎么引用二維數(shù)組的元素——>怎么通過指針來引用二維數(shù)組(具體包括多種分式)來逐步說明指針+二維數(shù)組的配合使用,相信學(xué)完本文內(nèi)容,讀者對(duì)于指針和二維數(shù)組會(huì)有更加深刻的印象和理解。通過學(xué)校期末考試和考研C語言內(nèi)容完全足夠?。?!?
怎么定義二維數(shù)組呢?其基本概念與方法和一維數(shù)組相似。
如: float pay[3][6];
這樣就是定義了一個(gè)二維數(shù)組,其第一維有3個(gè)元素,第二維有6個(gè)元素。
每一維的長(zhǎng)度分別用一隊(duì)方括號(hào)括起來。
由此引出 二維數(shù)組定義的一般形式為:
類型說明符 數(shù)組名[常量表達(dá)式][常量表達(dá)式]
例如:
float a[3][4],b[5][10];
定義a為3×4(3行4列)的數(shù)組,b為5×10(5行10列的數(shù)組)。
注意,不能寫成 ??float a[3,4],b[5,10]; ?//在一對(duì)方括號(hào)內(nèi)寫兩個(gè)下標(biāo),錯(cuò)誤
C語言中,對(duì)于二維數(shù)組采用以上的定義方式,使得二維數(shù)組可被看做一種特殊的一維數(shù)組: 它的元素又是一個(gè)一維數(shù)組。 例如,可以把a(bǔ)看做一個(gè)一維數(shù)組,它有三個(gè)元素:
如圖:? ? ?
?并且它的每一個(gè)元素又是包含了4個(gè)元素的一維數(shù)組:
?因此可以把a(bǔ)[0],a[1],a[2]看做3個(gè)一維數(shù)組的名字,且是3個(gè)行元素,即a[0],a[1],a[2]是一維數(shù)組名,這一點(diǎn)對(duì)于后面二維數(shù)組元素的引用很重要!
?C語言中,二維數(shù)組中的元素排列的順序是按行存放的,即在內(nèi)存中先順序存放第0行的元素,接著再存放第1行的元素。
?假設(shè)數(shù)組a存放在從2000字節(jié)開始的一段內(nèi)存單元中,一個(gè)元素占4個(gè)字節(jié),前16個(gè)字節(jié)(2000~2015)存放序號(hào)為0的行中4個(gè)元素,接著的16個(gè)字節(jié)(2016~2031)存放序號(hào)為1的行中4個(gè)元素,以此類推。
需要注意的是: 用矩陣形式(如3行4列)表示二維數(shù)組,是邏輯上的概念,能形象地表示出行列關(guān)系。而在內(nèi)存中,各元素是連續(xù)存放的,不是二維的,是線性的。
最通常的方法:
數(shù)組名[下標(biāo)][下標(biāo)]
例如 a[1][2];
需要注意引用時(shí)不能超過下標(biāo)范圍
方法①? ? 分行給二維數(shù)組賦初值。 如:
int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
方法②? ? 寫在一個(gè)花括號(hào)內(nèi),按排列順序賦值。 如:
int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
方法③? ? 可以對(duì)部分元素賦初值。 如:
1) int a[3][4] = {{1},{5},{9}};
賦值的結(jié)果為:
?2)int a[3][4] = {{1},{0,6},{0,0,11}};
初始化后的數(shù)組元素如下:
?3)int a[3][4] = {{1},{5,6}};
數(shù)組元素為:
?4)int a[3][4] = {{1},{ },{9}};
注:在定義并賦值時(shí),可以省略第一維的大?。▽?shí)際上不管幾維數(shù)組都只能省略第一維大小),但第二維的大小不能省。
?為了讓讀者更加清楚多維數(shù)組的地址問題,我們先回顧一下一維數(shù)組的地址問題。
在一維數(shù)組中,數(shù)組名代表的是數(shù)組首元素的地址
?例如: int a[4] = {1,2,3,4};
a的值就是第一個(gè)元素即a[0]的地址,a+1,往右移一個(gè)位置,所以是a[1]的地址,例如如下程序:
#includeint main(){ int a[4] = {1,2,3,4}; printf("%d/n",a); printf("%d/n",a+1); return 0;}
?運(yùn)行結(jié)果為:
?可以看出輸出的是地址,且地址是連續(xù)存放的。
那么一維數(shù)組中的元素值呢?
我們所熟悉且最常見的就是用[ ]表示法來獲取數(shù)組元素值,
所以 a[i] 就是 第 i 個(gè)元素的值,既然 a+i 是第 i 個(gè)元素的地址,那么我們知道地址引用其值的方法就是在前面加一個(gè)“ * ”符號(hào), 所以*(a+i) = a[i] = 第 i 個(gè)元素的值。
需要明確, a[i] 和 *(a+i) 是無條件等價(jià)的(非常重要)?。?!
好了,這里我們主要為了明確:一維數(shù)組名 代表的是 一維數(shù)組首元素的地址。
解決了這個(gè)問題,我們就可以開始思考二維數(shù)組的地址問題了。
? 首先 我們定義一個(gè)二維數(shù)組為: int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}};
a 是二維數(shù)組名。
a 數(shù)組包含3行,即3個(gè)行元素:a[0]、a[1]、a[2]。
而每一個(gè)行元素又是一個(gè)一維數(shù)組,它包含4個(gè)元素(即4個(gè)列元素)。
(這里有點(diǎn)疑惑的讀者,可以上翻二維數(shù)組的初步理解再次細(xì)看一下~~~)
一定要非常敏感 行 和 列 的區(qū)分。
例如:a[0]所代表的一維數(shù)組又包含4個(gè)元素:a[0][0],a[0][1],a[0][2],a[0][3],見下圖
?可以認(rèn)為: 二維數(shù)組a是由3個(gè)一維數(shù)組所組成的,或者看做3個(gè)行組成。
從二維數(shù)組的角度來看,a代表二維數(shù)組首元素的地址,現(xiàn)在的首元素不是一個(gè)簡(jiǎn)單的整型元素哦,而是由4個(gè)整型元素所組成的一維數(shù)組。
因此,a代表的是首行(即序號(hào)為0的行)的起始地址。
而a+1則是序號(hào)為1的行的起始地址。 (a是指向一行的,a+1當(dāng)然在行方向移動(dòng)~~~)
如果二維數(shù)組的首行起始地址為2000的話,按照一個(gè)int類型數(shù)據(jù)占4個(gè)字節(jié)來算,則a+1的值應(yīng)該是2000+4×4 = 2016 (因?yàn)橐恍杏?個(gè)數(shù)組嘛~~~)
又因?yàn)閍+1指向a[1],也能說a+1的值是a[1](代表序號(hào)為1的行)的起始地址
既然a[0],a[1],a[2]是一維數(shù)組名,從復(fù)習(xí)一維數(shù)組部分可以知道,代表的是數(shù)組首元素的地址,
因此,a[0]代表一維數(shù)組a[0]中第0列的地址,即&a[0][0]。 (這里一定要反復(fù)琢磨是指向列的)
?同理,a[1]的值是第1列的地址,即&a[1][0]。
請(qǐng)思考,a數(shù)組0行1列元素的地址怎么表述(除了&a[0][1],這個(gè)太簡(jiǎn)單了)?
?a[0]是一維數(shù)組名,也是第0行的首元素(或是第0列)的地址,所以同一維數(shù)組一樣,
第1列就是第0列+1得到,所以a[0]+1就是a[0][1]的地址。
?此時(shí)“a[0]+1”中的1,代表的是1個(gè)列元素的字節(jié)數(shù),即4個(gè)字節(jié),a[0]的值是2000,a[0]+1的值是2004而不是2016。
同理,既然a[0]是a[0][0]的地址,a[1]是a[1][0]的地址,并且a[0]+1是a[0][1]的地址,
所以,a[i]+j 就是 a[i][j]的地址。 注意:是地址,而不是元素的值
看圖理解一下:
? ? ? ? ? ? ? ? ? ?
?前面一維復(fù)習(xí)部分已經(jīng)講述了,*(a+i)和a[i]是等價(jià)的,
因此,a[0]+1 和 *(a+0)+1 和 *(a)+1 都是 &a[0][1]。
所以 a[i]+j 和 *(a+i)+j 都是 &a[i][j],是一個(gè)地址而不是值。
注意不要寫成了 *(a+1+2),這樣就是 *(a+3) 即 a[3] 了。
?進(jìn)一步分析,若想得到某行某列元素的值呢?
?如果把地址弄明白,那么這就變得簡(jiǎn)單了。
& 取地址運(yùn)算符, * 指針運(yùn)算符(或稱“間接訪問運(yùn)算符”),如 *p代表p指向的對(duì)象。
得到地址取值的方法就是加一個(gè)“ * ”。
因此, *(a[i]+j) 或者 *(*(a+i)+j)是a[i][j]的值,或說 *(a[i]+j) =? *(*(a+i)+j) = a[i][j] 。
總結(jié)一下:二維數(shù)組 a 的有關(guān)指針?
?舉個(gè)栗子
在軍訓(xùn)中,一個(gè)排分3個(gè)班,每個(gè)班站成一行,3個(gè)班為3行,相當(dāng)于一個(gè)二維數(shù)組。
為方便比較,班和戰(zhàn)士的序號(hào)也從0開始。
請(qǐng)思考:班長(zhǎng)點(diǎn)名和排長(zhǎng)點(diǎn)名的方法有什么不同。
班長(zhǎng)從第0個(gè)戰(zhàn)士開始逐個(gè)檢查本班戰(zhàn)士是否在隊(duì)列中,班長(zhǎng)每移動(dòng)一步,走過一個(gè)戰(zhàn)士。
而排長(zhǎng)點(diǎn)名則是以班為單位,排長(zhǎng)先站在第0班的起始位置,檢查該班是否到齊,然后走到第1班的起始位置,檢查該班是否到齊。
班長(zhǎng)移動(dòng)的方向是橫向的,而排長(zhǎng)移動(dòng)的方向是縱向的。排長(zhǎng)看起來只走了一步,但實(shí)際上他跳過了一個(gè)班的10個(gè)戰(zhàn)士。這相當(dāng)于從a移到a+1(見下圖)
班長(zhǎng)“指向”的是戰(zhàn)士,排長(zhǎng)“指向”的是班,班長(zhǎng)相當(dāng)于列指針,排長(zhǎng)相當(dāng)于行指針。
一定要好好理解,并能分清楚 指向行 和 指向列?。?!
?
?為了找到某一班內(nèi)某一個(gè)戰(zhàn)士,必須給兩個(gè)參數(shù),即第i班第j個(gè)戰(zhàn)士,先找到第i班,然后由該班班長(zhǎng)在本班范圍內(nèi)找第j個(gè)戰(zhàn)士。這個(gè)戰(zhàn)士的位置就是a[i]+j(這是一個(gè)地址)。
開始時(shí)班長(zhǎng)面對(duì)第0個(gè)戰(zhàn)士。注意,排長(zhǎng)和班長(zhǎng)的初始位置是相同的(如圖的a和a[0]都是2000),但他們面對(duì)的對(duì)象是不同的,班長(zhǎng)面向的對(duì)象是戰(zhàn)士,排長(zhǎng)面向的對(duì)象是班。排長(zhǎng)“指向”班,在圖上是“縱向管理”,他縱向走一步就跳過一個(gè)班,而班長(zhǎng)“指向”戰(zhàn)士,在圖上是“橫向管理”,橫向走一步只是指向下一個(gè)戰(zhàn)士。
所以 a+1 是在行方向上移動(dòng),a[i]+1(或者 *(a+i)+1)是在列的方向上移動(dòng)?。?!
二維數(shù)組a相當(dāng)于排長(zhǎng),而每一行(即一維數(shù)組a[o],a[1],a[2])相當(dāng)于班長(zhǎng),每一行中的元素(如 a[1][2])相當(dāng)于戰(zhàn)士。
再次強(qiáng)調(diào): 二維數(shù)組名( 如a )是指向行的。因此a + 1中的 “1’’ 代表一行中全部元素所占的字節(jié)數(shù) 。 一維數(shù)組名 (如a[0],a[1])是指向列元素的。a[0] + 1 中的1代表一個(gè) a 元素所占的字節(jié)數(shù)。
在指向行的指針前面加一個(gè) *,就轉(zhuǎn)換為指向列的指針。 例如,a 和 a+1 是指向行的指針,在它們前面加一個(gè) * 就是 *a 和 *(a+1),它們就成為指向列的指針,分別指向a數(shù)組0行0列的元素和1行0列的元素。
反之,在指向列的指針前面加&,就成為指向行的指針。例如 a[0] 是指向0行0列元素的指針,在它前面加一個(gè)&,得&a[0],由于a[0] 與 *(a+0)等價(jià),因此 &a[0]與&*a等價(jià),也就是與a等價(jià),它指向二維數(shù)組的 0 行。
?不要把&a[i]簡(jiǎn)單的理解為a[i]元素的存儲(chǔ)單元的地址,因?yàn)槎S中并不存在a[i]這樣一個(gè)實(shí)際的數(shù)據(jù)存儲(chǔ)單元。 它只是一種地址的計(jì)算方法,能得到第 i 行的起始地址。
到這里為止,我們通過二維數(shù)組名的不同方式來獲取元素地址、值的內(nèi)容就這些了,請(qǐng)讀者要反復(fù)思考,加深理解。(ps 比較期末、考研的C語言的試題,這可是重點(diǎn)+難點(diǎn))
?
?啊這,你以為已經(jīng)結(jié)束了嗎??Impossible?。。?還沒有和指針更深入的結(jié)合呢~~~
?一看標(biāo)題那么長(zhǎng)有木有,但實(shí)際就是普通的指針!
?指向數(shù)組元素的指針變量,不就是指針變量嘛
例如: 定義一個(gè) int a = 10;? ? ? int *p = &a;
所以 p=&a, *p = a = 10;
此時(shí)用來指向數(shù)組的 具體元素 也是一樣的,不管是一維還是二維。
例如這樣一個(gè)簡(jiǎn)單的程序:
#includeint main(){ int a[4] = {1,2,3,4}; int *p = a; for(int i=0;i<4;i++) printf("%d ",*(p+i)); return 0;}
結(jié)果為:
用在二維中效果也是一樣的:
#includeint main(){ int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}; int *p = a[0]; for(int i=0;i<4;i++) printf("%d ",*(p+i)); return 0;}
?結(jié)果為:
?但要注意,p是列指針,a在二維代表行,所以需要把p賦值為a[i]才是指向列的!
?同時(shí),因?yàn)樵趦?nèi)存中地址是連續(xù)的!所以也可以輸出全部的元素,而不只是一行
for(int i=0;i<12;i++) printf("%d ",*(p+i));
?
?指向數(shù)組的指針變量,就是 數(shù)組指針
定義方式例如:? ? int (*p)[4];
解釋:①別忘了 (),因?yàn)閇 ]的優(yōu)先級(jí)比 * 高。
? ? ? ? ? ?②4代表的 指向的數(shù)組 有4個(gè)元素,如果是二維數(shù)組,那么就是第二維(即列)的個(gè)數(shù)。
?第三個(gè)標(biāo)題說的方法是指向具體元素(列)的,我們也可以改用另一種方法,使p不是指向整型變量,而是指向一個(gè)包含m個(gè)元素的一維數(shù)組。
這是,如果p指向a[0](即 p = &a[0] 當(dāng)然也就是 p = a),則p+1 不是指向a[0][1]了,就是指向a[1],
p的增量是以一行字節(jié)為單位的。 這里其實(shí)也相當(dāng)于 第二部分說的 用數(shù)組名來引用二維數(shù)組一樣,畢竟 p = a 嘛。
看一個(gè)簡(jiǎn)單的引用例子:
#includeint main(){ int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}; int (*p)[4] = a; printf("數(shù)組指針引用方式1:%d/n",p[1][1]); printf("數(shù)組指針引用方式2:%d/n",*(*(p+1)+1)); return 0;}
結(jié)果為:
由此看出這樣的確和用 a 來引用方式是一樣的。
?不僅數(shù)組指針可以引用二維數(shù)組,指針數(shù)組也可以哦
?一個(gè)數(shù)組,若其元素均為指針類型數(shù)據(jù),則成為 指針數(shù)組
也就是說,指針數(shù)組中的每一個(gè)元素都是存放一個(gè)地址。
定義樣例:? int *p[3];? ? ? //這里的3 我的理解是 如果指向二維數(shù)組,則3是代表行數(shù)。
注意:這里就不用()了,[ ]優(yōu)先級(jí)比 * 高。因此p先與[3]結(jié)合為p[3] ,表示是一個(gè)數(shù)組。
?既然指針數(shù)組是一個(gè)數(shù)組,所以肯定得用p[0] =? ? p[1]=? ?p[2]=? ? 這樣的形式來賦值~~~
而又因?yàn)?,?shù)組里面應(yīng)該放的是一行的地址起始,而且在二維中,a[0],a[1],a[2]不就是行地址嘛
所以就有如下例子:?
#includeint main(){ int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}; int *p[3]; p[0] = a[0], p[1] = a[1], p[2] = a[2]; return 0;}
那么元素的值呢? 很簡(jiǎn)單,我們拿到了地址,所以加一個(gè)“ * ”即可得到
printf("%d/n",p[0]); //錯(cuò)誤寫法printf("%d/n",*(p[0])); //正確寫法
結(jié)果為:?
?注意正確寫法,因?yàn)槲覀兊?span style="background-color:#a2e043;">p[0]才是地址,不要以為p[0] = *(p+0) 就是值了。
總結(jié)一下前面的方法,比較一下對(duì)于各種定義,應(yīng)該怎么賦值以及引用。
#include#includeusing namespace std;int main(){ int a[3][4] = {{1,3,5,7},{9,11,13,15},{17,19,21,23}}; int (*p)[4]; p = a; int *p2[3]; p2[0] = a[0], p2[1] = a[1], p2[2] = a[2]; int *p3 = a[1]; printf("1.數(shù)組名本身的引用:%d/n",a[1][1]); printf("2.數(shù)組指針引用方式1:%d/n",p[1][1]); printf("3.數(shù)組指針引用方式2:%d/n",*(*(p+1)+1)); printf("4.指針數(shù)組引用:%d/n",*(p2[1]+1)); printf("5.指針引用1:%d/n",*p3); printf("6.指針引用2:%d/n",*(p3+1)); return 0; }
?
自此,關(guān)于指針+二維數(shù)組的 地址和值 的引用講解就結(jié)束了,指針本就是難點(diǎn),再加上二維、地址就更懵了,希望讀者能夠好好理解文章的內(nèi)容。 如果在閱讀時(shí),發(fā)現(xiàn)有什么沒有提及或是有錯(cuò)誤的地方,歡迎廣大讀者留言反映。
最后,寫文不易,如有轉(zhuǎn)載 請(qǐng)標(biāo)明出處!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/119106.html
摘要:此專欄文章是對(duì)力扣上算法題目各種方法的總結(jié)和歸納整理出最重要的思路和知識(shí)重點(diǎn)并以思維導(dǎo)圖形式呈現(xiàn)當(dāng)然也會(huì)加上我對(duì)導(dǎo)圖的詳解目的是為了更方便快捷的記憶和回憶算法重點(diǎn)不用每次都重復(fù)看題解畢竟算法不是做了一遍就能完全記住的所 ...
此專欄文章是對(duì)力扣上算法題目各種方法的總結(jié)和歸納, 整理出最重要的思路和知識(shí)重點(diǎn)并以思維導(dǎo)圖形式呈現(xiàn), 當(dāng)然也會(huì)加上我對(duì)導(dǎo)圖的詳解. 目的是為了更方便快捷的記憶和回憶算法重點(diǎn)(不用每次都重復(fù)看題解), 畢竟算法不是做了一遍就能完全記住的. 所以本文適合已經(jīng)知道解題思路和方法, 想進(jìn)一步加強(qiáng)理解和記憶的朋友, 并不適合第一次接觸此題的朋友(可以根據(jù)題號(hào)先去力扣看看官方題解, 然后再看本文內(nèi)容). 關(guān)...
摘要:哪吒社區(qū)技能樹打卡打卡貼函數(shù)式接口簡(jiǎn)介領(lǐng)域優(yōu)質(zhì)創(chuàng)作者哪吒公眾號(hào)作者架構(gòu)師奮斗者掃描主頁左側(cè)二維碼,加入群聊,一起學(xué)習(xí)一起進(jìn)步歡迎點(diǎn)贊收藏留言前情提要無意間聽到領(lǐng)導(dǎo)們的談話,現(xiàn)在公司的現(xiàn)狀是碼農(nóng)太多,但能獨(dú)立帶隊(duì)的人太少,簡(jiǎn)而言之,不缺干 ? 哪吒社區(qū)Java技能樹打卡?【打卡貼 day2...
摘要:所以是數(shù)組指針,而是指針數(shù)組。因?yàn)閷?duì)一個(gè)二維數(shù)組,可以不知道有多少行,但是必須知道一行多少元素。當(dāng)二維數(shù)組數(shù)組名傳參,形參接收時(shí),數(shù)組的行可以省略,列不能省略,如果省略了列,我們就無法知道當(dāng)指針加減跳過幾個(gè)字節(jié)。 ...
此專欄文章是對(duì)力扣上算法題目各種方法的總結(jié)和歸納, 整理出最重要的思路和知識(shí)重點(diǎn)并以思維導(dǎo)圖形式呈現(xiàn), 當(dāng)然也會(huì)加上我對(duì)導(dǎo)圖的詳解. 目的是為了更方便快捷的記憶和回憶算法重點(diǎn)(不用每次都重復(fù)看題解), 畢竟算法不是做了一遍就能完全記住的. 所以本文適合已經(jīng)知道解題思路和方法, 想進(jìn)一步加強(qiáng)理解和記憶的朋友, 并不適合第一次接觸此題的朋友(可以根據(jù)題號(hào)先去力扣看看官方題解, 然后再看本文內(nèi)容). 關(guān)...
閱讀 1437·2021-09-28 09:43
閱讀 4329·2021-09-04 16:41
閱讀 1962·2019-08-30 15:44
閱讀 3839·2019-08-30 15:43
閱讀 818·2019-08-30 14:21
閱讀 2070·2019-08-30 11:00
閱讀 3364·2019-08-29 16:20
閱讀 1984·2019-08-29 14:21