我大二剛學完C語言,之后用來寫矩陣分析的時候想把二維矩陣直接傳到函數里,結果出現了問題:形參實參類型不一致,無法通過編譯!隨后我就嘗試各種方法(改變形參或者實參的格式),雖然最后通過了不過當時還是沒理解原理。
后來自己把原因分析出來了,現在把它寫出來,希望對碰到同樣問題的朋友有所幫助。
轉載請注明出處,謝謝!
幾個跟參數有關的知識:C/C++的函數形參可以是普通類型、指針、引用。傳值方式有兩種:值傳遞(包括指針)、引用。 傳參時從左往右,結合時從右往左,這個很重要(函數默認值與此有關)。
參數是指針時,我們一般通過兩種方式實現讀寫:①移動指針 p++ ② p+i(目標位置)或者 p[i],等同於尋址的方式實現,他們實現時在內存里的操作: 一維 p+0(p[0]) p+1(p[1]) p+2(p[2]) ······ p+(n-1) (p[n-1]) 由於作圖不太方便,下面的講解就不附圖了。
1、一維數組(指針)
做參數 一般指針做參數我就不多說了,專門搜這種問題的人應該都懂。
下面說一下一維數組: 一般傳參情況:字符串、整型數組(舉個特例,實際上字符串是字符型數組)。 字符串,我們一般用下面這種方式:
bool PrintStr(char* str)//char str[]也一樣
{
if (NULL == str || "" == str)
{
return false;
}
for (int i = 0; i < strlen(str);i++)//就不考慮效率了,注意不要用sizeof
{
cout << str[i] << " ";
}
while ('\0' != *str)//通過指針
{
cout << *str++ << " ";
}
return true;
}
2、二維數組做參數
在一維中我們看到,遍歷數組時必須有終止條件,可以是某種標志也可以規定移動次數。
當到二維的時候這種情況就更為復雜。很多人定義函數的時候將函數定義為雙重指針,傳參的時候直接把二維數組名放進去,例如:
//matrix 一維矩陣,m 矩陣行數,n矩陣列數
bool PrintMatrix(int** matrix,int m,int n)
{
return true;
}
int main(void)
{
int arr[3][3] = {1,2,3,4,5,6,7,8,9};
PrintMatrix(arr,3,3);
return 0;
}
這時候會提示錯誤:無法從int[3][3]轉為int**,類型不兼容! 當然會不兼容!
函數傳參的時候並不是你想的那樣,他需要知道傳入參數的特征:二維數組,數組每一維占多大。因為在函數里面讀寫實際是以*(p+i) 或者 p++的形式操作的。
二維數組如果那樣操作會怎么樣?我從第一行跳到第二行,你會這么寫 p+1 或者 p++,可是函數怎么操作?
int**p,p+1每次移動sizeof(int*) ==4個字節,*p+1每次會移動sizeof(int)個字節;int p[3][3],p+1每次移動sizeof(p[0]) ==3*4個字節,*p+1每次會移動sizeof(int)個字節。它們是不能等同看待的,否則很容易出現內存錯誤,甚至系統崩潰。
所以在定義函數的時候如果是一維就可以省略,因為指針是按照sizeof(指針類型)移動;而在二維的時候則必須告訴函數一維以后的數據布局,這樣它才不會讀寫錯誤甚至越界,一維部分也可以省略。
從抽象而且直接的角度,你也可以這么理解:一維的在內存中線性排列,讀寫的時候也是線性操作,所以通過了。當你需要處理的內容是非線性的時候,不僅僅要告訴函數我的內容是非線性的,還要告訴他非線性的特征:二維數組,數組每一維特征(空間大小)。
例如:
#define M 3
#define N 3
//matrix 一維矩陣,m 矩陣行數,n矩陣列數;
//M、N必須是常數,而且N必須和傳入的參數一致
bool PrintMatrix(int matrix[M][N], int m, int n)
{
return true;
}
//matrix 一維矩陣,m 矩陣行數,n矩陣列數
//M甚至可以省略,因為有類型int
bool PrintMatrix(int matrix[][N], int m, int n)
{
return true;
}
//matrix 一維矩陣,m 矩陣行數,n矩陣列數
//當然可以這么寫,它本來就是這個樣子!
bool PrintMatrix(int (*matrix)[N], int m, int n)
{
return true;
}
按照上面的方式完美通過,Perfect!
3、多維數組做參數
多維數組和二維數組類似,只不過需要多加幾個說明:
例如:int p[M][N][K] ,p[0][0][0+1] 指針移動移動一個類型長度4byte==sizeof(int),p[0][0+1][0] 指針移動一個維 K*sizeof(int),p[0+1][0][0]指針移動二維N*(K*sizeof(int))。
#define M 3
#define N 3
#define K 3
bool PrintMatrix(int(*matrix)[N][K], int m, int n,int k)
{
return true;
}
4、總結
通過上面分析可以看出多維指針比較復雜,很容易出錯。所以實際用的時候一般用其它方法繞過這個問題:數據整理為一維,處理完后再轉成原形式;用結構體或類;一維一維的處理等。
PS:今天登陸發現編碼出問題,重新編輯了一下