以下是網上摘抄的一段:
首先,我引用了譚浩強先生編著的《C程序設計》上面的一節(jié)原文,它簡要介紹了如何將二維數組作為參數傳遞,原文如下(略有改變,請原諒):
[原文開始]
可以用二維數組名作為實參或者形參,在被調用函數中對形參數組定義時可以指定所有維數的大小,也可以省略第一維的大小說明,如:
void Func(int array[3][10]);
void Func(int array[][10]);
二者都是合法而且等價,但是不能把第二維或者更高維的大小省略,如下面的定義是不合法的:
void Func(int array[][]);
因為從實參傳遞來的是數組的起始地址,在內存中按數組排列規(guī)則存放(按行存放),而并不區(qū)分行和列,如果在形參中不說明列數,則系統無法決定應為多少行多少列,不能只指定一維而不指定第二維,下面寫法是錯誤的:
void Func(int array[3][]);
實參數組維數可以大于形參數組,例如實參(zhihui3409注:應該是形參)數組定義為:
void Func(int array[3][10]);
而形參(zhihui3409注:應該是實參)數組定義為:
int array[5][10];
這時形參數組只取實參數組的一部分,其余部分不起作用。
[原文結束]
大家可以看到,將二維數組當作參數的時候,必須指明所有維數大小或者省略第一維的,但是不能省略第二維或者更高維的大小,這是由編譯器原理限制的。
根據編譯原理可知,如果我們省略了第二維或者更高維的大小,編譯器將不知道如何正確的尋址。但是我們在編寫程序的時候卻需要用到各個維數都不固定的二維數組作為參數,這就難辦了,編譯器不能識別啊,怎么辦呢?不要著急,編譯器雖然不能識別,但是我們完全可以不把它當作一個二維數組,而是把它當作一個普通的指針,再另外加上兩個參數指明各個維數,然后我們?yōu)槎S數組手工尋址,這樣就達到了將二維數組作為函數的參數傳遞的目的,根據這個思想,我們可以把維數固定的參數變?yōu)榫S數隨機的參數,例如:
void Func(int array[3][10]);
void Func(int array[][10]);
變?yōu)椋?br> void Func(int **array, int RowSize, int LineSize);
在轉變后的函數中,array[i][j]這樣的式子是不對的(不信,大家可以試一下),因為編譯器不能正確的為它尋址,所以我們需要模仿編譯器的行為把array[i][j]手工轉變?yōu)椋?br> *((int*)array + LineSize*i + j);即把二維數組當作一維數組來處理,這是比較容易理解的方式。其它方式見下面總結的第二點。
數組作為形參的問題總結:
1 一維數組作為函數形參
數組作為形參時,編譯器通常只會檢查數組形參關聯的實參,檢查的項目包括實參是不是指針、指針類型和數組元素的類型是否匹配,但不會檢查數組的長度。
void print( int *a[] )
void print( int *a[10] )
void print( int *a )
以上三個函數的聲明是等價的。
在很多情況下,將數組形參直接定義為指針要比使用數組語法定義方便很多。因為定義為指針后,函數可以借助于指針方便的操作數組元素。
數組以非引用類型的傳遞時,此時數組會自動轉換為同類型的指針,即初始化為相應類型實參的副本。調用函數時,函數實際操作的是指針的副本,而不會修改實參指針的值,但是可以通過指針改變數組元素的值。
2 多維數組的傳遞
多維數組的元素本身就是數組。
對二維數組的處理可以采用將二維數組看作一維或者二維數組來處理,下面兩個例子分別采用了這兩種方法。第3個例子有點不同,但實際上也是利用了一維數組作中間過渡處理。
例1 將二維數組當作一維數組來處理:
//print_array和主函數中的循環(huán)printf實現了同樣效果
#include <stdio.h>
void print_array(int *p,int RowSize,int LineSize)
{
int i,j;
for(i=0 ; i<RowSize ;i++)
{
for(j=0 ; j<LineSize ;j++)
printf("%d ",*(p+i*LineSize+j));
printf("\n");
}
}
void main()
{
int i,j,a[3][3]={ {1,0,0} , {0,1,0} , {0,0,1} };
print_array( (int *)a ,3,3);
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
printf("%d ",*(*(a+i)+j));
printf("\n");
}
}
例2 將二維數組依舊當作二維數組來處理
下面是一個字符串數組的參數傳遞程序,實現將字符串數組中的字符串按照從小到大的順序進行排序:
//WordSort實現了對5個字符串的排序
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
void WordSort(char p[][10],int RowSize)
{
int n=0,m;
char temp[10];
for(n=0;n<RowSize;n++)
for(m=n+1;m<RowSize;m++)
if( strcmp(p[m],p[n]) < 0 )
{
strcpy(temp,p[n]);
strcpy(p[n],p[m]);
strcpy(p[m],temp);
}
for(n=0;n<5;++n)
printf("In subfunction:%s\n",p[n]);
}
void main()
{
int k=0;
char word[5][10];
for(;k<5;++k)
scanf("%s",&word[k]);
WordSort(word,5);
printf("sorted word:\n");
for(k=0;k<5;k++)
printf("In main function:%s\n",word[k]);
system("pause");
}
例3 用“行指針”傳遞參數
運行下面程序:
/************************************/
//二維數組作為形參的參數傳遞方式之一
/************************************/
#include <stdio.h>
void print_array_1(int (*a)[3], int Row_Size)
{
int j;
for(j=0;j<3*Row_Size;j++)
{
printf("%d ",(*a)[j]);
if(j%3==2) printf("\n");
}
}
void print_array_2(int (*a)[3], int Row_Size)
{
int i,j;
for(i=0;i<Row_Size;i++)
{
for(j=0;j<3;j++)
printf("%d ",*(*(a+i)+j));
printf("\n");
}
}
void main()
{
int i,j,value=0;
int a[4][3]={0};
for(i=0;i<4;i++)
for(j=0;j<3;j++)
a[i][j]=value++;
print_array_1(a,4);
printf("\n");
print_array_2(a,4);
}
這個程序中的兩個函數實現了相同的功能:打印數組元素。這種方法可能容易使人迷惑:int (*a)[3] 是什么東西呢?還得看強哥的書(P229-P230),上面這樣寫道(在本例中):
*a有3個元素,每個元素為整型。也就是a所指向的對象是有3個整型元素的數組,即a是行指針。
再強調一遍 int (*a)[3] 中括號的作用,如果不明白它的重要性,請仔細對比本文章黃色背景的代碼。
補充一點,用這個方法處理字符串數組(字符型二維數組),還是比較方便的:用這樣一個例子結束本文:
//打印數組內字符串(一行)
#include <stdio.h>
void print_string(char (*string)[20], int Row_Size)
{
int i;
for(i=0;i<Row_Size;i++)
printf("%s\n",string+i);
}
void main()
{
char a[6][20]={"God","bless","you","who","help","themselves"};
print_string(a,6);
}