Il trattamento delle matrici di C è molto diverso da quello di Java e dovrai adattare il tuo pensiero di conseguenza. Le matrici in C non sono oggetti di prima classe (ovvero, un'espressione di matrice non mantiene la sua "matrice" nella maggior parte dei contesti). In C, un'espressione di tipo "Matrice di elementi N di T
" sarà convertita in modo implicito ("decadimento") in un'espressione di tipo "puntatore a T
", tranne quando l'espressione di matrice è un operando degli operatori sizeof
unari &
o, o se il espressione di matrice è una stringa letterale utilizzata per inizializzare un altro array in una dichiarazione.
Tra le altre cose, ciò significa che non è possibile passare un'espressione di matrice a una funzione e averla ricevuta come tipo di matrice ; la funzione riceve effettivamente un tipo di puntatore:
void foo(char *a, size_t asize)
{
// do something with a
}
int bar(void)
{
char str[6] = "Hello";
foo(str, sizeof str);
}
Nella chiamata a foo
, l'espressione str
viene convertita dal tipo char [6]
in char *
, motivo per cui foo
viene dichiarato il primo parametro di char *a
anziché char a[6]
. In sizeof str
, poiché l'espressione di matrice è un operando sizeof
dell'operatore, non viene convertita in un tipo di puntatore, quindi ottieni il numero di byte nella matrice (6).
Se sei davvero interessato, puoi leggere Lo sviluppo del linguaggio C di Dennis Ritchie per capire da dove proviene questo trattamento.
Il risultato è che le funzioni non possono restituire i tipi di array, il che va bene poiché le espressioni di array non possono essere neppure la destinazione di un compito.
Il metodo più sicuro è che il chiamante definisca l'array e passi il suo indirizzo e dimensione alla funzione che dovrebbe scrivergli:
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);
...
}
Un altro metodo è per la funzione di allocare dinamicamente l'array e restituire il puntatore e la dimensione:
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 questo caso, il chiamante è responsabile della deallocazione dell'array con la free
funzione di libreria.
Si noti che dst
nel codice sopra è un semplice puntatore a char
, non un puntatore a una matrice di char
. La semantica del puntatore e dell'array di C è tale che è possibile applicare l'operatore di sottoscrizione []
a un'espressione di tipo di array o tipo di puntatore; entrambi src[i]
e dst[i]
accederanno i
all'elemento th dell'array (anche se src
ha solo il tipo di array).
È possibile dichiarare un puntatore ad un array N-elemento T
e fare qualcosa di simile:
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]);
...
}
Diversi inconvenienti con quanto sopra. Innanzitutto, le versioni precedenti di C prevedono SOME_SIZE
di essere una costante di tempo di compilazione, il che significa che la funzione funzionerà solo con una dimensione dell'array. In secondo luogo, devi dereferenziare il puntatore prima di applicare il pedice, che ingombra il codice. I puntatori agli array funzionano meglio quando si ha a che fare con array multidimensionali.