C语言中对数组的处理与Java截然不同,因此你需要相应地调整思维方式。在C语言中,数组不是一级对象(也就是说,在大多数情况下,数组表达式不会保留其 "数组性")。在C语言中,类型为“N个元素的
T
数组”的表达式将被隐式转换(“衰减”)为类型为“指向
T
的指针”的表达式,除非数组表达式是
sizeof
或一元
&
运算符的操作数,或者数组表达式是用于在声明中初始化另一个数组的字符串字面值。
此外,这意味着您无法将数组表达式传递给函数并将其接收为数组类型; 实际上,该函数接收到的是指针类型。
void foo(char *a, size_t asize)
{
}
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
具有数组类型)。
您可以声明一个指向
T
的N元素数组的指针,并进行类似操作:
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
必须是编译时常量,这意味着该函数只能适用于一个数组大小。其次,在应用下标之前必须解引用指针,这会使代码变得混乱。当处理多维数组时,指向数组的指针效果更好。