: Une fonction peut elle renvoyer un tableau ?? [C] - Programmation
Marsh Posté le 27-02-2001 à 22:41:56
oui c'est tout à fait possible, mais en pratique tu n'as pas du tout intérêt à surcharger la pile, il vaut 1000 fois mieux passer par un pointeur ou une référence.
--Message édité par z51--
Marsh Posté le 27-02-2001 à 22:57:27
En général, oui, mais en C, un tableau est déjà un pointeur, donc il n'y a même aucun risque d'exploser la pile...
Marsh Posté le 28-02-2001 à 09:39:35
euh... retourner un tableau c retourner une adresse
Marsh Posté le 28-02-2001 à 17:06:34
ex :
int* retournetableau()
{
int tab[5] = {0};
return tab;
}
la fonction retourne l'adresse du pointeur tab soit l'adresse du premier element du tableau soit l'adresse de tab[0].
Marsh Posté le 28-02-2001 à 17:23:48
Oui mais là c'est très dangereux, tu retourne l'adresse d'une variable locale !
Marsh Posté le 28-02-2001 à 18:24:11
C'est clair la viper ->
ne retourne jamais l'adresse d'une var locale !
Soit tu passes le tableau en paramètre de ta fonction, soit tu fais de l'allocation dynamique à l'intérieur (mais c'est crade)
Marsh Posté le 28-02-2001 à 18:30:24
le mieux c de faire faire passer un tableau en parametre...
Comme ca ta fonction est dechargée de tout ce ki est gestion de memoire... et elle peut donc se concentrer sur son but...
Marsh Posté le 28-02-2001 à 20:14:18
Je ne comprends pas pourquoi c'est crade d'allouer dynamiquement à l'intérieur de la fonction ? Pour moi ca revient au même .
Marsh Posté le 28-02-2001 à 20:24:33
Dans ce cas, il faut bien se souvenir qu'on a alloué de la mémoire avec cette fonction et penser à la libérer sinon ça fuit.
Marsh Posté le 28-02-2001 à 21:06:48
effectivement j'ai pas trop reflechi là !!!
toutes mes escuses ..
int* EnDynamique(int valeur)
{
int* ptr = (int)malloc(valeur*sizeof(int));
return ptr;
}
Le seul reproche qui est a faire ici est qu'on passe par deux pointeur. Et que dans ce cas là, on aura p etre un probleme d'adresse a remettre à jour si on agrandit la zone de memoire alouée à ptr.
bref, ct juste pour montrer que ct possible et que d'ailleur il est recommandé de faire des passages d'adresse plutot que de variable! vous confirmez ??
Marsh Posté le 28-02-2001 à 21:40:06
Je ne pensais pas provoquer un tel débat ??
J'm'aperçois qu'il y a des C(iens) avertis dans ce forum -> Tant mieux parceque pour ma part c'est le démarrage et j'ai encore du chemin à faire mais j'aime bien ça.
Le but de ma question était de savoir si je pouvais envoyer 2 vecteurs à une fct et de lui demander m'en rendre la somme ou le produit.
Dailleur cette adresse en retour, je peux l'affecter à un autre tableau directement(:ouch: ) ou pluôt lui faire pointer un int *.
Merci à vous tous pour votre aide
Marsh Posté le 28-02-2001 à 23:53:49
moi je ferais ca !
struct vecteur
{
int i,j,k;
}
vecteur somme(vecteur A, vecteur B);
vecteur produit(vecteur A,vecteur B);
void main(void)
{
vecteur A,B,C,D;
C = somme(A,B);
D = produit(A,B);
}
vecteur somme(vecteur A,vecteur B)
{
vecteur tmp;
tmp.i = A.i + B.i;
tmp.j = A.j + B.j;
tmp.k = A.k + B.K;
return tmp;
}
idem pour produit
ici pas besoin de tableau et de pointeur !!
Marsh Posté le 01-03-2001 à 00:07:17
Merci à toi grande Viper
Même pas le temps de finir de tester une fonction que m'a envoiée BifaceMcLeOD sur un autre sujet que voila une réponse à cette question (Qui + est Avé le code)
C'est vraiment le pied
Merci beaucoup
Marsh Posté le 01-03-2001 à 00:19:58
la viper a écrit :
>>>vecteur somme(vecteur A,vecteur B)
>>>{
>>> vecteur tmp;:hot:
>>> tmp.i = A.i + B.i;
>>> tmp.j = A.j + B.j;
>>> tmp.k = A.k + B.K;
>>> return tmp;:gun:
>>>}
en C, à moins de déclarer une variable static, elle est détruite à la fin du bloc où elle est déclarée, donc ici pour utiliser le résultat dans main ça risque d'être catastrophique
personnellement je passerais en paramètres les adresses des 2 tableaux à sommer + l'adresse du tableau résultat, à alouer évidemment avant l'appel
Marsh Posté le 01-03-2001 à 01:29:05
oh_damned> Oui, mais la structure est retournée, donc une copie en sera faite avant, et c'est cette copie qui sera utilisée par le main. Ce n'est pas comme si on retournait un pointeur sur cette structure locale...
Le seul inconvénient à retourner une structure, c'est que ce n'est pas d'une efficacité à toute épreuve. Mais quand on débute en programmation, c'est la dernière chose à laquelle penser !
Marsh Posté le 01-03-2001 à 10:26:06
c bien vrai... vaut mieu eviter de prendre cette habitude au depart... car une structure est tellement variable!!!
Kom je lai dit plus haut.. je prefere la soluce de damned.
Car ta fonction n'est pas sensée toucher koi ke ce soi a la memoire... au nivo alloc
Marsh Posté le 01-03-2001 à 10:53:47
Ou faire un truc du genre
int* retournetableau()
{
static int tab[5] = {0};
return tab;
}
Marsh Posté le 01-03-2001 à 11:01:13
Marsh Posté le 01-03-2001 à 20:41:08
vous vous prenez vraiment le choux les mecs !!! effectivement renvoyer une structure de hum ... 3*2 octets .. soit 6 octets au lieu d'un pointeur de 4 octets ca vaut vachement le coup !!!
parfois, il faut faire abstration de tous ces petits probleme pour aller au plus simple .. j'vous promet que meme un 286 ne vera pas la difference.
Marsh Posté le 01-03-2001 à 21:00:51
tu devrais essayer le C++ , car la surcharge d'operateur ( ici l'operateur + , * et = ) c'est super pratique. En effet dans le code c'est mieux de mettre C = A + B ou C = A * B plutot que C = somme(A,B) ou C = produit(A,B).
Marsh Posté le 01-03-2001 à 22:42:16
xilebo>
Tu pourrais me mettre un exemple, je sais pas faire
Marsh Posté le 01-03-2001 à 23:51:21
La surcharge d'opérateur, c'est très pratique, mais ça peut finir par être dangereux, car on finit par ne plus savoir ce que l'on fait.
Croyez-en mon expérience... pour avoir vu des programmeurs redéfinir les opérateurs new et delete. Là, ça commence à devenir plus intéressant d'acheter des actions dans les fabricants d'aspirine...
Marsh Posté le 01-03-2001 à 23:56:49
surtout pour une fonction qui n'a pour vocation que d'additionner deux structures de 2 entiers !!!!!!
Faut pas se prendre la tete !!!
toujours aller au plus simple et ou plus facile a coder
car :
- moins de ligne de code
- moins de bourrage de tete
et donc moins de BUG !
Marsh Posté le 02-03-2001 à 12:55:22
Allez un ch'tit exemple pour ma culture
Marsh Posté le 02-03-2001 à 14:59:26
En reprendrenant l'exemple de Viper :
vecteur operator+(vecteur const &A, vecteur const &B)
{
vecteur tmp;
tmp.i = A.i + B.i;
tmp.j = A.j + B.j;
tmp.k = A.k + B.K;
return tmp;
}
Et après tu peux directement écrire : A = B + C
où A, B et C sont trois vecteurs.
Sur des structures plus importantes (les matrices par ex) la surcharge est assez pénalisante, mais c'est tellement plus lisible ...
Marsh Posté le 02-03-2001 à 20:31:54
z51> Je me demande si operator+() ne doit pas renvoyer une référence...
Sinon, si vous voulez faire dans l'optimisé dans vos redéfinitions d'opérateurs, je vous conseille d'implémenter operator+=() d'abord, puis appeler operator+=() dans l'implémentation d'operator+(). Et pas le contraire (i.e. appeler operator+() dans l'implémentation d'operator+=()). Ainsi :
vecteur& vecteur::operator+=(vecteur const& a)
{
this->i += a.i;
this->j += a.j;
this->k += a.k;
return this;
}
vecteur& vecteur::operator+(vecteur const& a, vecteur const b)
{
vecteur result(a);
result += b;
return result;
}
Bien sûr il ne faut avoir oublié le constructeur par recopie :
vecteur::vecteur(vecteur const& a)
: i(a.i), j(a.j), k(a.k)
{
}
Avantage: operator+() ne change pas, mais operator+=() ne requiert pas de mémoire supplémentaire (=> plus optimisé).
Marsh Posté le 02-03-2001 à 21:06:32
Euh là ça va pas le faire.
Déja le premier opérateur doit retourner *this.
Ensuite le second définit un opérateur ternaire et en plus retourne une référence sur un temporaire.
Marsh Posté le 02-03-2001 à 21:13:10
C'est bon merci les gars j'ai capté
Marsh Posté le 02-03-2001 à 22:29:04
Verdoux a écrit a écrit : Euh là ça va pas le faire. Déja le premier opérateur doit retourner *this. Ensuite le second définit un opérateur ternaire et en plus retourne une référence sur un temporaire. |
Oups! J'ai oublié une étoile dans mon premier return... (preuve que j'ai tapé ce code sans même le compiler !)
Par contre, pour l'opérateur ternaire, je ne suis pas d'accord : en général, quand on écrit le proto tel que je l'ai écrit (sauf qu'il ne doit pas renvoyer pas de référence, là, je te donne raison), c'est que l'opérateur est friend ! Mais bon, on peut aussi le déclarer non-friend et ne mettre qu'un seul paramètre...
Bon, je vais quand même corriger ce code tout plein d'erreurs :
vecteur& vecteur::operator+=(vecteur const& a)
{
this->i += a.i;
this->j += a.j;
this->k += a.k;
return *this;
}
vecteur vecteur::operator+(vecteur const& a) const
{
vecteur result(*this);
result += b;
return result;
}
Marsh Posté le 02-03-2001 à 22:41:16
Oui mais si il est friend, il est en dehors de la classe. Donc il s'appelle pas vecteur::operator+ mais simplement operator+
Marsh Posté le 02-03-2001 à 22:46:54
Arrête moi si je me trompe, mais ça n'optimise en rien l'opérateur +() d'appeler +=()
Ca le ralentit même si tes fonctions ne sont pas inline.
Marsh Posté le 02-03-2001 à 23:01:49
Ouais c'est pas très optimal.
Mais pour faire des truc assez efficace, il faut pas mal réfléchir.
Un exemple de librairie optimisée:
http://www.oonumerics.org/blitz/
Ca permet d'écrire des trucs du genre:
Array<float,2> A(64,64), B(64,64); // 2 matrices 64x64
Range I(1,62), J(1,62); // on définit 2 indices avec leurs plages.
// et on peut calculer par exemple:
A(I,J) = (B(I,J) + B(I+1,J) + B(I-1,J)
+ B(I,J+1) + B(I,J-1)) / 5;
Cette dernière écriture est vraiment très proche de ce qu'on écrit mathématiquement.
Et l'évaluation est très efficace car on ne fait que 2 boucles (l'une sur I, l'autre sur J) alors que si on prend des opérateurs définis "simplement", le calcul de A+B+C+D+E est évalué en A + (B + (C + (D + E))) soit 4x2 boucles.
--Message édité par Verdoux--
Marsh Posté le 03-03-2001 à 00:20:52
Verdoux> Yep, tu as (encore) raison, le "vecteur::" était de trop !
Je sens que je vais arrêter de répondre aux questions C++, moi, ça fait trop longtemps que je n'en ai pas fait.
z51> Rien ne dit que les fonctions que j'ai écrites sont ou non sont pas inline (puisqu'il manque la définition de la classe elle-même). Mais ce qu'elles sont censées optimiser, ces fonctions, c'est la consommation mémoire (le += ne consomme rien). Et puis il n'est pas évident que l'appel de fonction que tu souhaite économiser soit vraiment pénalisant. Comme l'a souligné Verdoux au sujet des matrices, il y a d'autres "optimisations" beaucoup plus efficaces en modifiant carrément l'interface et les algorithmes.
Marsh Posté le 27-02-2001 à 21:43:38
Voir son adresse ?