cerhu > comp.lang.* > comp.lang.c

Thierry Abrard (03/12/2003, 09h10)
Bonjour,

Lorsque l'on défini une fonction, peut-elle retourner un pointeur
(tableau) ?

Actuellement, j'ai défini quelques fonctions du type :
void MaFonction (char Data1, char Data2)
{
le calcul...
Resultat[0] = ?;
Resultat[1] = ?;
}

Pour réutiliser mon tableau Resultat et ces données dans le main, je
le défini donc en variables globale (char Resultat[2]). Mais je trouve
que cette méthode n'est pas très simple à utiliser par la suite... en
effet, dans le main je me retrouve avec des fonctions :
Mafonction (Octet1, Octet2)
et faut ensuite se souvenir de quelle variable globale y est
associé...

J'aimerais donc savoir si il est possible en C (j'ai encore beaucoup à
découvir) d'avoir une fonction du style : Resultat =
MaFonction(Octet1, Octet2) avec Resultat comme tableau...

Faut-il faire jouer les pointeurs là dedans ?
J'ai essayé :
Char * MaFonction (char Data1, char Data2)
{
char Resultat[2];
mes calculs... (Resultat[0] = ?, Resultat[1]=?)
return Resultat;
}
puis dans le main :
Resultat[0]=Mafonction(Octet1, Octet2)
Mais Resultat[1] n'est pas correct...

Si vous avez une piste à ce sujet pour obtenir ce que je souhaite...
Je vous remercie,
TA
Éric Lévénez (03/12/2003, 09h41)
Le 3/12/03 8:10, dans <2dd29628.0312022310.756daa07>,
« Thierry Abrard » <thierryabrard> a écrit :

> Lorsque l'on défini une fonction, peut-elle retourner un pointeur
> (tableau) ?


Oui.

> Actuellement, j'ai défini quelques fonctions du type :
> void MaFonction (char Data1, char Data2)
> {
> le calcul...
> Resultat[0] = ?;
> Resultat[1] = ?;
> }
> Pour réutiliser mon tableau Resultat et ces données dans le main, je
> le défini donc en variables globale (char Resultat[2]).


Ce n'est pas bien d'utiliser une globale.

> Mais je trouve
> que cette méthode n'est pas très simple à utiliser par la suite... en
> effet, dans le main je me retrouve avec des fonctions :
> Mafonction (Octet1, Octet2)
> et faut ensuite se souvenir de quelle variable globale y est
> associé...


Il faut passer Resultat en argument à la fonction.

> J'aimerais donc savoir si il est possible en C (j'ai encore beaucoup à
> découvir) d'avoir une fonction du style : Resultat =
> MaFonction(Octet1, Octet2) avec Resultat comme tableau...


char *MaFonction(char Data1, char Data2)

> Faut-il faire jouer les pointeurs là dedans ?
> J'ai essayé :
> Char * MaFonction (char Data1, char Data2)
> {
> char Resultat[2];
> mes calculs... (Resultat[0] = ?, Resultat[1]=?)
> return Resultat;


Non, ça ne marche pas car "Resultat" est locale à MaFonction, et n'est pas
définie en dehors. Typiquement c'est une variable en pile, et donc le
return, dépilant tout, la variable est écrasée.

Si tu veux ce genre de construction il faut soit allouer Resultat avec
malloc (il faudra normalement faire un free dessus), soit définir le tableau
en static dans la fonction :

char *MaFonction(char Data1, char Data2)
{
static char Resultat[2];

Ainsi Resultat est alloué une fois pour tout, et ne disparaîtra pas au
return.

> }
> puis dans le main :
> Resultat[0]=Mafonction(Octet1, Octet2)


Non. MaFonction retourne un pointeur, pas un char, l'affectation adaptée
serait :

resultat2 = MaFonction(Octet1, Octet2);

Et après tu peux utiliser

resultat2[0] ou resultat2[1]

> Mais Resultat[1] n'est pas correct...


Normal. À l'affectation ton compilateur doit crier que tu affecte un
pointeur à un char, non ?
Marc Boyer (03/12/2003, 10h06)
Thierry Abrard wrote:
> Bonjour,
> Lorsque l'on défini une fonction, peut-elle retourner un pointeur
> (tableau) ?


Oui, toute la question etant de savoir qui est en charge d'allouer
et de liberer la memoire de ce tableau.
> Actuellement, j'ai défini quelques fonctions du type : [SNIP]
> Pour réutiliser mon tableau Resultat et ces données dans le main, je
> le défini donc en variables globale (char Resultat[2]). Mais je trouve
> que cette méthode n'est pas très simple à utiliser par la suite...


Et c'est entre autre pour cela qu'on la deconseille fortement.

> J'aimerais donc savoir si il est possible en C (j'ai encore beaucoup à
> découvir) d'avoir une fonction du style : Resultat =
> MaFonction(Octet1, Octet2) avec Resultat comme tableau...


