Cの配列の扱いはJava の扱いとは非常に異なり、それに応じて考え方を調整する必要があります。Cの配列は、ファーストクラスのオブジェクトではありません(つまり、配列式は、ほとんどのコンテキストでその「配列性」を保持しません)。Cでは、「N要素配列の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
は型char [6]
からchar *
に変換されます。そのため、の最初のパラメータがの代わりにfoo
宣言されます。では、配列式は演算子のオペランドなので、ポインター型に変換されないため、配列内のバイト数を取得します(6)。 char *a
char a[6]
sizeof str
sizeof
あなたがいる場合は、本当に興味を持って、あなたはデニス・リッチーさん読み取ることができるC言語のザ・開発を、この治療はどこから来るのかを理解すること。
結局のところ、関数は配列型を返すことができません。配列式も割り当てのターゲットにできないため、これは問題ありません。
最も安全な方法は、呼び出し元が配列を定義し、そのアドレスとサイズを、書き込むことになっている関数に渡すことです。
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);
...
}
別の方法は、関数が配列を動的に割り当て、ポインターとサイズを返すことです。
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]);
...
}
上記のいくつかの欠点。まず第一に、古いバージョンのC SOME_SIZE
はコンパイル時の定数であると想定しています。つまり、関数は1つの配列サイズでしか機能しません。次に、添え字を適用する前にポインタを逆参照する必要があります。これにより、コードが乱雑になります。配列へのポインターは、多次元配列を処理する場合により適切に機能します。