C 对数组的处理与 Java非常不同,您必须相应地调整您的想法。C 中的数组不是一等对象(也就是说,在大多数情况下,数组表达式不保留它的“数组特性”)。在 C 中,“N-element array of T
” 类型的表达式将被隐式转换(“decay”)为“pointer to 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
声明的第一个参数char *a
而不是char a[6]
。在sizeof str
中,由于数组表达式是运算符的操作数sizeof
,因此它不会转换为指针类型,因此您会得到数组中的字节数(6)。
如果您真的感兴趣,可以阅读 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);
...
}
另一种方法是让函数动态分配数组并返回指针和大小:
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
是一个编译时常量,这意味着该函数只能使用一个数组大小。其次,您必须在应用下标之前取消引用指针,这会使代码混乱。在处理多维数组时,指向数组的指针效果更好。