Une fonction peut retourner un pointeur qui est l'adresse d'un
tableau, mais pas un tableau (dans le sens de copie des elements),
a moins d'encapsuler le tableau dans une structure.

> J'ai essayé :
> Char * MaFonction (char Data1, char Data2)
> {
> char Resultat[2];
> mes calculs... (Resultat[0] = ?, Resultat[1]=?)
> return Resultat;
> }
> puis dans le main :
> Resultat[0]=Mafonction(Octet1, Octet2)
> Mais Resultat[1] n'est pas correct...


Parce que ta fonction retourne un pointeur sur une variable
locale a la fonction MaFonction, et que quand cette fonction
est terminee, la variable n'existe plus.

> Si vous avez une piste à ce sujet pour obtenir ce que je souhaite...


Le version la plus classique, c'est

void MaFonction(char Data1, char Data2, char[] Resultat){
// Tes calculs
}

int main(){
char Res[2];
...
MaFonction(Octet1, Octet2, Res);
...
}

On peut trouver d'autres solutions, avec des variables
locales statiauesm des enregistrements, de l'allocation
dynamique, mais cette solution la devrait je pense resoudre
ton probleme.

Marc Boyer
Marc Boyer (03/12/2003, 10h13)
Éric Lévénez wrote:
> Le 3/12/03 8:10, dans <2dd29628.0312022310.756daa07>,
> « Thierry Abrard » <thierryabrard> a écrit :
> Si tu veux ce genre de construction il faut soit allouer Resultat avec
> malloc (il faudra normalement faire un free dessus), soit définir le tableau
> en static dans la fonction :
> char *MaFonction(char Data1, char Data2)
> {
> static char Resultat[2];
> Ainsi Resultat est alloué une fois pour tout, et ne disparaîtra pas au
> return.


Je trouve dangeureux de presenter cette solution a quelqu'un
qui semble debuter. S'il s'habitue a ce type de passage de parametre,
il va avoir du mal s'il fait des appels successifs a la fonction,
voire un appel recursif (plus rare).

Marc Boyer
DINH Viêt Hoà (03/12/2003, 11h18)
Marc Boyer wrote :

> Je trouve dangeureux de presenter cette solution a quelqu'un
> qui semble debuter. S'il s'habitue a ce type de passage de parametre,
> il va avoir du mal s'il fait des appels successifs a la fonction,
> voire un appel recursif (plus rare).


Il existe sinon l'alternative :

char * MaFonction(char Data1, char Data2)
{
char * Resultat;

Resultat = malloc(2 * sizeof(* Resultat));

Resultat[0] = truc;
Resultat[1] = autre_truc;

return Resultat;
}

Il faut juste faire attention à bien libérer la mémoire utilisée par le
résultat avec free().
Marc Boyer (03/12/2003, 11h33)
DINH Viêt Hoà wrote:
> Il existe sinon l'alternative :
> char * MaFonction(char Data1, char Data2)
> {
> char * Resultat;
> Resultat = malloc(2 * sizeof(* Resultat));
> Resultat[0] = truc;
> Resultat[1] = autre_truc;
> return Resultat;
> }
> Il faut juste faire attention à bien libérer la mémoire utilisée par le
> résultat avec free().


Oui, mais Eric avait enonce cette possibilite.
Ceci dit, hors cas des initialiseurs d'ADT, j'evite les fonctions
qui retournent une memoire allouee. J'ai beaucoup lu (et pas mal constate
avec des debutants) que les gens avaient du mal a liberer la memoire
qu'ils n'avaient pas eut meme explicitement alloue.

