誰かがこれが何を意味するのか説明できますか?
int (*data[2])[2];
かっこは何ですか?
Cの場合、角かっこ[]はアスタリスクよりも優先順位が高くなります*
ウィキペディアからの良い説明:
変数を配列へのポインターとして宣言するには、括弧を使用する必要があります。これは、Cの括弧([])がアスタリスク(*)よりも優先されるためです。したがって、配列へのポインタを宣言する場合は、これをオーバーライドするために括弧を指定する必要があります。
double (*elephant)[20];
これは、象がポインターであり、象が指す型が20個のdouble値の配列であることを宣言します。
ポインタの配列へのポインタを宣言するには、表記を組み合わせるだけです。
int *(*crocodile)[15];
ソース。
そしてあなたの実際のケース:
int (*data[2])[5];
dataは2つの要素の配列です。各要素には、5つのintの配列へのポインターが含まれています。
したがって、「データ」タイプを使用してコードを作成できます。
int (*data[2])[5];
int x1[5];
data[0] = &x1;
data[1] = &x1;
data[2] = &x1;//<--- out of bounds, crash data has no 3rd element
int y1[10];
data[0] = &y1;//<--- compiling error, each element of data must point to an int[5] not an int[10]
Linux / Unix用に、そしておそらくWindows用にもダウンロードできる「cdecl」と呼ばれる非常にクールなプログラムがあります。C(またはc ++declを使用する場合はC++)変数宣言を貼り付けると、簡単な言葉でそれが綴られます。
C の式の読み方を知っていれば、複雑な宣言を読むことから一歩離れています。
何が
char *p;
本当に意味?それは*p
charであることを意味します。何が
int (*data[2])[5];
平均?それは(*data[x])[y]
int であることを意味します (0 <= x < 2 および 0 <= y < 5 の場合)。さて、それが何を意味するかを考えてみてください。data
... 2 の配列 ... ポインタ ... 5 の配列 ... 整数でなければなりません。
とてもエレガントだと思いませんか?あなたがしているのは、式の型を述べていることだけです。それを理解すれば、宣言はもうあなたを怖がらせることはありません!
「クイックルール」は、変数名から始めて、 ) を押すまで右にスキャンし、変数名に戻り、 ( を押すまで左にスキャンします。次に、括弧のペアから「ステップアウト」します、プロセスを繰り返します。
ばかげたことに適用してみましょう。
void **(*(*weird)[6])(char, int);
weird
それぞれが引数として char と int を受け取り、それぞれが void へのポインターへのポインターを返す関数への 6 つのポインターの配列へのポインターです。
それが何であり、どのように行われるかがわかったので、それをしないでください。typedef を使用して、宣言をより管理しやすいチャンクに分割します。例えば
typedef void **(*sillyFunction)(char, int);
sillyFunction (*weird)[6];
data[2] - 2 つの整数の配列
*data[2] - 2 つの整数の配列へのポインター
(*データ[2]) - "
(*data[2])[2] - 2 つの整数の配列への 2 つのポインターの配列。
配列がある場合:
int myArray[5];
int * myArrayPtr = myArray;
完全に合理的でしょう。myArray
括弧なしはへのポインタint
です。ブラケットを追加すると、ポインターを参照するようになりますmyArray
。あなたは書くことができます...
myArrayPtr[1] = 3;
これは完全に合理的です。括弧を使用すると、IMO の読み方や理解が難しくなります。そして、ポインター、配列、およびポインター演算 (コンパイラーまたはリンカーが一方から他方へ移動する方法) を人々が理解していないことを示しています。ただし、括弧を使用すると、境界チェックが行われるようです。