Partage
  • Partager sur Facebook
  • Partager sur Twitter

Pointeurs sur fonction... aïe

    14 février 2019 à 20:07:02

    Bonsoir tout le monde,

    j'ai conscience qu'il y a déjà topic sur les pointeurs sur fonction mais je ne trouve pas les réponses à mes questions. (trop de level chez les autres) 

    J'ai vraiment du mal à comprendre la façon dont cela fonctionne. 

    voilà mon code. 

    ///////////////////////Liste de fonction appele dans le programme ////////////////////
    double
    saisi()
    {
            //fonction saisi des nombres √ †traiter.
            double          x = 0;
            printf("saisi nombre à traiter\n>> ");
            scanf("%lf", &x);
            return x;
    }
    ///////////////////////////////////////////////////////////////////////////////
    double
    addition(double x, double y)
    {
            return x + y;
    }
    double
    soustraction(double x, double y)
    {
            return x - y;
    }
    double
    multiplication(double x, double y)
    {
            return x * y;
    }
    double
    division(double x, double y)
    {
            return x / y;
    }
    ///////////////////////////////////
    double fonction(double x)
    {
            //Menu et calcul d 'une fonction choisit
            int             f = 0;
            //variable permettant de choisir une fonction a calculer
                    double          r;
    
            printf(" f(x)= \n1. x        2. x²       3. x³ ");
            printf("\n\n4. cos(x)   5. sin(x)   6. tan(x)");
            printf("\n\n7. 1/x      8. ln(x)    9. exp(x)\n>>");
            scanf("%d", &f);
            //saisi de l 'operation a effectuer
    
                    switch (f) {
            case 1:
                    r = x;
                    break;
            case 2:
                    r = pow(x, 2);
                    break;
            case 3:
                    r = pow(x, 3);
                    break;
            case 4:
                    r = cos(x);
                    break;
            case 5:
                    r = sin(x);
                    break;
            case 6:
                    r = tan(x);
                    break;
            case 7:
                    r = 1 / x;
                    break;
            case 8:
                    r = log(x);
                    break;
            case 9:
                    r = exp(x);
                    break;
            }
            return r;
    }
    
    
    //////////////////////////////////////////////////////////////////////////////////
    double f(double x) //fonction en cours, la fonction f est appele dans la fonction integral
    {
            ptr_fct = fonction;
            return ptr_fct;
    }
    
    /////////////Calcul integral //////////////////////////////////////////////////
    
    double integral(double a, double b, int n, double ptr_fct)
    {
            int             i = 0;
            double          s = 0, s1 = 0, s2 = 0, dx = 0, d2 = 0;
            double          x = 0;
    
    
            x = a - dx;
            dx = (b - a) / n;
            s = f(a) + f(b);
            d2 = 2 * dx;
            s1 = 0;
    
            for (i = 1; i <= n - 1; i = i + 2) {
                    x = x + d2;
                    s1 = s1 + f(x);
                    //printf("%lf\n", s1);
            }
            x = a;
            s2 = 0;
    
            for (i = 2; i <= n - 2; i = i + 2) {
                    x = x + d2;
                    s2 = s2 + f(x);
                    //printf("%lf\n", s2);
            }
            s = dx * (s + 4 * s1 + 2 * s2) / 3;
            return s;
    }
    
    //////////////////////////////////////////////////////////////////
    //Programme principal ///////////////////////////////
    ///////////////////////////////////
    int
    main()
    {
            int             op = 0, validation = 1, test = 0, n = 0;
            //op est la variable pour le choix de l 'operation, validation sert de condition pour refaire un calcul ou non.
            double          nb1 = 0, nb2 = 0, result = 0, a = 0, b = 0;
            /*double (ptr_fct) (double);*/
             double (*pt_fonction)(double);
            while (validation == 1) {
    
                    printf(" opération à effecuter\n1. + \n2. - \n3. x \n4. / \n5.Calcul d'une fonction \n6.Calcul integral \n>> ");
                    scanf("%d", &op);
                    //saisi de l 'operation a effectuer
    
                            if (0 < op && op < 7) {
                            //il faut que la valeur de op soit comprise entre 1 et 6 pour effectuer une operation.
                                    validation = 0;
                            switch (op) {
                            case 1:
                                    result = addition(nb1 = saisi(), nb2 = saisi());
                                    break;
                            case 2:
                                    result = soustraction(nb1 = saisi(), nb2 = saisi());
                                    break;
                            case 3:
                                    result = multiplication(nb1 = saisi(), nb2 = saisi());
                                    break;
                            case 4:
                                    result = division(nb1 = saisi(), nb2 = saisi());
                                    break;
                            case 5:
                                    result = fonction(nb1 = saisi());
                                    break;
                            case 6:
                                    while (test == 0) {
                                            printf("saisir la borne inferieure\n>> ");
                                            scanf("%lf", &a);
                                            printf("saisir la borne superieure\n>> ");
                                            scanf("%lf", &b);
                                            printf("saisir le pas\n>> ");
                                            scanf("%d", &n);
                                            if (a > b) {
                                                    printf("veuillez saisir a plus petit que b\n\n");
                                            } else {
                                                    test = 1;
                                            }
                                    }
                                    test = 0;
                                    result = integral(a, b, n, *pt_fonction);
                                    break;
                            }
    
                            printf("=%lf\n\n", result);
                            //affichage du resultat
                    } else {
                            printf("entrez une valeur valide\n");
                            //message d 'erreur
                    }
                    printf("tapez 1 pour effectuer un calcul\ntapez 0 pour quitter\n");
                    scanf("%d", &validation);
            }
    
            return 0;
    }
    


    Comme vous le voyez c'est une calculatrice permettant de faire les opérations de base mais aussi le calcul de fonction ainsi que d'intégrale. 

    Je voudrais être capable de créer un pointeur sur fonction pour calculer l'integral de la fonction choisie dans le sous menu "fonction". 

    La fonction integral prendrait alors 4 paramètres : les bornes a et b, les pas n et le pointeur sur fonction (permettant de savoir quelle fonction intégrer. 

    mes questions : -où déclarer le pointeur ?  

                          -le pointeur peut il pointer sur la valeur renvoyer la la fonction "fonction" ? 

    • Partager sur Facebook
    • Partager sur Twitter
      14 février 2019 à 21:01:25

      Bonjour,

      Commençons par ta fonction fonction, elle devrait retourner un pointeur de fonction (la toute première ligne est très complexe mais peut s'écrire en 2 lignes pour être beaucoup plus lisible.)

      double (*fonction(void))(double) { // fonction sans paramètre retournant un pointeur sur une fonction recevant un double et retournant un double
         // Menu et calcul d 'une fonction choisie
         int      f = 0;
         // variable permettant de choisir une fonction a calculer
         double (*r)(double);      // un pointeur sur un fonction recevant un double et retournant un double
         printf(" f(x)= \n1. x        2. x²       3. x³ ");
         printf("\n\n4. cos(x)   5. sin(x)   6. tan(x)");
         printf("\n\n7. 1/x      8. ln(x)    9. exp(x)\n>>");
         scanf("%d", &f);
         // saisie de l'operation a effectuer
       
         switch ( f ) {
            case 1:
               r = &idem;  // un pointeur s'initialise toujours à partir d'une adresse (ici adresse d'une fonction)
            break;
            case 2:
               r = &pow2;
            break;
            case 3:
               r = &pow3;
            break;
            case 4:
               r = &cos;
            break;
            case 5:
               r = &sin;
            break;
            case 6:
               r = &tan;
            break;
            case 7:
               r = &inverse;
            break;
            case 8:
               r = &log;
            break;
            case 9:
               r = &exp;
            break;
         }
         return r;
      }

      Il a fallu créer des fonctions (en prenant leur adresse on a un pointeur de fonction), toutes reçoivent un double et retournent un double. Elle doivent être placées avant la fonction fonction.

      double idem( double x ) {
         return  x;
      }
      double inverse( double x ) {
         return  1. / x;
      }
      double pow2( double x ) {
         return  x * x;
      }
      double pow3( double x ) {
         return  x * x * x;
      }

      La fonction integrale doit recevoir en dernier paramètre un pointeur sur une fonction, on appelle f ce pointeur

      double integrale( double a, double b, int n, double (*f)(double) ) {
       ... ... ... // ici f est une fonction utilisable
      }

      Et dans le main on doit remplacer la ligne 82 par :

      double (*ptrfct)(double) = fonction();  // demander un pointeur mémorisé dans ptrfct
      result = integrale( a, b, n, ptrfct );  // transmettre ce pointeur à integrale




      • Partager sur Facebook
      • Partager sur Twitter

      En recherche d'emploi.

        14 février 2019 à 21:31:51

        super ! merci, je vais partir la dessus. 

        Donc le pointeur s'initialise dans le main. 

        Et si je comprend bien, il a fallu 2 pointeurs, 1 pour pointer la fonction désiré, et le second pour passer cette fonction en paramètre du calcul integral ? 

        • Partager sur Facebook
        • Partager sur Twitter
          14 février 2019 à 22:21:20

          Il n'y a qu'un pointeur (qui pointe sur la fonction à utiliser), on écrire la ligne 82 en une seule ligne 
          result = integrale( a, b, n, fonction() );  // appeler fonction et transmettre ce qu'elle retourne

          Mais cette notation est un peu trop difficile à lire, et peut être trompeuse. Exemple, ta ligne 

             result = soustraction(nb1 = saisi(), nb2 = saisi()); // rien ne garanti le chargement des paramètres de gauche à droite
          

          On a l'impression que la première valeur demandée sera nb1 et la seconde nb2, mais rien ne garantit que ça ne sera pas l'inverse! Il faut écrire :

             nb1 = saisi();
             nb2 = saisi(); // on est sûr de demander nb2 après nb1
             result = soustraction( nb1, nb2 );
          




          • Partager sur Facebook
          • Partager sur Twitter

          En recherche d'emploi.

            17 février 2019 à 12:24:18

            Faisons simple et logique :ça marche exactement(*) comme des pointeurs d'autre chose

            1. si tu avais des (par exemple) entiers a,.... pour avoir un pointeur p qui pointe sur a tu ferais :  p = & a.

            Pareil si tu as des fonctions  somme, produit, ....
            et que tu veux un pointeur ptr qui pointe sur une de ces fonctions, pour qu'il pointe sur somme, tu peux faire :

            ptr = & somme;

            2. maintenant si tu veux accéder à la valeur désignée par p, tu l'appelles *p.

            Pareil pour les fonctions. Avec somme tu ferais

            double toto = somme(1.2, 3.4);
            

            alors avec ptr, tu fais

            double toto = (*ptr) (2.3, 3.4);
            


            3. Et comme en C la déclaration se conforme à l'usage; puisque tu as

            double somme  (double a, double b);
            

            ptr se déclare en remplaçant   somme par *ptr

            double (*ptr) (double a, double b);
            

            Voila les bases.

            (*) Ensuite, il se trouve que le standard autorise des simplifications dans l'usage, pour les variables qui sont reconnues comme des pointeurs de fonctions. On peut omettre l'étoile

            ptr = somme;
            double toto = ptr(3.4, 5.6);
            

            Et enfin, quand on a des pointeurs de fonctions, il est de bon gout d'user du typedef pour ne pas se retrouver avec des déclarations à rallonge

            typedef double (*OperationBinaire)(double, double);
            


            ---------------

            Pour reprendre quelque chose qui ressemble à ton exemple, mais sans faire ton exercice, imaginons qu'on veuille calculer f(1)+f(2) +.... f(n), pour une fonction f et un entier n donnés.

            #include <stdio.h>
            
            typedef float (*FonctionUnaire)(int);
            
            float somme(FonctionUnaire f, int n) {
              float s = 0;
              for (int i = 1; i <= n; i++) {
                s += f(i);
              }
              return s;
            }
            
            float inverse_carre(int n) {
              return 1.0 / (n*n);
            }
            
            int main()
            {
              printf("-> 1/1 + 1/4 + 1/9 = %f\n", somme(inverse_carre, 3));
              return 0;
            }
            







            -
            Edité par michelbillaud 17 février 2019 à 12:46:10

            • Partager sur Facebook
            • Partager sur Twitter

            Pointeurs sur fonction... aïe

            × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
            × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
            • Editeur
            • Markdown