Marc Boyer
Erwan David (03/12/2003, 11h39)
DINH Viêt Hoà <dinh.viet.hoa> écrivait :

> Il faut juste faire attention à bien libérer la mémoire utilisée par le
> résultat avec free().


Et à commenter la fonction en disant qu'elle alloue un buffer et que
l'appelant est responsable de la désallocation.
Yves ROMAN (03/12/2003, 15h01)
Thierry Abrard a écrit :
[..]
> }
> Pour réutiliser mon tableau Resultat et ces données dans le main, je
> le défini donc en variables globale (char Resultat[2]). Mais je trouve
> que cette méthode n'est pas très simple à utiliser par la suite... en
> effet, dans le main je me retrouve avec des fonctions :
> Mafonction (Octet1, Octet2)
> et faut ensuite se souvenir de quelle variable globale y est
> associé... [...]
> Si vous avez une piste à ce sujet pour obtenir ce que je souhaite...
> Je vous remercie,


Comme personne n'en a parlé (sans doute parce que ca ne correspond pas au titre)
mais comme c'est aussi une solution, je te rappelle l'utilisation du passage en
paramètre :

void MaFonction (char Data1, char Data2, char Resultat[2])
{
le calcul...
Resultat[0] = ?;
Resultat[1] = ?;
}

et a l'appel :

char MonResultat[2] ;

MaFonction(Octet1,Octet2,MonResultat) ;
Emmanuel Delahaye (03/12/2003, 21h57)
In 'fr.comp.lang.c', thierryabrard (Thierry Abrard) wrote:

> Lorsque l'on défini une fonction, peut-elle retourner un pointeur
> (tableau) ?


Une fonction peut ou non retourner une valeur. Cette valeur peut être une
adresse, dans ce cas, le type retourné est 'pointeur sur le type voulu'.

char const *fa();
int *fb();
struct xx *fc();

Toutefois, pour pouvoir être utilisée (déréférencée), cette adresse doit être
valide, notamment après l'exécution de la fonction.

C'est le cas de l'adresse :

- d'une variable locale de l'appelant.
- d'un paramètre 'adresse valide' de l'appelant.
- d'une variable statique (peu recommandé sauf pour une donnée constante)
- d'une variable allouée avec malloc() ou fopen().

[..]
> Mafonction (Octet1, Octet2)
> et faut ensuite se souvenir de quelle variable globale y est
> associé...


Oui, cette conception est d'apparence simple, mais trompeuse. Il est
formellement déconseillé de travailler comme ça pour de nombreuses raisons
maintes fois évoquées (lire les archives et la FAQ).

> J'aimerais donc savoir si il est possible en C (j'ai encore beaucoup à
> découvir) d'avoir une fonction du style : Resultat =
> MaFonction(Octet1, Octet2) avec Resultat comme tableau...


On ne peut pas retourner un tableau en C. La méthode la plus courante est:

MaFonction (Resultat, Octet1, Octet2)

ou mieux

MaFonction (Resultat, Taille_de_resultat, Octet1, Octet2)

> Faut-il faire jouer les pointeurs là dedans ?
> J'ai essayé :
> Char * MaFonction (char Data1, char Data2)


'char'

On évitera 'char' pour des calculs, car ils sont traités en int, ce qui
oblige le compilateur à coder des conversions qui ne font que ralentir
l'exécution. de plus, la plage est limitée, et on ne sait pas si le 'char'
est signé ou non. Bref, la plage portable garantie est de 0 à 127.

> {
> char Resultat[2];
> mes calculs... (Resultat[0] = ?, Resultat[1]=?)
> return Resultat;
> }


C'est typiquement un cas interdit car l'adresse retournée n'est plus valide
une fois que l'on a quitté la fonction.

> puis dans le main :
> Resultat[0]=Mafonction(Octet1, Octet2)
> Mais Resultat[1] n'est pas correct...


