Если возвращаем НОВУЮ память:
1. вернуть массив заведомо бóльшей длины и поле длины.
struct Arr1 {
int length;
int data[100];
}
struct Arr1 someFunc() {}
2. Вернуть динамический массив.
struct Arr2 {
int length;
int* data; // не забудь free(arr.data);
}
struct Arr2 someFunc() {}
Если работаем в ИМЕЮЩЕЙСЯ памяти.
3. Тот же Arr2, но разница в том, что data не надо высвобождать.
4. А если arr.data гарантированно понятное — то можно вернуть только int, поле длины (как в функции sprintf).
int sprintf ( char * str, const char * format, ... );
Она и возвращает массив — только его адрес гарантированно будет str и вернуть надо только длину.