I am relatively new to C and I need some help with methods dealing with arrays. Coming from Java programming, I am used to being able to say int [] method()
in o
C's treatment of arrays is very different from Java's, and you'll have to adjust your thinking accordingly. Arrays in C are not first-class objects (that is, an array expression does not retain it's "array-ness" in most contexts). In C, an expression of type "N-element array of T
" will be implicitly converted ("decay") to an expression of type "pointer to T
", except when the array expression is an operand of the sizeof
or unary &
operators, or if the array expression is a string literal being used to initialize another array in a declaration.
Among other things, this means that you cannot pass an array expression to a function and have it received as an array type; the function actually receives a pointer type:
void foo(char *a, size_t asize)
{
// do something with a
}
int bar(void)
{
char str[6] = "Hello";
foo(str, sizeof str);
}
In the call to foo
, the expression str
is converted from type char [6]
to char *
, which is why the first parameter of foo
is declared char *a
instead of char a[6]
. In sizeof str
, since the array expression is an operand of the sizeof
operator, it's not converted to a pointer type, so you get the number of bytes in the array (6).
If you're really interested, you can read Dennis Ritchie's The Development of the C Language to understand where this treatment comes from.
The upshot is that functions cannot return array types, which is fine since array expressions cannot be the target of an assignment, either.
The safest method is for the caller to define the array, and pass its address and size to the function that's supposed to write to it:
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);
...
}
Another method is for the function to allocate the array dynamically and return the pointer and size:
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);
...
}
In this case, the caller is responsible for deallocating the array with the free
library function.
Note that dst
in the above code is a simple pointer to char
, not a pointer to an array of char
. C's pointer and array semantics are such that you can apply the subscript operator []
to either an expression of array type or pointer type; both src[i]
and dst[i]
will access the i
'th element of the array (even though only src
has array type).
You can declare a pointer to an N-element array of T
and do something similar:
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]);
...
}
Several drawbacks with the above. First of all, older versions of C expect SOME_SIZE
to be a compile-time constant, meaning that function will only ever work with one array size. Secondly, you have to dereference the pointer before applying the subscript, which clutters the code. Pointers to arrays work better when you're dealing with multi-dimensional arrays.