2次元配列を関数に渡すとき

仮引数はどう書けばいいでしょうか?

void piyo( int ? )
{
	hoge[3][2] = 1;
}

int main(void)
{
	int hoge[4][3];
	
	piyo(hoge);
	...
}



正解

この3つが正解で、どれも等価。つまり「(サイズ3の配列)へのポインタ」という意味です。C言語仮引数宣言においては、*hogehoge[ ]は等価で単なる見やすさのための糖衣構文です。ただし括弧が大事で、後述するように*hoge[3]と書いたら全く違う意味になります。
(*hoge)[3]とhoge[ ][3]は等価ですが、サイズ3の配列へのポインタを渡すときは(*hoge)[3]、サイズ3の配列の配列(2次元配列)を渡すときはhoge[ ][3]と書いたほうが意図が分かりやすいでしょう。
また、hoge[4][3]と書いても、要素数4は無視されます。コンパイラの気持ちになれば分かりますね。
サイズ3の配列へのポインタ

間違いその1

この3つはどれも等価で、「(サイズ不明の配列)へのポインタ」という意味です。サイズが不明なのでアドレスを計算できないからコンパイルエラーとなります。
サイズ不明の配列へのポインタ

間違いその2

この3つはどれも等価で、「ポインタへのポインタ」という意味です。意図が全く異なりますね。関数自体はコンパイルできますが、呼び出し元と型が合ってないのでコンパイルエラーになります。
ちなみに、**hogeと*hoge[ ]は等価ですが、ポインタへのポインタを渡すときは**hoge、ポインタ配列を渡すときは*hoge[ ]と書いたほうが意図が分かりやすいでしょう。
また、*hoge[3]と書いても要素数3は無視されます。
ポインタ配列へのポインタ

まとめ

  • 配列の配列(2次元配列) ないし 配列へのポインタ
  • ポインタの配列(ポインタ配列) ないし ポインタへのポインタ(ダブルポインタ)

これら全く別物です! 特に配列へのポインタとポインタの配列は紛らわしいので要注意です。