前言
多維數組中,二維數組是最常用的一種。在C語言編程中,二維數組的定義、取值以及賦值都比較容易,與一維數組類似。然而,在將二維數組作為函數參數傳遞時,參數結構較復雜,難以理解。本文章是實用型文章,注重代碼使用,不會講述過多理論。如果想要學習理論知識(非常推薦,可以對代碼的理解更透徹),可以查閱下方參考文獻列出書籍的第10章內容。話不多說,下面將給出一個C程序,以展示二維數組作為函數參數的4種方式。注:下面的代碼已在VS Code(使用Mingw64)和VS 2015下編譯運行過。
正文
下面程序的功能是對一個int型二維數組的所有元素進行求和,並分別把求和結果打印在屏幕上。根據二維數組傳入函數的方式,定義了4個版本的求和函數。
#include <stdio.h> #define ROW 2 //二維數組的行數 #define COL 2 //二維數組的列數 //4個版本的求和函數 //方式一:數組形式 int TwoDimArraySum1(int twoDimAr[][COL], int row, int col); //方式二:指針形式,prArray是一個指向包含COL個int的數組的指針 int TwoDimArraySum2(int (*prArray)[COL], int row, int col); //方式三:指針形式,pr是一個指向int的指針 int TwoDimArraySum3(int *pr, int row, int col); //方式四:變長數組(C99開始支持) int TwoDimArraySum4(int row, int col, int twoDimAr[row][col]); int main(void) { int twoDimArray[ROW][COL] = {{-2, 5}, {4, 9}}; int result; //方式一 result = TwoDimArraySum1(twoDimArray, ROW, COL); printf("Sum1函數結果:%d\n", result); //方式二 result = TwoDimArraySum2(twoDimArray, ROW, COL); printf("Sum2函數結果:%d\n", result); //方式三 result = TwoDimArraySum3(twoDimArray[0], ROW, COL); printf("Sum3函數結果:%d\n", result); //方式四 result = TwoDimArraySum4(ROW, COL, twoDimArray); printf("Sum4函數結果:%d\n", result); return 0; } int TwoDimArraySum1(int twoDimAr[][COL], int row, int col) { int i, j; int result = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { //下面兩種尋址方式都行 result += twoDimAr[i][j]; // result += *(*(twoDimAr + i) + j); } } return result; } int TwoDimArraySum2(int (*prArray)[COL], int row, int col) { int i, j; int result = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { //下面兩種尋址方式都行 result += prArray[i][j]; // result += *(*(prArray + i) + j); } } return result; } int TwoDimArraySum3(int *pr, int row, int col) { int i, j; int result = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { //下面兩種尋址方式都行 result += pr[i*row + j]; // result += *(Pr + i*row + j); } } return result; } int TwoDimArraySum4(int row, int col, int twoDimAr[row][col]) { int i, j; int result = 0; for (int i = 0; i < row; i++) { for (int j = 0; j < col; j++) { //下面兩種尋址方式都行 result += twoDimAr[i][j]; // result += *(*(prArray + i) + j); } } return result; }
正如程序注釋所言,方式4(變長數組)是C99開始支持的,不是所有編譯器都支持。例如,VS 2015就不支持該語法。因此,在VS 2015環境下運行時,方式4被注釋了。下面給出VS Code(基於Mingw64)以及VS 2015環境下的運行結果。
左圖為VS Code;右圖為VS 2015
優缺點評價
這里先給出結論,最推薦使用方式3。下面是簡要的分析。
- 方式1和方式2實質上是相同的。它們兼容性很好。但是,它們定義必須事先給出第二維的長度,即不是對任意大小的二維數組都適用。
- 方式3兼容性同樣很好,對任意大小的二維數組都適用。但是,它是最難理解的。理解它需要對二維數組元素的結構、二維數組元素的儲存以及二維數組與指針的關系有比較深刻的理解。
- 方式4是最容易理解的了。但是,它的兼容性最差。
此外還需要強調的是,對於該程序的求和函數,更安全、更易讀的寫法是將參數列表中接受二維數組數據的參數加上const修飾。本程序沒加的原因是為了更好的突出其功能。const修飾的對象不同,產生的效果也不同。如果參數列表中接受二維數組數據的參數加上const修飾,它將無法修改二維數組的數據;如果只有待傳入的二維數組是用const修飾,參數列表中的參數不是const修飾的,那么上述方式都不被允許。因此,請根據實際情況,自行決定const的修飾對象和修飾位置。
關於更高維數組
對於更高維的數組,上面四種方式仍然適用。除了方式3外,另外三種方式都很容易擴展成更高維的。對於方式3,雖然最推薦它,但是它隨着維數的增多,它變得更復雜更難理解。而且基於方式3,還可以延伸出其他方式。這里以三維數組舉例,方式3還可以延伸出這樣一種方式,該方式中接受三維數組的形參是一個指向一維數組的指針。對於這種由方式3延伸的方式,我是不推薦的,它比方式3更復雜,使用它還不如使用方式3。
參考文獻
Stephen Prata寫的《C Primer Plus》第五版