Partage
  • Partager sur Facebook
  • Partager sur Twitter

Problème fonctions et conditions.

Sujet résolu
    2 mai 2019 à 16:19:50

    Bonjour, 

    Actuellement en train de coder plusieurs petits projets, je me dois d'utiliser des structures dans mes programmes : Procédures et fonctions.

    Je n'ai pas de soucis pour les procédures, je les trouve même plus simples à réaliser que les fonctions (bien qu'il y ait l'utilisation des pointeurs que beaucoup trouvent plus lourde que l'utilisation de fonctions simples).

    Bref, je n'ai pas réellement de programme concret dont je pourrai vous faire part sous la main mais j'ai remarqué que lorsque je tente de coder une fonction (classique, simple et non récursive) dans laquelle j'inclus une boucle et des conditions à l'intérieur de celle-ci, j'ai du mal à savoir quelle valeur retourner car je me retrouve avec 2 choix. 

    Y a-t'il un type de valeur particulier dont on doit se servir ? Un type booléen ? J'entends très peu parler de son utilisation en langage C. De même pour les fonctions récursives, lorsque je code comme je l'ai appris, cela ne compile pas. 

    Des conseils à m'apporter ? Je doute que ce soit simple de m'aider car je n'ai pas de programme particulier à vous faire parvenir mais j'aimerais bien savoir comment procéder dans un cas général si jamais vous avez des exemples sous la main. 

    Merci !

    -
    Edité par CircuitBreaker 2 mai 2019 à 16:20:08

    • Partager sur Facebook
    • Partager sur Twitter

    Restent ceux qui pensent qu'ils savent, bien qu'ils ne sachent pas. -Platon, Alcibiade Majeur

      2 mai 2019 à 16:46:03

      Il n'y a aucune différence entre une procédure et une fonction. C'est un terme marketing ou écolier. En C ça ne change rien ce ne sont pas des types différents.

      Je ne comprends pas trop ce que tu veux dire dans ta question. Est-ce que tu hésites quant à quoi retourner si ta fonction ne peut pas réaliser son traitement ? Quel moyen pour renvoyer une valeur (pointeur, paramètre non-const, etc) ?

      • Partager sur Facebook
      • Partager sur Twitter

      git is great because Linus did it, mercurial is better because he didn't.

        2 mai 2019 à 16:58:55

        Salut,

        La valeur de retour d'une fonction, si elle n'est pas évidente peut se redéfinir à l'usage. Selon que c'est pratique ou non.

        Si la série d'instruction qu'elle exécute peut être sujet à erreur, alors je retourne au minimum un booléen pour savoir si ça c'est bien passé.

        Parfois, même si la fonction peut être void et bosser sur un pointeur, il peut s'avérer utile de retourner le résultat calculé, par exemple pour pouvoir l’intégrer au sein d'une autre fonction en guise d'argument qui attend un type particulier.

        mettons un exemple bidon avec une fonction qui fait une multiplication par 5 , 2 options possibles :

        void parCinqPtr(int *a)
        {
           *a *= 5;
        }
        
        int parCinqRet(int *a)
        {
           *a *= 5;
           return *a;
        }

        Pour afficher le resultat au printf() tu peux alors faire :

        ...
        parCinqPtr(&maVariable);
        printf("ma variable vaut %d\n", maVariable);
        ...
        /** ou bien **/
        printf("ma variable vaut %d\n", parCinqRet(&maVariable));
        

        Si tu as besoin de la nouvelle valeur de maVariable plus tard, c'est calculé. Bon forcément, là l'exemple manque d'évidence mais parfois cela s'avère pratique.

        J'avais une fonction (void) anti-débordement qui limite une valeur dans un intervalle donné. Un jour j'ai eu besoin de savoir si la variable envoyée avait été restreinte, alors j'ai juste modifié la fonction pour qu'elle me donne cette info :

        void CEV_constraint(int mini, int* value, int maxi)
        {/*keeps value within [mini, maxi]*/
        
            if (*value < mini)    
                *value = mini;
            
            else if (*value>maxi)    
                *value = maxi;
        }
        
        //est devenue :
        
         bool CEV_constraint(int mini, int* value, int maxi)
        {/*keeps value within [mini, maxi]*/
        
            if (*value < mini)
            {
                *value = mini;
                return true;
            }
            else if (*value>maxi)
            {
                *value = maxi;
                return true;
            }
        
            return false;
        }

        Bref, c'est de l'usage, je fais généralement une fonction de base, j’essaie d'en extraire une info utile. Si je ne vois pas tout de suite, il va arriver un moment où je vais me dire que ce serait pratique que la fonction m'informe sur quelque chose.

        Pour ce qui est des procédures, il n'y en a techniquement pas en C. Une procédure est une fonction attachée à un objet, le C n'étant pas un langage objet...

        à la rigueur, on peut faire la différence entre une routine et une fonction, mais rien d'absolu et encore moins d'obligatoire. On reste généralement sur le terme de "fonction" en C.

        Bonne continuation.

        -
        Edité par drx 2 mai 2019 à 17:13:15

        • Partager sur Facebook
        • Partager sur Twitter

        Bonhomme !! | Jeu de plateforme : Prototype.

          2 mai 2019 à 17:29:22

          Bonjour markand, merci pour ta réponse !

          Effectivement, c'est un terme bien écolier, c'est comme ça qu'on les intitule à la fac nos fonctions. On définissait la procédure comme un sous-programme qui retournait 0, 1 ou plusieurs valeurs et une fonction comme un sous-programme qui retourne et calcule une seule valeur. En algo, en pseudo-langage, on faisait une petite nuance et en C aussi, mais on les différenciait bien par le fait que la procédure seulement utilisait le passage par adresse (qui utilisait l'utilisation de pointeurs) et non la fonction. Et dans la syntaxe, "void MaProcédure (paramètres entrées, sorties, ou entrées-sorties et leur type)" pour la procédure, "int MaFonction (valeurs entrées et sorties et leur type)" pour les fonctions.  

          Dans tous les cas, c'est ce que j'en ai compris en cours, mais effectivement, les 2 sont des fonctions, ça me facilite juste d'utiliser des termes différents.

          En fait, je vais donner un exemple concret de ce que je voulais dire :

          Admettons que je rédige un code qui permet de déterminer si un nombre est premier. Dans ce cas, je demande la saisie d'un nombre. Ensuite, j'utilise une boucle qui va me permettre de rechercher le nombre de diviseurs de ce nombre. Et ensuite, utiliser 2 conditions pour évaluer : Un cas de figure où mon nombre de diviseurs sera supérieur à 2, dans ce cas, le nombre n'est pas premier et un cas où le nombre de diviseur est égal à 2, dans ce cas, il est premier. Et enfin, l'affichage du résultat. 

          C'est un programme que j'ai déjà codé, jusque là, aucun souci !

          Mais quand je tente de lui ajouter une fonction pour que ces étapes ne s'exécutent que lorsque j'appelle ma fonction (les étapes de la boucle et des conditions seulement), je vais par exemple, avoir du mal à savoir quelle variable retourner étant donné les 2 cas de figure. Du coup, dans mon programme "principal", je me retrouve avec mes déclarations, la saisie du nombre, l'appel de la fonction. Et c'est le résultat qui me pose problème.

          Bonjour drx, merci également pour ta réponse !

          Cela rejoint un peu ce que j'ai dit au dessus, je ne savais pas que l'on pouvait utiliser des pointeurs dans une fonction de type int Fonction (param) ! Penses-tu que le souci puisse venir de là ? Et le cas du booléen, c'est ce que je dois utiliser dans l'exemple ci-dessus par exemple (enfin du moins j'y ai songé), mais j'ai ce même cas dans pleins d'autres programmes où ma fonction doit retourner quelque chose en fonction de l'évaluation d'une condition.

          Je vais tout de même tenter quelque chose avec ça et je vous ferai part du retour, merci pour votre aide !

          -
          Edité par CircuitBreaker 2 mai 2019 à 17:42:34

          • Partager sur Facebook
          • Partager sur Twitter

          Restent ceux qui pensent qu'ils savent, bien qu'ils ne sachent pas. -Platon, Alcibiade Majeur

            2 mai 2019 à 17:52:19

            Salut,

            Il n'y a aucun lien entre le type d'une fonction et les arguments qu'elle peut prendre. Il faut bien comprendre que le type d'une fonction fait de celle-ci une variable (ou pas) du même type avec toutes les propriétés dudit type, hors affectation.

            Si j'ai une structure toto :

            struct toto
            {
              int a,b;
              char* text;
            }

            alors, le type struct toto peut aussi bien être attribué à une variable qu'être issu d'une fonction de type struct toto. Pour rester sur un printf :

            struct toto fonction(void)
            {
              
                return (struct toto){.a = 20, .b = 1, .text = "Coucou"};
            }
            
            ...
            struct toto var= {.a = 10, .b = 5, .text = "Salut"};
            
            printf("texte de var est %s\n", var.text);
            printf("texte de fonction est %s\n", fonction().text);
            
            

            Si une fonction doit retourner plusieurs résultat, alors soit on passe un pointeur pour chaque résultat, soit on passe une structure d'instance.

            Le mieux reste de nous présenter du code...


            • Partager sur Facebook
            • Partager sur Twitter

            Bonhomme !! | Jeu de plateforme : Prototype.

              2 mai 2019 à 18:09:36

              Sans la fonction, ma portion de code donnerait ceci (Pardonnez moi d'avance si j'utilise mal la fonction d'insertion du code, c'est une première pour moi) :

                  int n; /** Entier saisi */
                  int k; /** Nombre de diviseurs */
                  int i; /** Diviseurs*/
              
                  printf("Saisir un entier\n");
                  scanf("%d", &n);
              
                  for (i=1; i<=n; i++)
                  {
                      if ((n % i == 0))
                      {
                          k = k+1;
                      }
                  }
              
                  if (k > 2)
                  {
                      printf("Ce nombre n est pas premier");
              
                  }
              
                  if (k == 2)
                  {
                      printf("Ce nombre est premier");
                  }

              C'est donc l'affichage et le retour de la valeur qui me posent souci, lorsque je devrai utiliser une fonction.

              -
              Edité par CircuitBreaker 2 mai 2019 à 18:13:03

              • Partager sur Facebook
              • Partager sur Twitter

              Restent ceux qui pensent qu'ils savent, bien qu'ils ne sachent pas. -Platon, Alcibiade Majeur

                2 mai 2019 à 18:30:48

                Salut,

                Dans l'ordre, il faut en premier écrire un truc qui fait le boulot correctement. J'entends par là que ça doit rendre le résultat attendu, que le code soit crado et mal optimisé n'entre pas en compte.

                Ici avec un k qui n'est pas initialisé, peu de chances que ça arrive.

                Ensuite seulement, on nettoie, on factorise et on optimise en évitant l'obfuscation.

                Il suffit là de mettre ta boucle dans une fonction et que celle-ci te retourne soit k soit un booléen vrai pour nombre premier, je ne vois pas trop le souci.

                bool estPremier(int valeur)
                {
                  int k = 0;
                  
                  for (int i=1; i<=valeur; i++)
                  {
                    if (!(valeur % i))
                    {
                        k++;
                    }
                  }
                
                  return (k == 2);
                }
                
                ....
                
                printf("Ce nombre %s premier\n",estPremier(n)?"est":"n'est pas");


                Bonne continuation.

                -
                Edité par drx 2 mai 2019 à 18:31:43

                • Partager sur Facebook
                • Partager sur Twitter

                Bonhomme !! | Jeu de plateforme : Prototype.

                  2 mai 2019 à 18:39:54

                  Effectivement, k n'était pas initialisé dans cette portion de code que j'ai modifié mainte fois, merci pour la remarque ! Je pense que le souci venait en partie du fait que je n'étais pas sûre qu'on pouvait déclarer une fonction de type booléen et probablement dans la syntaxe du return ! 

                  En fait, j'imaginais que ma fonction renvoie True si c'est premier et False si ça ne l'est pas. En gros un truc style si ma condition (k ==2) est exécutée, ça renvoie vrai et si c'est (k>2), ça renvoie faux. Mais je ne sais pas si cela est possible rédigé tel quel.

                  Merci à vous !

                  -
                  Edité par CircuitBreaker 2 mai 2019 à 19:03:02

                  • Partager sur Facebook
                  • Partager sur Twitter

                  Restent ceux qui pensent qu'ils savent, bien qu'ils ne sachent pas. -Platon, Alcibiade Majeur

                    3 mai 2019 à 14:06:28

                    markand a écrit:

                    Il n'y a aucune différence entre une procédure et une fonction. C'est un terme marketing ou écolier. En C ça ne change rien ce ne sont pas des types différents.


                    A mon avis, ça vient plutôt du langage PASCAL, qu'on apprenait avant le C dans le temps, ou il y avait effectivement une différence entre une procédure et une fonction (si elle renvoyait quelque chose ou non) les deux mots clé procedure et function étaient réservés.

                    Et même le "main" était encore un cas à part : c'était un bloc begin/end  (comme {}en C) sans rien au dessus...

                    En C, il n'y a plus cette différenciation. Une fonction renvoie une valeur ou ne renvoie rien (void).

                    Maintenant, le langage PASCAL est tombé un peu dans les oubliettes, mais je pense que ça vient de la.

                    -
                    Edité par Fvirtman 3 mai 2019 à 14:08:56

                    • Partager sur Facebook
                    • Partager sur Twitter

                    Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                      4 mai 2019 à 13:31:42

                      La phrase « on les différenciait bien par le fait que la procédure seulement utilisait le passage par adresse » me fait plutôt penser au Fortran : dans une subroutine Fortran, si on modifie les arguments, ils sont modifiés dans le programme principal (du coup, pas besoin de pointeur pour faire un « swap » par exemple).

                      Bref, c'est vieux...

                      Dans un programme calculant si un nombre premier, on pourrait avoir besoin de deux fonctions :

                      − une fonction qui retourne le nombre de diviseurs d'un entier naturel : cette fonction retourne un entier naturel, elle est donc de type 'int' (ou 'unsigned int' pour chipoter) ;

                      − une fonction qui détermine si un nombre est premier : cette fonction retourne vrai ou faux, elle est donc de type 'bool' (type défini dans <stdbool.h> depuis le C99).

                      Il est probable que la deuxième fonction utilise la première.

                      -
                      Edité par robun 4 mai 2019 à 13:31:54

                      • Partager sur Facebook
                      • Partager sur Twitter
                        4 mai 2019 à 19:58:01

                        CircuitBreaker a écrit:

                        Admettons que je rédige un code qui permet de déterminer si un nombre est premier. Dans ce cas, je demande la saisie d'un nombre. Ensuite, j'utilise une boucle qui va me permettre de rechercher le nombre de diviseurs de ce nombre. Et ensuite, utiliser 2 conditions pour évaluer : Un cas de figure où mon nombre de diviseurs sera supérieur à 2, dans ce cas, le nombre n'est pas premier et un cas où le nombre de diviseur est égal à 2, dans ce cas, il est premier. Et enfin, l'affichage du résultat. 

                        Bonjour,

                        Pour un tel programme, voici un exemple de découpage en fonctions:

                        int nbDiviseurs(int);
                        bool estPremier(int);
                        int saisirNombre(void);
                        
                        
                        bool estPremier(int n)
                        {
                            return nbDiviseurs(n) == 2;
                        }
                        
                        
                        int main(void)
                        {
                           int nombre = saisirNombre();
                        
                           if (estPremier(nombre))
                              printf("%d est premier.\n", nombre);
                           else
                              printf("%d n'est pas premier.\n", nombre);
                        
                           return 0;
                        }
                        

                        NB: Dans l'énoncé tu as oublié le cas où un nombre a moins de 2 diviseurs. Un tel nombre n'est pas premier.


                        • Partager sur Facebook
                        • Partager sur Twitter
                          4 mai 2019 à 20:18:44

                          robun a écrit:

                          La phrase « on les différenciait bien par le fait que la procédure seulement utilisait le passage par adresse » me fait plutôt penser au Fortran : dans une subroutine Fortran, si on modifie les arguments, ils sont modifiés dans le programme principal (du coup, pas besoin de pointeur pour faire un « swap » par exemple).

                          Bref, c'est vieux...

                          Dans un programme calculant si un nombre premier, on pourrait avoir besoin de deux fonctions :

                          − une fonction qui retourne le nombre de diviseurs d'un entier naturel : cette fonction retourne un entier naturel, elle est donc de type 'int' (ou 'unsigned int' pour chipoter) ;

                          − une fonction qui détermine si un nombre est premier : cette fonction retourne vrai ou faux, elle est donc de type 'bool' (type défini dans <stdbool.h> depuis le C99).

                          Il est probable que la deuxième fonction utilise la première.

                          -
                          Edité par robun il y a environ 6 heures


                          Fortran: c'est comme si c'était hier :-)

                          Dans la première version (fin années 50) les programmes étaient monolithiques. On pouvait seulement définir des "fonctions implicites" dans les premières lignes par des équations du genre

                                    D(X,Y) = SQRT(X**2 + Y**2)

                          Ensuite est apparu (Fortran II ?) la notion d'unité de compilation - pour pouvoir faire des bibliothèques réutilisables  au lieu de "copier coller" les cartes perforées des autres programmes -, qui chapeautait  le programme principal (PROGRAM), les fonctions (FUNCTION) et les sous programmes (SUBROUTINE).

                          La différence est très nette

                          • un appel de fonction fournit une valeur, genre   Z = D(X1,Y1) + D(X2,Y2)
                          • une sous-programme est appelé par CALL :    CALL SCHTROUMFER(TRUC,MACHIN)

                          Les variables étaient passées par référence, ce qui posait parfois quelques problèmes aux programmeurs distraits qui passaient des constantes dans des paramètres modifiés...

                          Dans Algol, il y avait des PROCEDUREs, qui pouvaient optionnellement retourner quelque chose ou pas, ce qui en fait l'analogue entre void/autre chose comme type de retour. Pas de mot clé "call" pour l'appel.

                          Pascal reprend la distinction explicite  FUNCTION/PROCEDURE pour les appels.

                          C fait presque comme Algol, avec "void" introduit (tardivement) pour les trucs qui ne retournent rien (implicitement, ça retournait un entier).

                          * c'est une mauvaise idée de calculer le nombre de diviseurs pour savoir si un nombre est premier. Il suffit de savoir qu'il y a un qui ne soit pas 1 ni le nombre.

                          -
                          Edité par michelbillaud 4 mai 2019 à 20:22:09

                          • Partager sur Facebook
                          • Partager sur Twitter
                            4 mai 2019 à 20:20:20

                            Salut,

                            Par curiosité, dans quel cas un nombre entier pourrait-il avoir moins de 2 diviseurs ? Je pensais que tout nombre (entier) possède au moins 2 diviseurs : 1 et lui-même.

                            Existe-t-il un cas particulier dans N ?

                            -
                            Edité par drx 4 mai 2019 à 20:20:56

                            • Partager sur Facebook
                            • Partager sur Twitter

                            Bonhomme !! | Jeu de plateforme : Prototype.

                              4 mai 2019 à 22:13:29

                              drx a écrit:

                              Salut,

                              Par curiosité, dans quel cas un nombre entier pourrait-il avoir moins de 2 diviseurs ? Je pensais que tout nombre (entier) possède au moins 2 diviseurs : 1 et lui-même.

                              Existe-t-il un cas particulier dans N ?

                              -
                              Edité par drx il y a environ 1 heure


                              Bonne question. Le nombre 1 peut être ?
                              • Partager sur Facebook
                              • Partager sur Twitter

                              Recueil de code C et C++  http://fvirtman.free.fr/recueil/index.html

                                4 mai 2019 à 22:34:23

                                michelbillaud a écrit:

                                * c'est une mauvaise idée de calculer le nombre de diviseurs pour savoir si un nombre est premier. Il suffit de savoir qu'il y a un qui ne soit pas 1 ni le nombre.

                                C'était une idée pour illustrer le genre de fonctions qu'on pourrait mettre dans le programme, mais en effet ce n'est pas efficace du tout.

                                (Oui, 1 n'a qu'un seul diviseur et n'est pas un nombre premier.)

                                -
                                Edité par robun 4 mai 2019 à 22:38:24

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  4 mai 2019 à 23:04:52

                                  1 n'est pas un nombre premier il me semble... ça doit commencer à 2. ... Je confirme après vérification.

                                  Au passage je corrige une ânerie :

                                  drx a écrit:

                                  [...]tout nombre (entier) possède au moins 2 diviseurs : 1 et lui-même.[...]


                                  Ce n'est pas  "au moins" mais "seulement".
                                  • Partager sur Facebook
                                  • Partager sur Twitter

                                  Bonhomme !! | Jeu de plateforme : Prototype.

                                    4 mai 2019 à 23:29:12

                                    Ben non, c'est tout nombre _premier_ possède exactement deux diviseurs entiers (positifs distincts).

                                    Pourquoi 1 n'est pas premier

                                    • parce que la définition dit qu'un nombre n > 1 est premier si et seulement etc.
                                    • parce que 1 figurerait dans une décomposition en facteurs premiers
                                    • pour d'autres raisons techniques

                                    https://primes.utm.edu/notes/faq/one.html

                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      5 mai 2019 à 12:52:24

                                      drx a écrit:

                                      drx a écrit:

                                      [...]tout nombre (entier) possède au moins 2 diviseurs : 1 et lui-même.[...]


                                      Ce n'est pas  "au moins" mais "seulement".

                                      Non, c'est bien « au moins ». (Quand tu as écrit cette phrase tu parlais de nombres entiers, pas de nombres premiers.) À part 1.

                                      ------

                                      Concernant le fait que 1 n'est pas classé parmi les nombres premiers, je vois quatre raisons :

                                      1) On ne gagne rien à considérer que 1 est premier.

                                      2) La raison principale : si 1 était premier, la décomposition en facteurs premiers ne serait plus unique. C'est l'unicité de cette décomposition qui fait des nombres premiers une sorte de base des nombres entiers.

                                      3) Les théorèmes sur les nombres premiers, au lieu de commencer par « tout nombre premier » ou « soit p un nombre premier » devraient commencer par « tout nombre premier autre que 1 » ou « soit p un nombre premier différent de 1 » (et c'est ce qu'il faudrait faire dans le 2) : parler d'une décomposition en « nombres premiers autres que 1 »).

                                      4) La définition actuelle est simple : un nombre premier a exactement deux diviseurs. Si 1 était considéré comme premier, il faudrait dire : un nombre premier a soit un diviseur, soit deux diviseurs. C'est plus compliqué.

                                      -
                                      Edité par robun 5 mai 2019 à 12:59:48

                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                        5 mai 2019 à 14:44:29

                                        Ben non, le nombre 1 a un seul diviseur entier positif.

                                        > Quatre raisons

                                        Ne mélangeons pas tout :

                                        • La raison fondamentale pour dire que 1 n'est pas premier, c'est la définition "nombre premier : entier naturel qui admet exactement deux diviseurs distincts entiers et positifs.  D'après cette définition, l'entier 1 n'est pas premier, circulez y a rien à voir.
                                        • le choix de ce concept (avoir deux diviseurs entiers positifs distincts) comme élément pertinent pour raconter des trucs sur les propriétés des nombres entiers.
                                        • si on avait plein de choses intéressantes à dire sur les nombres qui ont la propriété d'avoir 2 diviseurs entiers positifs distincts *ou pas*, il y aurait un mot pour ça. Mais pas "premier", c'est déjà pris.

                                        Spoiler : la semaine prochaine notre épisode "0 est-il pair", suivi par '0,9999... est-il vraiment égal à 1 ?". La Réponse que l'On Veut Vous Cacher Va Vous Surprendre.

                                        -
                                        Edité par michelbillaud 5 mai 2019 à 15:49:05

                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          5 mai 2019 à 19:06:50

                                          Je parlais du choix du concept.
                                          • Partager sur Facebook
                                          • Partager sur Twitter

                                          Problème fonctions et conditions.

                                          × 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