En C ANSI tu peut aussi passer une référence de structure:
struct t {
double tab[3]; /* ou double x,y,z; */
};
/* Version où le tableau retourné est passé en paramètre */
function f(struct t &t) {
t.tab[0] = ...; /* ou t.x = ... */
t.tab[1] = ...; /* ou t.y = ... */
t.tab[2] = ...; /* ou t.z = ... */
}
main() {
struct t ret;
f(ret);
printf("%lf %lf %lf", ret.tab[0], ret.tab[1], ret.tab[2]);
/* ou printf("%lf %lf %lf", ret.x, ret.y, ret.z); */
}
/* Version en passant 3 références aux variables à retourner */
function f (double &x, double &y, double &z) {
x = ...;
y = ...;
z = ...;
}
main() {
double x, y, z;
f(x, y, z);
printf("%lf %lf %lf", x, y, z);
}
Tu peux aussi utiliser directement une déclaration de tableau:
f(double tab[3]) {
tab[0] = ...;
tab[1] = ...;
tab[2] = ...;
}
main() {
double ret[3];
f(ret);
printf("%lf %lf %lf", ret[0], ret[1], ret[2]);
}
Maintenant si on suppose que le tableau n'est pas déclaré par l'appelant et n'est pas passé en paramètre, mais retourné à l'appelant, la seule façon est de l'allouer dynamiquement dans f:
double[3] f() {
double tab[] = (double[])calloc(sizeof double, 3);
/* et aussi, en C++ seulement: double tab[] = new double[3]; */
tab[0]=...;
tab[1]=...;
tab[2]=...;
return tab;
}
main() {
double ret[];
ret = f();
printf("%lf %lf %lf", ret[0], ret[1], ret[2]);
free((void*)ret); /* en C++: delete[] ret; */
}
/* version avec un typedef de tableau */
typedef double tableau[3];
tableau *f() {
tableau *tab = (tableau *)malloc(sizeof tableau);
/* et aussi, en C++ seulement: tableau *tab = new tableau; */
(*tab)[0] = ...;
(*tab)[1] = ...;
(*tab)[2] = ...;
return tab;
}
main() {
tableau *ret;
ret = f();
printf("%lf %lf %lf", (*ret)[0], (*ret)[1], (*ret)[2]);
free((void*)ret); /* en C++: delete ret; */
}
/* version avec une structure ou classe C++ */
typedef struct t {
double tab[3]; /* ou double x,y,z; */
} tableau;
tableau *f() {
tableau *val;
val = (tableau*)calloc(sizeof tableau);
/* et aussi, en C++ seulement: tab = new tableau;
val->tab[0] = ...; /* ou tab->x = ...; */
val->tab[1] = ...; /* ou tab->y = ...; */
val->tab[2] = ...; /* ou tab->z = ...; */
return val;
}
main() {
tableau *ret;
ret = f();
printf("%lf %lf %lf", ret->tab[0], ret->tab[1], ret->tab[2]);
/* ou printf("%lf %lf %lf", ret->x, ret->y, ret->z); */
free((void*)ret); /* ou en C++: delete ret; */
}
Le principal ennui avec les versions dynamiques où la fonction alloue la place pour le résultat est qu'elle confie la désallocation à l'appelant, et que cela peut générer non seulement des lenteurs (trop de new ou de malloc ou calloc), mais en plus il est plus difficile de maintenir le programme car des oublis de désallocation ou le problème des désallocations différées ou des références multiples à gérer pour savoir quand on peut libérer l'objet peuvent survenir.
Dans ce cas, il vaut mieux conceptuellement considérer que la fonction agit tel un constructeur C++, et qu'à tout constructeur (appel de f() dans un contexte local de variables ou scope) doit être associé un destructeur dans le même scope.
Aussi les solutions où c'est l'appelant qui s'occupe de gérer l'allocation de la valeur de retour d'une fonction sont en général plus propres (c'est le même cas ici quand une fonction doit retourner une chaine de caractères, qui est aussi un tableau de caractères): l'appelant précise à la fonction l'adresse ou la référence de la structure ou du tableau à retourné complété, accompagné d'indication telle que la longueur maximale du tableau, pour que la fonction adopte un comportement approprié en cas d'insuffisance de taille, par exemple retourner au programme client une indication d'erreur.
[edit]--Message édité par verdy_p--[/edit]