http://thomas0988.iteye.com/blog/133535
聲明:
如果你是得道的大俠,這篇文章可能浪費你的時間,如果你堅持要看,我當然感覺很高
興,但是希望你看完了別罵我!如果你發現我這篇文章有錯誤的話,你可以提出批評以及
指正,我將很樂意地接受。*_*
概述:
今天寫程序的時候要用到二維數組作參數傳給一個函數,我發現將二維數組作參數進行
傳遞還不是想象得那麼簡單裏,但是最後我也解決了遇到的問題,所以這篇文章主要介紹
如何處理二維數組當作參數傳遞的情況,希望大家不至於再在這上面浪費時間。
正文:
首先,我引用了譚浩強先生編著的《C程序設計》上面的一節原文,它簡要介紹瞭如何
將二維數組作爲參數傳遞,原文如下(略有改變,請原諒):
[原文開始]
可以用二維數組名作爲實參或者形參,在被調用函數中對形參數組定義時可以可以指
定所有維數的大小,也可以省略第一維的大小說明,如:
void Func(int array[3][10]);
void Func(int array[][10]);
二者都是合法而且等價,但是不能把第二維或者更高維的大小省略,如下面的定義是
不合法的:
void Func(int array[][]);
因爲從實參傳遞來的是數組的起始地址,在內存中按數組排列規則存放(按行存放),
而並不區分行和列,如果在形參中不說明列數,則系統無法決定應爲多少行多少列,不能
只指定一維而不指定第二維,下面寫法是錯誤的:
void Func(int array[3][]);實參數組維數可以大於形參數組,例如實參數組定義爲
:
void Func(int array[3][10]);
而形參數組定義爲:
int array[5][10];
這時形參數組只取實參數組的一部分,其餘部分不起作用。
[原文結束]
大家可以看到,將二維數組當作參數的時候,必須指明所有維數大小或者省略第一維的
,但是不能省略第二維或者更高維的大小,這是由編譯器原理限制的。大家在學編譯原理
這麼課程的時候知道編譯器是這樣處理數組的:
對於數組 int p[m][n];
如果要取p[i][j]的值(i>=0 && i<m && 0<=j && j < n),編譯器是這樣尋址的,它的
地址爲:
p + i*n + j;
從以上可以看出,如果我們省略了第二維或者更高維的大小,編譯器將不知道如何正確
的尋址。但是我們在編寫程序的時候卻需要用到各個維數都不固定的二維數組作爲參數,
這就難辦了,編譯器不能識別阿,怎麼辦呢?不要着急,編譯器雖然不能識別,但是我們
完全可以不把它當作一個二維數組,而是把它當作一個普通的指針,再另外加上兩個參數
指明各個維數,然後我們爲二維數組手工尋址,這樣就達到了將二維數組作爲函數的參數
傳遞的目的,根據這個思想,我們可以把維數固定的參數變爲維數隨即的參數,例如:
void Func(int array[3][10]);
void Func(int array[][10]);
變爲:
void Func(int **array, int m, int n);
在轉變後的函數中,array[i][j]這樣的式子是不對的(不信,大家可以試一下),因爲
編譯器不能正確的爲它尋址,所以我們需要模仿編譯器的行爲把array[i][j]這樣的式子
手工轉變爲
*((int*)array + n*i + j);
在調用這樣的函數的時候,需要注意一下,如下面的例子:
int a[3][3] =
{
{1, 1, 1},
{2, 2, 2},
{3, 3, 3}
};
Func(a, 3, 3);
根據不同編譯器不同的設置,可能出現warning 或者error,可以進行強制轉換如下調用
:
Func((int**)a, 3, 3);
其實多維數組和二維數組原理是一樣的,大家可以自己擴充的多維數組,這裏不再贅述
。寫到這裏,我先向看了這篇文章後悔的人道歉,浪費你的時間了。下面是一個完整的例
子程序,這個例子程序的主要功能是求一個圖中某個頂點到其他頂點的最短路經,圖是以
鄰接矩陣的形式存放的(也就是一個二維數組),其實這個函數也是挺有用的,但是我們這
篇文章的重點在於將二維數組作爲函數的參數傳遞。
完整的例子程序包括三個文件,在Microsoft Visual C++ 6.0下調試通過。如下:
//
// mian.c 爲主程序入口,並且調用了示範瞭如何調用求一個圖中某個頂點到其他頂點
的最短路經
// 的函數
//
#include "short.h"
#include <stdio.h>
int main()
{
int i = 0, v = 0;
float AdjoinMatrix[5][5]=
{
{0, 10,NO_PATH,30,100},
{NO_PATH,0,50,NO_PATH,NO_PATH},
{NO_PATH,NO_PATH,0,NO_PATH,10},
{NO_PATH,NO_PATH,20,0,60},
{NO_PATH,NO_PATH,NO_PATH,NO_PATH,0}
};
int Path[5];
float Length[5];
ShortestPath(AdjoinMatrix, Length, Path, 5, 0);
for(i = 1; i < 5; i++)
{
v = i;
while(v != 0)
{
printf("%d ", v);
v = Path[v];
}
printf("%d\n", v);
}
return 0;
}
//
// ShortestPath.h 中定義了求一個圖中某個頂點到其他頂點的最短路經的函數,還定
義了一個
// 宏,#define NO_PATH 0x00ffffff,如果圖中的兩個頂點之間的直接路徑的長度爲
NO_PATH,
// 表示圖中兩個頂點是不直接相通的。
//
#ifndef INCLUDE_SHORTESTPATH_H
#define INCLUDE_SHORTESTPATH_H
#define IN
#define OUT
#define NO_PATH 0x00ffffff
/*++
Abstract:
該函數的功能是求得一個圖中的某個頂點到其他所有頂點的最短路經,及其最
短路經的長度
Returen value:
類型是int,含義如下
0 成功
1 資源不夠
Examples:
//你有一個圖的鄰接矩陣如AdjoinMatrix[n][n]和數組
Path[n], Length[n](n爲圖頂點的個數,
//然後你可以如下調用:ShortestPath(AdjoinMatrix,
Length, Path, 5, 0);
//調用後,Path[n]中存放最短路徑,Length[n]中存放着最
短路徑的長度
//下面的例子中我們求得從0頂點到其他定點的最短路經及
其長度
float AdjoinMatrix[5][5]=
{
{0, 10,NO_PATH,30,100},
{NO_PATH,0,50,NO_PATH,NO_PATH},
{NO_PATH,NO_PATH,0,NO_PATH,10},
{NO_PATH,NO_PATH,20,0,60},
{NO_PATH,NO_PATH,NO_PATH,NO_PATH,0}
};
int Path[5];
float Length[5];
ShortestPath(AdjoinMatrix, Length, Path, 5,
0);
int i = 0, int v =0;
for(i = 1; i < 5; i++)
{
v = i;
while(v != 0)
{
printf("%d ", v);
v = Path[v];
}
printf("%d\n", v);
}
--*/
int ShortestPath(
IN float **AdjoinMatrix, //存放圖的鄰接矩陣,是
一個二維數組
OUT float *Length, //用於返回到各
個點的最短路經的長度
OUT int *Path, //用於返回最短
路經,Path[i]表示在最短路經上頂點i前面的頂點
IN int VertexNum, //頂點的個數
IN int Vertex //起始頂點
);
#endif
//
// ShortestPath.c 中實現了求一個圖中某個頂點到其他頂點的最短路經的函數。
//
#include "ShortestPath.h"
#include <stdlib.h>
/*++
Abstract:
該函數的功能是求得一個圖中的某個頂點到其他所有頂點的最短路經,及其最短
路經的長度
Returen value:
類型是int,含義如下
0 成功
1 資源不夠
--*/
int ShortestPath(
IN float **AdjoinMatrix, //存放圖的鄰接矩陣,是
一個二維數組
OUT float *Length, //用於返回到各
個點的最短路經的長度
OUT int *Path, //用於返回最短
路經,Path[i]表示在最短路經上頂點i前面的頂點
IN int VertexNum, //頂點的個數
IN int Vertex //起始頂點
)
{
int i = 0, j = 0, w = 0;
//
// 已經在最短路經中的點的集合,如果VertexSet[i]不爲0,則表示第
i個點在該集合中
//
int *VertexSet = (int*)malloc(VertexNum);
if(VertexSet == NULL)
{
return 1; //缺乏內存資源
}
//
// 初始化
//
for(i = 0; i < VertexNum; i++)
{
Length[i] = *((float*)AdjoinMatrix + Vertex*VertexNum
+ i);
VertexSet[i]=0;
if(i != Vertex && Length[i] < NO_PATH)
{
Path[i]=Vertex;
}
else
{
Path[i] = -1;
}
}
VertexSet[Vertex] = 1;
Length[Vertex] = 0;
//
// 求得最短路經
//
for(i = 0; i < VertexNum-1; i++)
{
float min = NO_PATH;
int u = Vertex;
for(j = 0; j < VertexNum; j++)
{
if( !VertexSet[j] && Length[j] < min)
{
u = j;
min = Length[j];
}
}
VertexSet[u] = 1;
for(w = 0; w < VertexNum; w++)
{
if(!VertexSet[w] && *((float*)AdjoinMatrix +
u*VertexNum + w) < NO_PATH && Length[u]+*((float*)AdjoinMatrix + u*VertexNum +
w) < Length[w])
{
Length[w] = Length[u] +
*((float*)AdjoinMatrix + u*VertexNum + w);
Path[w] = u;
}
}
}
return 0;
}