Annonce

Réduire
Aucune annonce.

Cours langage C n°8 - Fonctions et prototypes

Réduire
Ceci est une discussion importante.
X
X
 
  • Filtre
  • Heure
  • Afficher
Tout nettoyer
nouveaux messages

  • Cours langage C n°8 - Fonctions et prototypes

    Fonctions et prototypes

    Fonctions ? What ?

    Les fonctions sont les étapes à la résolution d'un problème. Quand un problème devient difficile il est bon de découper en plusieurs étapes sa résolution, afin d'éviter les erreurs fréquentes.

    Imaginons que l'on veuille faire un pendu...

    Pour simplifier on va imaginer que le mot mystère à découvrir est déjà généré, ce qui évite ça recherche dans un fichier ou autres.

    Plusieurs étapes découlent de cette problématique:
    1. Générer le mot caché composé des caractères '*'
    2. Trouver le caractère proposé par l'utilisateur et le remplacer le caractère '*' par la lettre si trouvé, sinon rien
    3. Vérifier que le mot mystère est équivalent au mot caché, si oui c'est gagné, sinon on continue à deviner



    Vous le voyez ci-dessus, si vous êtes observateur, ces étapes sont représentées par des verbes, ça sera la même chose en programmation et si possible en anglais

    Voici une proposition de fonctions pour chacune des ces étapes:
    1. generate
    2. replace
    3. check


    Donc garder cela en tête, une fonction est une étape à la résolution d'un problème, elle est représentée par un verbe anglais.

    Vous utilisez depuis le début du cours une fonction, elle se nomme main

    Code:
    int main(void)
    {
        /* code */
    
        return 0;
    }
    main est la fonction principale de votre programme C.

    Le prototype? what ?

    Le prototype, c'est le plan d'une fonction, elle se représente en une seule ligne et se termine par un point virgule... On retrouve les prototypes dans les documentations du langage C, on en a besoin pour savoir plusieurs choses
    • Valeur/Adresse que retourne cette fonction
    • Paramètres que prend cette fonction pour être fonctionnelle


    Souvenez-vous de la fonction puts, son prototype est le suivant

    Code:
    int puts ( const char * str );
    On va détailler la ligne ci-dessus...

    prototype.gif

    Le type de retour de la fonction:

    Dans notre exemple, le type de retour est int, ce qui veut dire que cette fonction retourne (et non affiche) un entier. Retourner en informatique, est équivalent à dire valeur/adresse à enregistrer dans une variable.

    Euh oui, mais puts, on enregistrait pas sa valeur de retour dans une variable, c'est mal non? Oui c'est très mal d'ignorer la valeur de retour d'une fonction, elle retourne un état indiquant si la fonction s'est bien ou mal passée.

    Ce que dis la documentation, est explicite

    On success, a non-negative value is returned.
    On error, the function returns EOF and sets the error indicator (ferror).


    En cas de succès, une valeur positive est retournée.
    En cas d'erreur, le retour renvoie EOF et on peut utiliser ferror, pour en savoir plus sur l'erreur (ne faites pas attention à ferror pour l'instant).

    Ok, Fred, c'est pas que je te crois pas, mais j'aimerais vérifier cela par le code... Okok, faisons ça !

    Code:
    #include <stdio.h>
    
    int main(void)
    {
        char result[] = "Bonjour";
        int ret; /* valeur de retour de la fonction */
    
        ret = puts(result); /* affichage du tableau de caractères result */
    
        printf("La fonction s'est bien passée ? resultat : %d\n", ret); /* valeur positive, donc oui ça s'est bien passé */
    
        return 0;
    }
    Notre retour de fonction est bien enregistré dans une variable ret de type entier (int).

    Le/Les paramètre(s) de fonction:

    Ok, ça roule, mais je comprend pas, la fonction puts prend en paramètre l'adresse d'un caractère, bah oui char *... Vous avez raison, modifions...

    Code:
    #include <stdio.h>
    
    int main(void)
    {
        char result[] = "Bonjour";
        int ret; /* valeur de retour de la fonction */
    
        ret = puts(&result[0]); /* affichage du tableau de caractères result */
    
        printf("La fonction s'est bien passée ? resultat : %d\n", ret); /* valeur positive, donc oui ça s'est bien passé */
    
        return 0;
    }
    Mais comme vous le savez en C, on simplifie pour éviter ce type de notation, on préférera mettre result, plutôt que &result[0], mais sachez que la notation est identique, ça à déjà été expliqué dans le cours sur les pointeurs

    Arf, oui mais? Quoi encore ? Eh bien la fonction prend en paramètre un type const char * ... const c'est juste pour indiquer que l'on prend un type constant, qui ne sera donc pas modifiable... On peut préciser const lors de la déclaration de la fonction result.

    En effet puts permet d'afficher du texte, pas besoin d'avoir un type modifiable pour notre variable en paramètre de fonction.

    Code:
    #include <stdio.h>
    
    int main(void)
    {
        const char result[] = "Bonjour";
        int ret; /* valeur de retour de la fonction */
    
        ret = puts(result); /* affichage du tableau de caractères result */
    
        printf("La fonction s'est bien passée ? resultat : %d\n", ret); /* valeur positive, donc oui ça s'est bien passé */
    
        return 0;
    }
    Eh bien voilà notre fonction respecte à la lettre le prototype de cette fonction, content ?

    Le type de retour void

    Il arrive que vous n'ayez pas besoin d'enregistrer dans une variable le retour d'une fonction (exemple affichage simple d'un entier), dans ce cas, nous utiliserons le mot clé void, il indiquera que la fonction ne retourne rien !

    Exemple

    Code:
    void display(const char chaine[])
    {
        int ret; /* valeur de retour puts */
    
        if ((ret = puts(chaine)) == EOF)
        {
            puts("Erreur"); /* Afficher Erreur */
            exit(-1); /* Sortir du programme avec code -1 */
        }
    
    }
    Dans un code complet, il faudra donner le prototype de la fonction (oui car c'est une fonction inventée par nous, il faut expliquer comment ça fonctionne).

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    void display(const char chaine[]);
    
    int main(void)
    {
        const char result[] = "Bonjour";
    
        display(result); /* Affiche Bonjour */
    
        return 0;
    }
    
    void display(const char chaine[])
    {
        int ret; /* valeur de retour puts */
    
        if ((ret = puts(chaine)) == EOF) /* Si ret vaut EOF */
        {
            puts("Erreur"); /* Afficher Erreur */
            exit(-1); /* Sortir du programme avec code -1 */
        }
    
    }
    On remarquera:
    • La déclaration de notre prototype en début de code (simplement un copier/coller avec un point virgule à la fin de la ligne)
    • La fonction display est après la fonction main


    On a apprit pas mal de choses là, oufff...

    Fonction sans paramètre

    Une fonction sans paramètre sera indiqué par le mot clé void, exemple, ce que vous utilisez couramment

    Code:
    int main(void)
    {
        /* code */
    
        return 0;
    }
    on voit que la fonction main comprend le mot clé void, qui veut dire qu'on précise que cette fonction attend aucun paramètre...

    Exemple:

    Code:
    void displayHello(void)
    {
        puts("Hello World !");
    }
    Pas de valeur de retour, pas de paramètre, son simple but est d'afficher "Hello World !"

    EXERCICES

    Ça va se compliquer, nous allons mélanger ce qu'on a appris (boucle, pointeurs et fonctions), ça demandera sans doute lectures, relectures, refaire les exercices précédents, ...

    Exercice n°1:

    Compléter le code suivant permettant de transformer la chaine "bonjour" par "*******".

    Code:
    #include <stdio.h>
    
    void generate(const char chaine[], char *str); /* prototype de la fonction à construire */
    
    int main(void)
    {
        const char ch[] = "bonjour";
        char chaineCache[8];
    
        generate(ch, chaineCache);
    
        puts(chaineCache); /* Affichage de "*******" sur la console */
    
        return 0;
    }
    
    void generate(const char chaine[], char *str)
    {
        /* À compléter */
    
        /* ne pas oublier le caractère de fin de chaîne '\0' */
    }
    exo1-fonctions1.jpg

    Exercice n°2:

    Compléter le code suivant où l'on souhaite une fonction retournant le double de la valeur en paramètre.

    Code:
    #include <stdio.h>
    
    /* prototype à compléter */
    
    int main(void)
    {
        int value = 18;
        int result; /* variable enregistrant le résultat de la fonction foisDeux */
        
        /* Utilisation de la fonction foisDeux à compléter */
        
        printf("Le double de %d est %d\n", value, result); /* Le double de 18 est 36 */
    
        return 0;
    }
    
    /* fonction à créer */
    La fonction sera nommée foisDeux, prendra en paramètre un entier et retournera un entier

    Merci de m'avoir lu et à bientôt pour le prochain cours
    Dernière modification par fred, 05 juillet 2014, 19h35.

  • #2
    Question :

    1)Pourquoi dans certains de tes codes tu a :
    #include <stdio.h>
    alors que dans d'autres tu a
    #include <stdio.h>
    #include <stdlib.h>
    J'aimerais que tu m'explique ce procédé s'il te plait en détails merci.

    2)Désoler j'ai relus et relus je n'arrive pas à partir de tes explications à visualiser la différence et l'utilité exacte entre :
    int main(void)

    et


    void display

    Je sais peut être je te redemande de m'expliquer encore mais n'ayant pas compris la première explication je me dit qu'avec une autre approche peut être je comprendrais mieux. Mon but est de comprendre chaque étape de tes cours pas de les survoler et de ce fait je pose beaucoup de question mais je ne veux pas que faire mais surtout bien comprendre tout ce que je fait. Cela fait longtemps que je voulais faire du C et C++ sérieusement et pour une fois que des cours m'ont motivé

    Merci d'avance je bosserais ensuite sur les exercices une fois bien compris l'ensemble du cours et revus les anciens comme tu le conseille. Je t'ai mis bien entendu un Thank's bien mérité car tu taff superbement bien.

    Commentaire


    • #3
      1)Pourquoi dans certains de tes codes tu a :
      #include <stdio.h>
      alors que dans d'autres tu a
      #include <stdio.h>
      #include <stdlib.h>
      J'aimerais que tu m'explique ce procédé s'il te plait en détails merci.
      Se sont des bibliothèques, stdio sera utile pour printf, puts, ... tout ce qui est en rapport avec entrées sorties et stdlib pour d'autres choses et en l'occurrence dans notre cas la fonction exit, permettant une sortie sauvage du programme.

      Mais il n'y a pas d'intérêts de s'en préoccuper, si je n'en parle pas, c'est que tu dois considérer cela comme hors objectif du cours...

      Ça fera d'ailleurs parti du cours suivant.

      2)Désoler j'ai relus et relus je n'arrive pas à partir de tes explications à visualiser la différence et l'utilité exacte entre :
      int main(void)

      et


      void display
      int main(void) est une fonction ne prenant pas de paramètre, mais retournant un entier (return 0; que tu rencontres couramment depuis le début des cours).
      void display(const char chaine[]) est une fonction prenant en paramètre un tableau de caractères, et ne retournant rien.

      Commentaire


      • #4
        Bon malgrès le graph ça rentre pas suis dans une impasse ,je sais pas la fatigue (très peu dormis en 3 jours), un truc que je pige pas , peut etre tout revoir depuis le début mais désoler les pointeurs et fonctions suis blockout totale. Je reéssairais demain vais pas lacher car si je passe pas la ben je me doute que c'est mort.C'est comme si on étais passer d'un niveau débutant à direct un niveau supérieur. Je comprenais tout jusqu'à ce cours sur les fonctions.

        Demain j'éditerais ce poste si j'arrive à trouverune solution.

        Commentaire


        • #5
          L'objectif est d'utiliser les indices, et le caractère de fin de chaîne pour arrêter la boucle...

          Au niveau algorithme ça donne ceci

          Code:
          TANT QUE chaine[index] différent de '\0'
              str[index] = '*'
              incrémenter index
          Tout simplement non ? À toi de transposer cela en C

          Commentaire


          • #6
            Yessss Réussis non sans peine je t'ai envoyer un mp d'ailleur tellement j'étais démoraliser. J'ai refait et refait et relus du cours 0 à celui ci j'en peux plus. Allez je met la soluce grace à toi et je fait le 2.

            Si tu pourrais commenter la solution pour savoir si j'ai bien compris les étapes du code se serais sympas merci.

            Code:
            #include <stdio.h>
            
            void generate(const char chaine[], char *str); /* prototype de la fonction à construire */
            
            int main(void)
            {
                const char ch[] = "bonjour";
                char chaineCache[8];
            
                generate(ch, chaineCache);
            
                puts(chaineCache); /* Affichage de "*******" sur la console */
            
                return 0;
            }
            
            void generate(const char chaine[], char *str)
            {
                int index;
                /* À compléter */
                while(str[index] != '\0')
                {
                    str[index]= '*';
                    index++;
                }
            J'ai fait attention à l'indentation comme tu peux le voir mais j'ai garder index comme l'aide je sais pas s'il fallais changer.

            Merci encore et comme j'ai dit si tu pouvais m'expliquer exactement comment il fonctionne j'ai mon idée mais je voudrais vraiment comprendre exactement.

            Commentaire


            • #7
              J'allais te répondre sur ton MP, puis j'ai regardé si message au cas où.

              C'est pas mal mais il y a une petite erreur de logique

              On contrôle la fin de chaîne sur la variable chaine et non str...
              Tu as aussi oublié le caractère de fin de chaîne '\0' pour str, même si ça fonctionne il faut être extrêmement rigoureux en C, on joue avec la mémoire, il peut y avoir des comportements indéfinis...

              En MP je te mets les réponses que je pouvais attendre selon les niveaux.

              Commentaire


              • #8
                Bon voila pour le 2eme exercice :

                J'espère ne pas mettre planté de trop. En tous cas je fait de mon mieux pour comprendre en même temps que je fait et c'est dur mais plus gratifiant si je réussis.

                Code:
                #include <stdio.h>
                
                
                void display(const char chaine[],int *foisDeux);  /* prototype à compléter */
                int main(void)
                {
                    int value = 18;
                    int result; /* variable enregistrant le résultat de la fonction foisDeux */
                    result=18*2;
                    /* Utilisation de la fonction foisDeux à compléter */
                
                    printf("Le double de %d est %d\n", value, result); /* Le double de 18 est 36 */
                
                    return 0;
                }
                
                /* fonction à créer */
                void generate(const char chaine[],int *foisDeux)
                {
                    int i=0;
                    /* À compléter */
                    while(foisDeux[i] !='\0')
                    {
                        foisDeux[i]= '36';
                
                    }
                    foisDeux[i] = '\0'; /* ne pas oublier le caractère de fin de chaîne '\0' */
                   
                }
                Voila ensuite c'est clair que c'est pas pro pro encore que je peux mieux faire mais je compte m'exercer encore sur cette partie et celle d'avant.

                Mais je pense que tu devrais rajouter d'autres exemple en détaillant plus chaque étape du prgramme et la crétion du prototype de la fonction car c'est encore peu évident pour moi.
                Dernière modification par DreAmuS, 07 juillet 2014, 23h03.

                Commentaire


                • #9
                  Désolé

                  Envoyé par fred
                  La fonction sera nommée foisDeux

                  Commentaire


                  • #10
                    Code::Blocks planté quand je compilé le code pour l'exercice n°1 de DreAmus, je pense que lorsque qu'on déclare la chaine : "chaineCache[8]"

                    la valeur de fin de chaîne ('\0') n'y est pas mise par défaut, donc quand il boucle sur sa chaîne, on a boucle infinie.

                    J'ai préféré copier le contenu de "chaine" dans "str" pour m'assurer qu'on aura aucuns souci pour boucler dessus :

                    Exercice n°1 :

                    Code:
                    #include <stdio.h>
                    
                    void generate(const char chaine[], char *str);
                    
                    int main(void)
                    {
                        const char ch[] = "bonjour";
                        char chaineCache[8];
                    
                        generate(ch, chaineCache);
                    
                        puts(chaineCache);
                    
                        return 0;
                    }
                    
                    void generate(const char chaine[], char *str)
                    {
                       int i =0;
                    
                       for(i=0; i<8; i++)
                       {
                           str[i] = chaine[i]; // *str = *chaine pour éviter la boucle ?
                       }
                    
                       i = 0;
                    
                       while(*(str+i) != '\0')
                       {
                           *(str+i) = '*';
                           i++;
                       }
                    }
                    Exercice n°2 :

                    Code:
                    #include <stdio.h>
                    
                    int foisDeux( int entier);
                    
                    int main(void)
                    {
                        int value = 18;
                        int result;
                    
                        result = foisDeux(value);
                    
                        printf("Le double de %d est %d\n", value, result);
                    
                        return 0;
                    }
                    
                    int foisDeux( int entier)
                    {
                        return 2 * entier;
                    }
                    Dernière modification par shirocen, 11 janvier 2015, 21h19.
                    deux et deux font cinq

                    Commentaire


                    • #11
                      Exercice 1,il manque quelque chose...

                      Exercice 2, c'est ok

                      Commentaire


                      • #12
                        @Fred',

                        Même le débogueur serait plus précis que ça !

                        Un indice ?
                        deux et deux font cinq

                        Commentaire


                        • #13
                          Même le débogueur serait plus précis que ça !
                          Finalement non c'est correct, mais c'est pas du tout ce que je veux

                          En fait, il me faut une fonction générique, qui ne fonctionne pas seulement pour une chaîne de 8 caractères, mais pour n'importe quelle longueur de chaîne.

                          Faut donc revoir la conception de ta fonction...
                          Dernière modification par fred, 11 janvier 2015, 21h38.

                          Commentaire


                          • #14
                            "Compléter le code suivant permettant de transformer la chaine "bonjour" par "*******"."

                            J'aurais transformé cette chaine avec grand plaisir, mais c'est une constante, je vois pas sinon ?

                            EDIT : J'ai respecté toutes les consignes, j'ai pas oublié le caractère de fin de chaîne, What else ? :v

                            Si tu attends une fonction générique, il faudrait envoyé la longueur de la chaine dans la fonction ?

                            Sinon j'ai fais ça :

                            Code:
                            #include <stdio.h>
                            
                            void generate(const char chaine[], char *str);
                            
                            int main(void)
                            {
                                const char ch[] = "bonjour";
                                char chaineCache[8];
                            
                                generate(ch, chaineCache);
                            
                                puts(chaineCache);
                            
                                return 0;
                            }
                            
                            void generate(const char chaine[], char *str)
                            {
                               int i =0;
                            
                               while(i != 8)
                               {
                                   *(str+i) = '*';
                                   i++;
                               }
                            
                               *(str+i) = '\0';
                            }
                            Dernière modification par shirocen, 11 janvier 2015, 21h55.
                            deux et deux font cinq

                            Commentaire


                            • #15
                              J'aurais transformé cette chaine avec grand plaisir, mais c'est une constante, je vois pas sinon ?
                              Tu n'as pas compris. La fonction generate prend une chaîne de caractères en paramètre qui permet de transformer une chaîne quelconque en "***..." quelque soit la longueur. Dans la fonction main, on en donne un exemple pour que ça fonctionne en indiquant des variables correctement choisi.

                              Commentaire

                              Chargement...
                              X