この構文はdouble x[]
何ですか?
配列を宣言するのはCの方法ですか?
次のような関数がある場合
void evaluate(double x[], double *f)
{
// evaluate
}
任意の長さのパラメーター x を渡すことはできますか?
配列型のパラメーターは、ポインターとまったく同じように動作します。配列を関数の引数として渡すことはできません。ただし、この構文は、読みやすくするためにできるという錯覚を与えます。したがって、関数は次と同等です。
void evaluate(double *x, double *f)
{
// evaluate
}
ISO/IEC 14882:2011 の §8.3.5/5 から:
各パラメーターの型を決定した後、「T の配列」または「T を返す関数」型のパラメーターは、それぞれ「T へのポインター」または「T を返す関数へのポインター」になるように調整されます。
配列を表す式は、その最初の要素へのポインターに減衰するため、引き続きこれを行うことができます。
void evaluate(double x[]);
int array[] = {1, 2, 3, 4, 5};
evaluate(array); // The array decays to a pointer to its first element
§4.2から:
「NT の配列」または「T の境界が不明な配列」型の左辺値または右辺値は、「T へのポインタ」型の prvalue に変換できます。結果は、配列の最初の要素へのポインターです。
はい、実際に任意の長さの配列を渡すことができます。実際には、最初の要素へのポインターを渡しているだけです。ただし、必要に応じて、配列の長さも渡す必要があります。
ほとんどの場合、配列の名前は最初の要素へのポインタに崩壊するため、配列は混乱を招く可能性があります。それで:
double x[3]; // x is an array of 3 doubles
void f(double x[3]); // f takes a pointer to double
f(x); // calls f with the address of x[0]
配列型をポインタに減衰させる理由は、f
配列サイズごとに個別の関数を用意する必要がないようにするためです。
double x[3];
double y[4];
void f(double x[3], int size) {
for (int i = 0; i < size; ++i)
std::cout << x[i] << ' ';
std::cout << '\n';
}
f(x, 3);
f(y, 4);
引数が、、、、、;の場合も同じように機能double*x
しdouble x[]
ます。これらすべての場合において、はとして扱われます。double x[3]
double x[17]
double x[]
x
double*
関数のパラメータ リスト内では、double x[]
と同じdouble *x
です。
任意の長さのパラメーター x を渡すことはできますか?
はい、合格できます。x
しかし、関数内の配列の長さを知る方法はありませんevaluate
。したがって、おそらく長さも渡したいでしょう。
配列はすぐにポインターに分解されるため、配列が実際に関数に渡されることはありません。関数が配列をパラメーターとして受け取るふりをして、対応するパラメーターを配列として宣言することでそれを説明できます。
void f(char a[]) { ... }
文字どおりに解釈すると、この宣言は役に立たないため、コンパイラは向きを変えて、関数が実際に受け取るものであるため、ポインター宣言を記述したふりをします。
void f(char *a) { ... }
関数が伝統的に配列を操作するために使用されている場合、または関数内でパラメーターが自然に配列として扱われている場合、関数が配列を「受け取る」かのように話すことに特に問題はありません。
配列のような宣言子からポインターへのこの変換は、関数の仮パラメーター宣言内でのみ保持され、それ以外の場所では保持されません。変換が気になる場合は、強制的に使用する必要はありません。多くのプログラマーは、それが引き起こす混乱は、宣言が呼び出しや関数内での使用に「似ている」という小さな利点よりも重要であると結論付けています。(変換は 1 回だけ行われることに注意してください。char a2[][] のようなものは機能しません。質問 6.18 と 6.19 を参照してください。)
つまり、関数のパラメーター宣言では、長さが指定されていない配列はポインターと同じです。
void evaluate(double x[], double *f)
{
// evaluate
}
実際には次と同等です:
void evaluate(double *x, double *f)
{
// evaluate
}
C および C++ で。
これは、x
パラメーターの型がdouble *
両方の場合であることを意味します。
関数の引数x
は長さが指定されていない配列です。つまりdouble
、サイズに関係なく、任意の型の配列を渡すことができます。へのポインターをdouble
引数として渡すこともできます。
ただし、注意点が 1 つあります。sizeof
配列x
にはサイズがないため、この演算子は使用できません。