Обробка масивів C дуже відрізняється від Java, і вам доведеться відповідно налаштувати своє мислення. Масиви на C не є першокласними об'єктами (тобто вираз масиву не зберігає його "масив-ness" у більшості контекстів). У 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
оголошується char *a
замість char a[6]
. В sizeof str
, так як масив вираз є операндом sizeof
оператора, він не перетвориться в тип покажчика, так що ви отримаєте кількість байтів в масиві (6).
Якщо вас справді цікавить, ви можете прочитати «Розвиток мови С» Денніса Річі, щоб зрозуміти, звідки походить таке лікування.
Підсумок полягає в тому, що функції не можуть повертати типи масивів, що добре, оскільки вирази масиву також не можуть бути ціллю призначення.
Найбезпечнішим методом є те, що абонент повинен визначити масив та передати його адресу та розмір функції, яка повинна йому написати:
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
це буде константа часу компіляції, тобто ця функція буде працювати колись лише з одним розміром масиву. По-друге, вам слід знеструмити покажчик перед тим, як застосувати індекс, який захаращує код. Покажчики на масиви працюють краще, коли ви маєте справу з багатовимірними масивами.