C の配列の扱いは Java とは大きく異なるため、それに応じて考え方を調整する必要があります。C の配列は第一級のオブジェクトではありません (つまり、配列式はほとんどのコンテキストでその「配列性」を保持しません)。C では、配列式がまたは 単項演算T
子T
のオペランドである場合、または配列式は、宣言で別の配列を初期化するために使用される文字列リテラルです。 sizeof
&
とりわけ、これは配列式を関数に渡して配列型として受け取ることができないことを意味します。関数は実際にポインター型を受け取ります。
void foo(char *a, size_t asize)
{
// do something with a
}
int bar(void)
{
char str[6] = "Hello";
foo(str, sizeof str);
}
の呼び出しfoo
で、式は型からにstr
変換されます。これが、 の代わりにの最初のパラメータが宣言されている理由です。では、配列式は演算子のオペランドであるため、ポインター型に変換されないため、配列内のバイト数 (6) を取得します。 char [6]
char *
foo
char *a
char a[6]
sizeof str
sizeof
本当に興味がある場合は、Dennis Ritchie のThe Development of the C Languageを読んで、この処理がどこから来たのかを理解してください。
要するに、関数は配列型を返すことができないということです。これは、配列式も代入の対象にならないため問題ありません。
最も安全な方法は、呼び出し元が配列を定義し、そのアドレスとサイズをそれに書き込む関数に渡すことです。
void returnArray(const char *srcArray, size_t srcSize, char *dstArray, char dstSize)
{
...
dstArray[i] = some_value_derived_from(srcArray[i]);
...
}
int main(void)
{
char src[] = "This is a test";
char dst[sizeof src];
...
returnArray(src, sizeof src, dst, sizeof dst);
...
}
もう 1 つの方法は、関数が動的に配列を割り当て、ポインターとサイズを返すことです。
char *returnArray(const char *srcArray, size_t srcSize, size_t *dstSize)
{
char *dstArray = malloc(srcSize);
if (dstArray)
{
*dstSize = srcSize;
...
}
return dstArray;
}
int main(void)
{
char src[] = "This is a test";
char *dst;
size_t dstSize;
dst = returnArray(src, sizeof src, &dstSize);
...
free(dst);
...
}
この場合、呼び出し元は、free
ライブラリ関数を使用して配列の割り当てを解除する必要があります。
dst
上記のコードでは、char
の配列へのポインターではなく、への単純なポインターであることに注意してくださいchar
。[]
C のポインターと配列のセマンティクスは、添字演算子を配列型またはポインター型の式に適用できるようなものです。src[i]
との両方が配列の '番目の要素にdst[i]
アクセスします(配列型しかありませんが)。i
src
の N 要素配列へのポインターを宣言し、同様のことを行うことができます。T
char (*returnArray(const char *srcArr, size_t srcSize))[SOME_SIZE]
{
char (*dstArr)[SOME_SIZE] = malloc(sizeof *dstArr);
if (dstArr)
{
...
(*dstArr)[i] = ...;
...
}
return dstArr;
}
int main(void)
{
char src[] = "This is a test";
char (*dst)[SOME_SIZE];
...
dst = returnArray(src, sizeof src);
...
printf("%c", (*dst)[j]);
...
}
上記のいくつかの欠点。まず第一に、古いバージョンの CSOME_SIZE
はコンパイル時の定数であると想定しています。つまり、関数は 1 つの配列サイズでしか機能しません。次に、添字を適用する前にポインターを逆参照する必要があり、コードが乱雑になります。多次元配列を扱う場合は、配列へのポインターがより適切に機能します。