C'est possible, car le comportement est indéfini (Undefined Behaviour ou UB).
Le plus grave serait qu'il ai l'air correct. (C'est possible avec un UB).
Emmanuel Delahaye (03/12/2003, 22h01)
In 'fr.comp.lang.c', Marc Boyer <Marc.Boyer> wrote:

>> char * MaFonction(char Data1, char Data2)
>> {
>> char * Resultat;
>> Resultat = malloc(2 * sizeof(* Resultat));


if (Resultat)
{

>> Resultat[0] = truc;
>> Resultat[1] = autre_truc;


}

> Ceci dit, hors cas des initialiseurs d'ADT, j'evite les fonctions
> qui retournent une memoire allouee. J'ai beaucoup lu (et pas mal constate
> avec des debutants) que les gens avaient du mal a liberer la memoire
> qu'ils n'avaient pas eut meme explicitement alloue.


C'est vrai. Il m'arrive d'utiliser de telles fonctions, et dans ce cas, j'y
accolle le suffixe '_dyn'

char *MaFonction_dyn (char Data1, char Data2)

C'est suffisant pour moi, mais peut être pas pour un autre...
Emmanuel Delahaye (03/12/2003, 22h05)
In 'fr.comp.lang.c', Yves ROMAN <yves.roman> wrote:

> void MaFonction (char Data1, char Data2, char Resultat[2])


Rappelons que le '2" ici n'a qu'une valeur documentaire. La taille du tableau
n'est pas transmise, et sizeof ne donnera pas le bon résultat.

Pour éviter les tentations:

void MaFonction (char Data1, char Data2, char Resultat[])
ou
void MaFonction (char Data1, char Data2, char *Resultat)
[..]
Thierry Abrard (05/12/2003, 01h40)
Merci beaucoup pour tout ces éléments de réponses... je devrais
maintenant sans problème trouver une solution. Même si l'affectation
dynamique avec les malloc etc n'est pas évident à comprendre (!), je
sais où chercher.

Je me contenterai donc pour le moment du passage du résultat en
paramètre de la fonction...

Good job !
TA
Marc Boyer (05/12/2003, 11h08)
Thierry Abrard wrote:
> Merci beaucoup pour tout ces éléments de réponses... je devrais
> maintenant sans problème trouver une solution. Même si l'affectation
> dynamique avec les malloc etc n'est pas évident à comprendre (!), je
> sais où chercher.


Disons qu'il vaut mieux prendre un problème après l'autre.
La maîtrise de l'allocation dynamique vient après la maîtrise
des structures de controle de base et l'appel de sous programme.

> Je me contenterai donc pour le moment du passage du résultat en
> paramètre de la fonction...


Un problème après l'autre, en effet.

Marc Boyer
Marc Espie (05/12/2003, 21h12)
In article <2dd29628.0312041540.5fb9eb5>,
Thierry Abrard <thierryabrard> wrote:
>Merci beaucoup pour tout ces éléments de réponses... je devrais
>maintenant sans problème trouver une solution. Même si l'affectation
>dynamique avec les malloc etc n'est pas évident à comprendre (!), je
>sais où chercher.

En fait, lorsqu'on peut eviter l'allocation dynamique avec malloc, on
s'en porte assez souvent mieux.

Oui, c'est souvent necessaire, mais dans la plupart des cas ou on peut
s'en passer, s'en passer est souvent plus efficace.

[ inserer ici un couplet standard sur les perfs respectives des tableaux
ajustes avec realloc compares aux listes chainees ]
Marc Lasson (05/12/2003, 23h19)
Marc Espie wrote:

> [ inserer ici un couplet standard sur les perfs respectives des tableaux
> ajustes avec realloc compares aux listes chainees ]


Euh, pourrais-je voir ce couplet (ou avoir une référence si vous en avez
déjà parlé) ?

Marci,

Discussions similaires
Fonction de Hash retournant une clé sur 12 bits

Fonction retournant une formule

Fonction retournant 2 valeurs

Fonction retournant une valeur constante


Fuseau horaire GMT +2. Il est actuellement 03h36. | Privacy Policy