今天寫程序的時(shí)候要用到二維數(shù)組作參數(shù)傳給一個(gè)函數(shù),我發(fā)現(xiàn)將二維數(shù)組作參數(shù)進(jìn)行傳遞還不是想象得那么簡單,但是最后我也解決了遇到的問題,所以這篇文章主要介紹如何處理二維數(shù)組當(dāng)作參數(shù)傳遞的情況,希望大家不至于再在這上面浪費(fèi)時(shí)間。
下文是我從互聯(lián)網(wǎng)上download的一篇文章,講的很好,但是我后面將指出問題所在,并加以改進(jìn),希望對(duì)你有所幫助:
首先,我引用了譚浩強(qiáng)先生編著的《C程序設(shè)計(jì)》上面的一節(jié)原文,它簡要介紹了如何將二維數(shù)組作為參數(shù)傳遞,原文如下(略有改變,請?jiān)?span style="line-height: 34px; ">)
: [原文開始]
可以用二維數(shù)組名作為實(shí)參或者形參,在被調(diào)用函數(shù)中對(duì)形參數(shù)組定義時(shí)可以指定所有維數(shù)的大小,也可以省略第一維的大小說明,如:
void Func(int array[3][10]);
void Func(int array[][10]);
二者都是合法而且等價(jià),但是不能把第二維或者更高維的大小省略,如下面的定義是不合法的:
void Func(int array[][]);
因?yàn)閺膶?shí)參傳遞來的是數(shù)組的起始地址,在內(nèi)存中按數(shù)組排列規(guī)則存放(按行存放),而并不區(qū)分行和列,如果在形參中不說明列數(shù),則系統(tǒng)無法決定應(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ù)組的一部分,其余部分不起作用。
[原文結(jié)束]
大家可以看到,將二維數(shù)組當(dāng)作參數(shù)的時(shí)候,必須指明所有維數(shù)大小或者省略第一維的,但是不能省略第二維或者更高維的大小,這是由編譯器原理限制的。大家在學(xué)編譯原理這么課程的時(shí)候知道編譯器是這樣處理數(shù)組的:
對(duì)于數(shù)組 int p[m][n];
如果要取p[i][j]的值(i>=0 && i<m && 0<=j && j < n),編譯器是這樣尋址的,它的地址為:
p + i*n + j;
從以上可以看出,如果我們省略了第二維或者更高維的大小,編譯器將不知道如何正確的尋址。但是我們在編寫程序的時(shí)候卻需要用到各個(gè)維數(shù)都不固定的二維數(shù)組作為參數(shù),這就難辦了,編譯器不能識(shí)別阿,怎么辦呢?不要著急,編譯器雖然不能識(shí)別,但是我們完全可以不把它當(dāng)作一個(gè)二維數(shù)組,而是把它當(dāng)作一個(gè)普通的指針,再另外加上兩個(gè)參數(shù)指明各個(gè)維數(shù),然后我們?yōu)槎S數(shù)組手工尋址,這樣就達(dá)到了將二維數(shù)組作為函數(shù)的參數(shù)傳遞的目的,根據(jù)這個(gè)思想,我們可以把維數(shù)固定的參數(shù)變?yōu)榫S數(shù)隨即的參數(shù),例如:
void Func(int array[3][10]);
void Func(int array[][10]);
變?yōu)椋?/span>
void Func(int **array, int m, int n);
在轉(zhuǎn)變后的函數(shù)中,array[i][j]這樣的式子是不對(duì)的(不信,大家可以試一下),因?yàn)榫幾g器不能正確的為它尋址,所以我們需要模仿編譯器的行為把array[i][j]這樣的式子手工轉(zhuǎn)變?yōu)椋?/span>
*((int*)array + n*i + j);
在調(diào)用這樣的函數(shù)的時(shí)候,需要注意一下,如下面的例子:
int a[3][3] =
{
{1, 1, 1},
{2, 2, 2},
{3, 3, 3}
};
Func(a, 3, 3);
根據(jù)不同編譯器不同的設(shè)置,可能出現(xiàn)warning 或者error,可以進(jìn)行強(qiáng)制轉(zhuǎn)換如下調(diào)用:
Func((int**)a, 3, 3);
其實(shí)多維數(shù)組和二維數(shù)組原理是一樣的,大家可以自己擴(kuò)充的多維數(shù)組,這里不再贅述。寫到這里,我先向看了這篇文章后悔的人道歉,浪費(fèi)你的時(shí)間了。下面是一個(gè)完整的例子程序,這個(gè)例子程序的主要功能是求一個(gè)圖中某個(gè)頂點(diǎn)到其他頂點(diǎn)的最短路經(jīng),圖是以鄰接矩陣的形式存放的(也就是一個(gè)二維數(shù)組),其實(shí)這個(gè)函數(shù)也是挺有用的,但是我們這篇文章的重點(diǎn)在于將二維數(shù)組作為函數(shù)的參數(shù)傳遞。
上文結(jié)束,上文最后指出了實(shí)現(xiàn)二位數(shù)組作為函數(shù)參數(shù)的方法,但是它實(shí)現(xiàn)的是將靜態(tài)的二位數(shù)組作為參數(shù),但是如何將動(dòng)態(tài)而為數(shù)組作為參數(shù)呢?上面的方法顯然是不合適的,下面是我琢磨出來的方法。
先將靜態(tài)數(shù)組作為參數(shù)的代碼貼出來:
#include <iostream>
using namespace std;
void Calc(int **A, int m, int n);
int _tmain(int argc, _TCHAR* argv[])
{
int row = 0;
int col = 0;
int i = 0;
int A[3][3];
for (row = 0; row < 3; row++)
{
for (col = 0; col < 3; col++)
{
A[row][col] = row + col;
}
}
Calc((int **)A, 3, 3);
return 0;
}
void Calc(int **A, int m, int n)
{
if (NULL == A || m <1 || n < 1)
{
return;
}
int row = 0;
int col = 0;
int i = 0;
int j = 0;
int **matrix = NULL;
matrix = new int*[m];
if (NULL == matrix)
{
return;
}
for (row = 0; row < m; row++)
{
matrix[row] = new int[n];
if (NULL == matrix[row])
{
for (i = 0; i < row; i++)
{
delete []matrix[i];
matrix[i] = NULL;
}
delete []matrix;
matrix = NULL;
return;
}
}
for (row = 0; row < m; row++)
{
for (col = 0; col < n; col++)
{
matrix[row][col] = *((int *)A + row * n + col);
//matrix[row][col] = A[row][col];
}
}
for (row = 0; row < m; row++)
{
for (col = 0; col < n; col++)
{
cout<<matrix[row][col]<<" ";
}
cout<<"\n";
}
}
下面是動(dòng)態(tài)二位數(shù)組作為函數(shù)參數(shù)時(shí)的代碼:
#include <iostream>
using namespace std;
void Calc(int **A, int m, int n);
int main(int argc, char* argv[])
{
int row = 0;
int col = 0;
int i = 0;
int **A = NULL;
A = new int*[3];
if (NULL == A)
{
return 0;
}
for (row = 0; row < 3; row++)
{
A[row] = new int[3];
if (NULL == A[row])
{
for (i = 0; i < row; i++)
{
delete []A[i];
A[i] = NULL;
}
delete []A;
A = NULL;
return 0;
}
}
for (row = 0; row < 3; row++)
{
for (col = 0; col < 3; col++)
{
A[row][col] = row + col;
}
}
Calc((int **)A, 3, 3);
return 0;
}
void Calc(int **A, int m, int n)
{
if (NULL == A || m <1 || n < 1)
{
return;
}
int row = 0;
int col = 0;
int i = 0;
int j = 0;
int **matrix = NULL;
matrix = new int*[m];
if (NULL == matrix)
{
return;
}
for (row = 0; row < m; row++)
{
matrix[row] = new int[n];
if (NULL == matrix[row])
{
for (i = 0; i < row; i++)
{
delete []matrix[i];
matrix[i] = NULL;
}
delete []matrix;
matrix = NULL;
return;
}
}
for (row = 0; row < m; row++)
{
for (col = 0; col < n; col++)
{
//matrix[row][col] = *((int *)A + row * n + col);
matrix[row][col] = A[row][col];
}
}
for (row = 0; row < m; row++)
{
for (col = 0; col < n; col++)
{
cout<<matrix[row][col]<<" ";
}
cout<<"\n";
}
}
注意上面的代碼的不同之處,即將動(dòng)態(tài)二維數(shù)組作為函數(shù)參數(shù)時(shí),在函數(shù)里面應(yīng)用時(shí)候要將其偽裝成靜態(tài)二維數(shù)組!
這樣,以上的兩段代碼不僅實(shí)現(xiàn)了堆和棧之間數(shù)據(jù)的傳遞,而且實(shí)現(xiàn)了堆和堆之間數(shù)據(jù)的傳遞!