Sposób traktowania tablic w języku C bardzo różni się od sposobu traktowania w Javie i będziesz musiał odpowiednio dostosować swoje myślenie. Tablice w języku C nie są obiektami pierwszej klasy (to znaczy, że wyrażenie tablicowe nie zachowuje swojej „macierzy” w większości kontekstów). W języku C wyrażenie typu „tablica elementów N T
” zostanie niejawnie przekonwertowane („rozpad”) na wyrażenie typu „wskaźnik do T
”, z wyjątkiem sytuacji, gdy wyrażenie tablicowe jest operandem sizeof
jednoargumentowym lub&
operatorów lub, lub jeśli wyrażenie tablicowe to literał łańcuchowy używany do inicjalizacji innej tablicy w deklaracji.
Oznacza to między innymi, że nie można przekazać wyrażenia tablicowego do funkcji i odebrać je jako typ tablicowy ; funkcja faktycznie otrzymuje typ wskaźnika:
void foo(char *a, size_t asize)
{
// do something with a
}
int bar(void)
{
char str[6] = "Hello";
foo(str, sizeof str);
}
W wywołaniu do foo
wyrażenie str
jest konwertowane z typu char [6]
na char *
, dlatego zamiast parametru foo
deklarowany jest pierwszy parametr . W , ponieważ wyrażenie tablicowe jest operandem operatora, nie jest konwertowane na typ wskaźnikowy, więc otrzymujesz liczbę bajtów w tablicy (6). char *a
char a[6]
sizeof str
sizeof
Jeśli jesteś naprawdę zainteresowany, możesz przeczytać książkę Dennisa Ritchiego The Development of the C Language, aby zrozumieć, skąd pochodzi ta terapia.
W rezultacie funkcje nie mogą zwracać typów tablicowych, co jest w porządku, ponieważ wyrażenia tablicowe również nie mogą być celem przypisania.
Najbezpieczniejszą metodą jest zdefiniowanie przez wywołującego tablicy i przekazanie jej adresu i rozmiaru do funkcji, która ma do niej pisać:
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);
...
}
Inną metodą jest dynamiczne przydzielanie tablicy przez funkcję i zwracanie wskaźnika i rozmiaru:
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);
...
}
W tym przypadku wywołujący jest odpowiedzialny za zwolnienie tablicy za pomocą free
funkcji bibliotecznej.
Zauważ, że dst
w powyższym kodzie jest prosty wskaźnik do char
, a nie wskaźnik do tablicy char
. Wskaźnik C i semantyka tablicy są takie, że można zastosować operator indeksu dolnego []
do wyrażenia typu tablicowego lub typu wskaźnika; oba src[i]
i dst[i]
uzyskają dostęp do i
'-tego elementu tablicy (nawet jeśli src
ma tylko typ tablicy).
Państwo może zadeklarować wskaźnik do tablicy N-pierwiastkowej T
i zrobić coś podobnego:
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]);
...
}
Kilka wad z powyższym. Po pierwsze, starsze wersje języka C oczekują, SOME_SIZE
że będzie to stała czasu kompilacji, co oznacza, że funkcja będzie działać zawsze tylko z jednym rozmiarem tablicy. Po drugie, przed zastosowaniem indeksu dolnego należy usunąć odwołanie ze wskaźnika, który zaśmieca kod. Wskaźniki do tablic działają lepiej, gdy masz do czynienia z tablicami wielowymiarowymi.