C語(yǔ)言如果給函數(shù)傳遞二維數(shù)組作為參數(shù)
創(chuàng)新互聯(lián)是一家集網(wǎng)站建設(shè),茫崖企業(yè)網(wǎng)站建設(shè),茫崖品牌網(wǎng)站建設(shè),網(wǎng)站定制,茫崖網(wǎng)站建設(shè)報(bào)價(jià),網(wǎng)絡(luò)營(yíng)銷,網(wǎng)絡(luò)優(yōu)化,茫崖網(wǎng)站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強(qiáng)企業(yè)競(jìng)爭(zhēng)力。可充分滿足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網(wǎng)需求。同時(shí)我們時(shí)刻保持專業(yè)、時(shí)尚、前沿,時(shí)刻以成就客戶成長(zhǎng)自我,堅(jiān)持不斷學(xué)習(xí)、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實(shí)用型網(wǎng)站。
先看一個(gè)傳遞二維數(shù)組的例子:
編譯:
程序看著沒(méi)有任何問(wèn)題,但是編譯器通不過(guò),報(bào)錯(cuò)在處理二維數(shù)組參數(shù)a的時(shí)候,類型不兼容。
C語(yǔ)言里面對(duì)二維數(shù)組的存儲(chǔ)是按照一維數(shù)組來(lái)處理的,二維數(shù)組按照行展開的方式按順序存儲(chǔ),例如在上面的例子中:
二維數(shù)組a的定義:
它等同于一維數(shù)值的定義:
因?yàn)樗麄兊目臻g存儲(chǔ)分配一樣的。
所以在利用二維數(shù)組作為參數(shù)傳遞時(shí),必須指定二維數(shù)組的列數(shù),否則函數(shù)無(wú)法勾畫出二維數(shù)組的組織形式。只有有了列長(zhǎng)度,通過(guò)下標(biāo)a[i][j]時(shí)才能得到正確的下標(biāo)地址,即:
我們改一下上面的額foo函數(shù)定義:
編譯運(yùn)行:
這下就正常了。
參數(shù)如上所列。
我們看到,函數(shù)的參數(shù)聲明改成了:
這個(gè)聲明的含義是:
不過(guò)此時(shí)還是需要指定二維數(shù)組的列長(zhǎng)度,不然函數(shù)內(nèi)部還是無(wú)法使用二維下標(biāo)去訪問(wèn)數(shù)組:
編譯:
原因同前面方法1一致,如果要訪問(wèn)二維數(shù)組,必須指定列的長(zhǎng)度,否則無(wú)法計(jì)算出該元素的地址,a[i][j]=a [ (i-1)*COLNUM + j ],如果沒(méi)有COLNUM,那么這個(gè)地址無(wú)法計(jì)算出來(lái)。從形參的聲明來(lái)說(shuō),a就是一個(gè)指針,指向一維數(shù)組的指針,而不是一個(gè)二維數(shù)組。
這里要注意的是指針的指針,和二維數(shù)組的差異;二維數(shù)組的地址是連續(xù)的,所有成員按順序排序;而指針的指針只要求指針地址連續(xù),而不要求指針的指針地址連續(xù)。
然后作為實(shí)參傳遞時(shí),也不能直接使用a傳遞,因?yàn)轭愋筒黄ヅ?,必須定義新的變量p,然后把a(bǔ)的值賦給p,再傳遞給foo函數(shù)。
二維數(shù)組無(wú)法作為參數(shù)直接傳遞給函數(shù),但是可以利用二維數(shù)組內(nèi)部數(shù)據(jù)的連續(xù)性,將二維數(shù)組的地址按照一維數(shù)組的方式傳遞給函數(shù),并傳入對(duì)應(yīng)的行列數(shù),從而實(shí)現(xiàn)函數(shù)內(nèi)打印二維數(shù)組的效果。
以整型為例,具體方式如下:
void?print_array(int?*a,?int?m,?int?n)//a為一個(gè)m行,n列的二維數(shù)組的首地址。
{
int?i,?j;
for(i?=?0;?i??m;?i?++)
{
for(j?=?0;?j??n;?j?++)
{
printf("%d,",?a[i*n+j]);//a[i*n+j]也就是原始二維數(shù)組第i行第j列的元素。
}
printf("\n");//每行結(jié)束輸出換行。
}
}
對(duì)的,是我的第二種方法。
1.可以用指針。
void
Func(int
**array,
int
m,
int
n);
在轉(zhuǎn)變后的函數(shù)中,array[i][j]這樣的式子是不對(duì)的(不信,大家可以試一下),因?yàn)榫幾g器不能正確的為它尋址,所以我們需要模仿編譯器的行為把a(bǔ)rray[i][j]這樣的式子手工轉(zhuǎn)變?yōu)椋?/p>
*((int*)array
+
n*i
+
j);
2.可以用二維數(shù)組名作為實(shí)參或者形參,在被調(diào)用函數(shù)中對(duì)形參數(shù)組定義時(shí)可以指定所有維數(shù)的大小,也可以省略第一維的大小說(shuō)明,如:
void
Func(int
array[3][10]);
void
Func(int
array[][10]);
二者都是合法而且等價(jià),但是不能把第二維或者更高維的大小省略,如下面的定義是不合法的:
void
Func(int
array[][]);
因?yàn)閺膶?shí)參傳遞來(lái)的是數(shù)組的起始地址,在內(nèi)存中按數(shù)組排列規(guī)則存放(按行存放),而并不區(qū)分行和列,如果在形參中不說(shuō)明列數(shù),則系統(tǒng)無(wú)法決定應(yīng)為多少行多
少列,不能只指定一維而不指定第二維,下面寫法是錯(cuò)誤的:
void
Func(int
array[3][]);
實(shí)參數(shù)組維數(shù)可以大于形參數(shù)組,例如實(shí)參數(shù)組定義為:
void
Func(int
array[3][10]);
而形參數(shù)組定義為:
int
array[5][10];
這時(shí)形參數(shù)組只取實(shí)參數(shù)組的一部分,其余部分不起作用。
二維數(shù)組的本質(zhì)還是一位數(shù)組
返回?cái)?shù)組指針就可以
int
a[3][10];//假設(shè)全局
int
*
func()
{
return
a;
//返回的就是數(shù)組的指針
}
int
main(void)
{
int
*b;
b=func();
//這里b就指向數(shù)組地址
return
0;
}
C語(yǔ)言編程的過(guò)程中,不可避免的會(huì)碰到二維或二維以上的數(shù)組作為函數(shù)的形參的情況,在以前的編程過(guò)程中,習(xí)慣了動(dòng)態(tài)數(shù)組的應(yīng)用,很是使用直接定義高維數(shù)組。最近在編程的過(guò)程中就碰到了這個(gè)問(wèn)題:有如下的測(cè)試程序:
voidtest(double??**x,int?Row,int?Col);
voidtest(double??**x)
{
for(int?i=0;iRow;i++)
for(int?k=0;kCol;k++)
x[i][k]?+=?100.0;
}
intmain(int?argc,?char?*argv[])
{
/*
double?**x;
x?=?new?double?*[3];
for(int?i=0;i3;i++)
x[i]?=?new?double[3];
*/
double?x[3][3];
for(int?i=0;i3;i++)
for(int?k=0;k3;k++)
x[i][k]?=?i*k;
test(x,3,3);
for(int?i=0;i3;i++)
for(int?k=0;k3;k++)
printf("x[%d][%d]=?%e\n",i,k,x[i][k]);
getch();
return?0;
}
編譯時(shí)提示Cannot?convert?'double?[*][3]'?to?double?**'。
將調(diào)用方式強(qiáng)制進(jìn)行類型轉(zhuǎn)換:test((double?**)x),編譯通過(guò),運(yùn)行出錯(cuò),提示非法越界。
據(jù)傳:因?yàn)闂I戏峙涞臄?shù)組和堆上分配的數(shù)組在內(nèi)存排列上可能不相同,直接定義的數(shù)組是存儲(chǔ)在程序的堆棧區(qū),數(shù)據(jù)占用連續(xù)的區(qū)間;而動(dòng)態(tài)申請(qǐng)的數(shù)組是在系統(tǒng)的遠(yuǎn)堆上(far?heap),除最后一維的元素是連續(xù)存放的外,其他維上的元素有可能不是在一塊連續(xù)的內(nèi)存區(qū)域里。
//棧上:?
int???ia[2][2]???=?{2,3,4,5};????//4個(gè)元素是連續(xù)排列的內(nèi)存段?
//堆上:?
int???**p??=??new??int*[2];???//只有每行內(nèi)是連續(xù)排列,各行并不一定連續(xù)排列?
for?(?int??i??=?0;??i???2;?i++?)?
{?
p[i]???=??new??int[2];?
}?
for?(?int??i??=??0;??i????2;??i++?)?
{?
for?(?int??j??=??0;??j????2;??j++?)?
{?
p[i][j]???=???ia[i][j];?
}?
}?
所以對(duì)棧上的數(shù)組用int??**p指向首地址,因?yàn)閕nt??**p一次解引用為地址指針,而非堆上的指向數(shù)組的指針,所以二次解引用會(huì)出錯(cuò)。?
如果找一個(gè)通用方程只能用:?
void???f(?int??*p,?int??row,??int??col?)?????//給出數(shù)組的行和列,對(duì)堆上的數(shù)組不合適???
{?
for?(?int??i?=??0;??i????row;??i++)?
{?
for?(?int??j??=??0;??j???col;??j++?)?
{?
cout???p[i?*?row?+?j]???"???";????????????????????????
}?
cout???endl;?
}?
}?
int???main(){?
//.........?
int???ia[2][2]???=??{2,3,4,5};?
f(?(int*)ia,?2,?2?);?
}
采用上面的通用辦法還是比較麻煩,這無(wú)形中對(duì)編程增加了難度,為了避免這個(gè)麻煩可以采用動(dòng)態(tài)數(shù)組的形式,將原來(lái)采用直接定義的數(shù)組全部換成動(dòng)態(tài)數(shù)組,類似開頭例子中被注釋掉的那部分代碼,當(dāng)然這樣也有后續(xù)的麻煩,動(dòng)態(tài)數(shù)組的生命周期完成后必須釋放內(nèi)存空間,這也有點(diǎn)羅嗦,但是畢竟可以直接使用數(shù)組的形式,比上面的通用方式還是要簡(jiǎn)單一點(diǎn)。
如果執(zhí)意要使用直接定義的數(shù)組該怎么辦呢?有如下幾種方法:
方法一:
voidtest(double??(*x)[3],?int?Row,?int?Col);
調(diào)用方式:test(x,Row,Col);
調(diào)用用方式?test(x,Row,Col);
方法二:
voidtest(double??x[][3],?int?Row,int?Col);
調(diào)用方式?test(x,Row,Col);
對(duì)于多維數(shù)組作為參數(shù),除第一維之外的其它維必須指定維數(shù),否則是肯定編譯不過(guò)去的。
從上面的對(duì)直接定義的數(shù)組的引用情況看,直接定義的數(shù)組的使用比較麻煩,一旦直接定義數(shù)組的維數(shù)發(fā)生變換,函數(shù)的定義必須相應(yīng)的修改,否則程序就會(huì)出錯(cuò),這也增加了程序進(jìn)一步開發(fā)的麻煩,為了一勞永逸的解決這個(gè)問(wèn)題,建議還是使用動(dòng)態(tài)數(shù)組的方法,雖然需要手工釋放內(nèi)存,但是除卻了后續(xù)的麻煩。
標(biāo)題名稱:c語(yǔ)言用函數(shù)處理二維數(shù)組 C語(yǔ)言函數(shù)二維數(shù)組
URL地址:http://jinyejixie.com/article20/dochcjo.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供自適應(yīng)網(wǎng)站、域名注冊(cè)、微信公眾號(hào)、外貿(mào)建站、虛擬主機(jī)、網(wǎng)站收錄
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)