• Aucun résultat trouvé

CHAPITRE 7 : Les fonctions en langage C CHAPITRE 7 : Les fonctions en langage C Il est souhaitable, pour diverses raisons, de

N/A
N/A
Protected

Academic year: 2022

Partager "CHAPITRE 7 : Les fonctions en langage C CHAPITRE 7 : Les fonctions en langage C Il est souhaitable, pour diverses raisons, de"

Copied!
1
0
0

Texte intégral

(1)

CHAPITRE 7 : Les fonctions en langage C CHAPITRE 7 : Les fonctions en langage C

Il est souhaitable, pour diverses raisons, de décomposer un problème en plusieurs sous-tâches, et de programmer ces sous-tâches comme des blocs indépendants. C'est le concept de la programmation modulaire qui utilise des sous-programmes.

En langage C, il y a une seule sorte de sous-programmes : les fonctions. On commence d'abord avec l'écriture et les appels des fonctions. On verra plus tard les avantages de la programmation modulaire.

A)Fonction naturelle avec return

Une fonction "naturelle" est un sous-programme permettant de calculer et de

"retourner" (avec return) un seul résultat de type simple (float, char et int dans le cadre du cours IFT 1969) à partir (fréquemment) d'une liste de paramètres (des données).

1) Syntaxe

type_résultat_de_retour nom_fonction(liste de paramètre(s)) {

déclarations locales si nécessaire

calcul et retour (avec return) du résultat }

Illustration de la syntaxe à l'aide d'un exemple

La fonction suivante permet de calculer et de retourner la plus grande valeur parmi deux réels.

float plusGrand(float x, float y) {

if (x > y) return x;

else

return y;

}

Les déclarations locales sont "localement" utiles pour le calcul du résultat à partir des données. Pour la fonction "plusGrand" ci-dessus, on n’a besoin d'aucune déclaration locale.

La fonction suivante permet de calculer le prix total à payer d'un article taxable à partir

du prix de l'article. Dans le calcul du prix total à payer, on a besoin des informations

intermédiaires. On les déclare "localement" à l'intérieur de cette fonction.

(2)

float prixAPayer(float prix) {

/* déclarations locales : */

const float TAUX_TPS = 0.07, TAUX_TVQ = 0.075;

float tps, tvq;

/* calcul du prix total à payer : prix + les 2 taxes */

tps = prix * TAUX_TPS;

tvq = (prix+TPS) * TAUX_TVQ;

return prix + tps + tvq;

}

2) Remarques

a) Le nom de la fonction ne contient pas de résultat de retour comme en PASCAL.

b) Il faut utiliser le résultat retourné dans un bon contexte (affichage, affectation, comparaison, ...).

c) L'instruction "return" provoque la fin de la fonction. On revient ensuite à l’endroit où la fonction a été appellée. Il doit avoir au moins une instruction "return" dans la fonction.

d) Dans l'en-tête, on ne peut pas regrouper les paramètres de même type :

float plusGrand(float x, y) /* erroné! */

e) Ne pas terminer l'en-tête par un point virgule :

float plusGrand(float x, float y); /* erroné! */

3) Exemples

Exemple 1 : fonction qui retourne un entier comme résultat

Écrire un programme permettant de saisir un entier n supérieur à zéro (par exemple : 5284).

Le programme calcule (par les fonctions) et affiche à l'écran :

 la somme des chiffres du nombre n (ici 19);

 l'envers du nombre n (ici 4825).

(3)

Solution

#include <stdio.h>

int somChif(int n) {

int somme = 0;

while (n > 0){

somme += n % 10;

n /= 10;

}

return somme;

}

int envers(int n) {

int k = 0;

while (n > 0){

k = k * 10 + n % 10;

n /= 10;

}

return k;

}

void main() {

int nombre;

printf("Entrez un entier positif : ");

scanf("%d", &nombre);

printf("La somme des chiffres de %d est %d\n\n", nombre, somChif(nombre));

printf("L'envers du nombre %d est %d\n\n", nombre, envers(nombre));

printf("Cliquez sur le bouton de fermeture ");

}

Exécution

Entrez un entier positif : 875 La somme des chiffres de 875 est 20 L'envers du nombre 875 est 578

Exemple 2 : fonction qui retourne un réel comme résultat

Écrire une fonction permettant de calculer le bonus dépendant du poste de travail : poste 'A' (analyste) : 234.50 $ de bonus

poste 'P' (programmeur) : 210.90 $ de bonus

(4)

poste 'O' (opérateur) : 189.00 $ de bonus

Écrire quelques appels (utilisations) valides de cette fonction.

Solution

float montantBonus(char poste) {

const float BONUS_A = 234.50, BONUS_P = 210.90, BONUS_O = 189.00;

float bonus;

switch (toupper(poste)){

case 'A': bonus = BONUS_A;

break ;

case 'P': bonus = BONUS_P;

break ;

case 'O': bonus = BONUS_O;

}

return bonus;

}

Quelques appels valides

a) dans l'affichage (plus courant)

printf("bonus d'un analyste : %6.2f\n", montantBonus('A'));

b) dans une affectation :

float salHebdo, salTotal;

char poste;

...

salTotal = salHebdo + montantBonus(poste);

c) dans une comparaison :

if (montantBonus (poste) > 200.00) printf("Pas si mal\n");

Exemple 3 : fonction qui retourne un caractère comme résultat

Écrire une fonction permettant de jouer le même rôle que "toupper" (conversion d'un caractère en majuscule).

Écrire un appel valide de cette fonction.

Solution

(5)

char majuscule(char c) {

if (c >= 'a' && c <= 'z') /* lettre minuscule */

return c + 'A' - 'a'; /* code ASCII */

else

return c;

}

Un appel valide :

printf("Le caractere %c en majuscule est %c\n", 'e', majuscule('e'));

Voici un extrait de la table des codes ASCII :

Caractere Numero ... ...

'0' 48 '1' 49 ... ...

'A' 65 'B' 66 ... ...

'a' 97 'b' 98 ... ...

Supposons que la variable c contienne un 'b' minuscule, alors c + 'A' - 'a' vaut 98 + 65 – 97 = 66 (le langage C fait la conversion automatique pour interpréter certains résultats quand il y a un conflit de types). Quel est le caractère dont l'ordre est 66? C'est la lettre 'B' en majuscule. La fonction retourne cette lettre comme résultat de la conversion.

Exemple 4 : fonction qui retourne vrai ou faux comme résultat

Écrire une fonction permettant de retourner vrai (1) ou faux (0) selon qu'un caractère est une voyelle ou non.

Écrire une instruction utilisant cette fonction pour afficher les 20 consonnes en majuscules à l'écran.

Solution

int voyelle(char lettre) {

int reponse;

switch (toupper(lettre)){

case 'A':

case 'E':

case 'I':

case 'O':

case 'U':

case 'Y': reponse = 1; /* VRAI */

(6)

break;

default :reponse = 0; /* Faux */

}

return reponse;

}

(7)

L'affichage des 20 consonnes en majuscules à l'écran se fait comme suit :

char lettre;

for (lettre = 'A'; lettre <= 'Z'; lettre++) if (!voyelle(lettre))

printf("%c", lettre);

printf("\n\n");

Remarque

Pour plus de clarté, on peut aussi utiliser les #define dans le cas des fonctions booléennes. Exemple : écrire une fonction qui retourne vrai ou faux selon qu'un entier n est pair ou non.

int estPair(int n) {

#define VRAI 1 #define FAUX 0 if (n % 2 == 0) return VRAI;

else

return FAUX;

}

N.B. : Plusieurs autres exemples seront présentés avec les paramètres de type tableau.

B) Fonction de type void (pas de return)

Ce genre de fonction est semblable à "Sub" en Visual Basic (ou "Procedure en PASCAL). Elle réalise une ou quelques tâches (trier, chercher, compter-afficher, calculer, etc.).

Certains livres présentent la fonction principale comme fonction qui retourne un entier comme résultat :

int main() {

...

return 0;

}

Cette manière permet d'éviter des avertissements (warning) à la compilation (au lieu d'en-tête main tout court). Cette méthode n'est pas très compréhensible pour les débutants en programmation. Il est préférable d'utiliser une fonction de type void :

void main() /* rien à retourner */

{ ...

(8)

}

1) Syntaxe

void nom_fonction(liste de paramètre(s)) {

déclarations locales

suites d'instructions réalisant la tâche confiée à la fonction (s'il y a des résultats de retour, ce sont des paramètres

transmis par pointeurs ou par référence(on verra plus en détail plus tard))

}

Pour le nom de la fonction (nom_fonction), on suggère d'utiliser le nom d'un verbe (ou venant d'un verbe) qui résume la tâche de la fonction :

void calculer(...) void trier(...)

void lireRemplir(...) etc.

2) Exemples Premier cas

Quand on utilise des résultats à l'intérieur du corps d'une fonction, on n'a que des paramètres transmis par valeur.

Exemple 1

Écrire une fonction permettant de compter et d'afficher le nombre de diviseurs d'un entier n positif donné. Écrire 2 appels permettant d'afficher le nombre de diviseurs de 720 et 984.

Solution

void compter(int n) {

int k = 1, /* n est un diviseur de lui-même */

i; /* utilisé dans la boucle for */

for (i = 1; i <= n / 2; i++) if (n % i == 0)

k++ ;

printf("Le nombre de diviseurs de %d est %d\n", n, k);

}

Appels

(9)

compter(720);

compter(984);

Exemple 2

Un nombre parfait est un nombre entier qui est égal à la somme de ses diviseurs propres (sauf lui-même).

Exemples: 6 = 1 + 2 + 3

28 = 1 + 2 + 4 + 7 + 14

6 et 28 sont deux nombres parfaits.

Écrire un programme utilisant des sous-programmes qui permettent de découvrir et d'afficher tous les nombres parfaits entre 2 et 500. L'affichage est du genre :

Voici les nombres parfaits entre 2 et 500 1) 6 = 1 + 2 + 3

2) 28 = 1 + 2 + 4 + 7 + 14

3) 496 = 1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248

Solution

#include <stdio.h>

/* n est-il parfait? */

int estParfait(int n) {

int somDivPropre = 1, /* le premier diviseur est 1 */

k; /* est-il un diviseur de n */

/* totaliser des diviseurs propres */

for (k = 2; k <= n / 2; k++) if (n % k == 0)

somDivPropre += k;

return n == somDivPropre;

}

/* Affichage tel que demandé */

void afficher(int nombreParfait) {

int k;

printf("%4d = 1", nombreParfait);

for (k = 2; k <= nombreParfait / 2; k++) if (nombreParfait % k == 0)

printf(" + %3d", k);

printf("\n");

(10)

}

(11)

void main() {

const int BORNE1 = 2, BORNE2 = 500;

int nombre, compteur = 0;

printf("Voici les nombres parfaits entre %d et %d\n\n", BORNE1, BORNE2);

for (nombre = BORNE1; nombre <= BORNE2; nombre++) if (estParfait(nombre)){

printf("%3d) ", ++compteur);

afficher(nombre);

}

printf("Cliquez sur le bouton de fermeture ");

}

Exécution

Voici les nombres parfaits entre 2 et 500 1) 6 = 1 + 2 + 3

2) 28 = 1 + 2 + 4 + 7 + 14

3) 496 = 1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248

Deuxième cas

La fonction calcule et retourne des résultats à travers des paramètres transmis par pointeur (langage C et C++) ou par référence (le langage C++ seulement).

Arguments transmis par pointeur (langage C et C++) : L'en-tête :

void nom_fonction(..., type_résultat *P, ...)

L’appel :

nom_fonction(..., &variable_du_type_résultat, ...);

Dans l'en-tête, c'est un pointeur qui pointe vers le résultat de type type_résultat. Dans la ligne d'appel, on a l'adresse de la variable qui reçoit le résultat de type type_résultat.

Exemple 1 sur les pointeurs versus les adresses

La valeur d'un pointeur est une adresse :

float x = 5.67;

float *p; /* p est un pointeur de type float */

p = &x; /* la valeur de p est l'adresse de x */

(12)

Illustration à l'aide de schémas

Dans le dessin ci-dessous, 62000 est (par exemple) l'adresse du début de x en mémoire:

x p

5.67 62000

a) p est un pointeur (il pointe vers x qui est de type float) :

p ---> 5.67 x

b) La valeur de p est 62000 (soit l'adresse de x).

c) *p fait référence au contenu de la variable pointée par le pointeur p, et ce contenu est de type float. Sa valeur est le contenu à l'adresse 62000, ici c'est 5.67

Exemple 2 sur les pointeurs versus les adresses

La valeur d'un pointeur est une adresse :

int age, *p1;

float taille, poids, *p2;

char sexe, *p3;

age = 23;

p1 = &age;

taille = 1.67;

poids = 65.4;

p2 = &poids;

sexe = 'M';

p3 = &sexe;

p1 est un pointeur vers age qui est de type entier.

p2 est un pointeur vers poids qui est de type réel.

p3 est un pointeur vers sexe qui est de type caractère.

Illustration à l'aide d'un schéma:

Identificateurs Contenus Adresses

age 23 168 à 171

p1 168 172 à 175

taille 1.67 176 à 179

poids 65.40 180 à 183

(13)

p2 180 184 à 187

sexe 'M' 188

??? vides 189 à 191

p3 184 192 à 195

a) p1 est un pointeur (il pointe vers age qui est de type int)

p1 ---> 23 age

b) La valeur de p1 est 168 (adresse de age).

c) *p1 est de type int. Sa valeur est le contenu à l'adresse 168, ici c'est 23.

d) Quelles sont les valeurs de p2 et de *p2?

p2 vaut 180 (adresse de poids)

*p2 vaut 65.4 (le contenu à l'adresse 180 vaut 65.4) Illustration à l'aide d'exemples

i) void calculerMin(float a, float b, float *p) /* calculer et retourner la plus petite valeur */

{

if (a < b) *p = a;

else

*p = b;

}

Exemples d'utilisation :

float x, y , plusPetit;

printf("Entrez 2 réels ");

scanf("%f%f", &x, &y);

calculerMin(x, y, &plusPetit);

printf("La plus petite valeur est %8.2f\n", plusPetit);

Explications :

Avec 5.2 comme valeur de x et 3.4 comme valeur de y; et si l'adresse de plusPetit était 52000.

Et avec l'appel suivant :

calculer(x, y, &plusPetit);

On transmet à la fonction :

void calculer(float a, float b, float *p)

(14)

a) la valeur 5.2 à a;

b) la valeur 3.4 à b;

(15)

c) la valeur 52000 à p :

à l'adresse 52000

p plusPetit

52000 ???

Exécutons la fonction :

if (a < b) *p = a;

else

*p = b;

comme a < b est faux, on a : *p = b;

c'est-à-dire : déposer à l'adresse "52000" la valeur 3.4;

à l'adresse 52000 plusPetit

3.4

c'est la fin de la fonction, on revient à la fin d'appel. On rencontre :

printf("La plus petite valeur est %8.2f\n", plusPetit);

elle fait afficher la valeur 3.40 à l'écran.

ii)void echanger(int *p, int *s)

/* Échanger le contenu de 2 entiers */

{

int temporaire;

temporaire = *p;

*p = *s;

*s = temporaire;

}

Utilisation

int a, b;

printf("Entrez 2 entiers ");

scanf(&a, &b);

printf("Avant l'echange, a = %3d, b = %3d\n", a, b);

echanger(&a, &b);

printf("Apres l'echange, a = %3d, b = %3d\n", a, b);

(16)

Explications

Si a vaut 15 et si b vaut 7; si l'adresse de a est 48000 et l'adresse de b est 48004; avec l'appel suivant :

echanger(&a, &b);

on transmet à la fonction :

void echanger(int *p, int *s)

 la valeur 48000 à p (avec *p vaut 15);

 la valeur 48004 à s (avec *s vaut 7)

p s

48000 48004

Exécutons la fonction :

temporaire = *p; ===> temporaire vaut 15

*p = *s; ===> le contenu à l'adresse 48000 est celui à l'adresse 48004

à l'adresse 48000 à l'adresse 48004

a b

7 7

*s = temporaire; ==> Le contenu à l'adresse 48004 vaut 15 :

à l'adresse 48004 b

15

À la fin de la fonction, les valeurs de a et b sont échangées.

Exercice

Écrire une fonction qui reçoit deux réels a et b comme paramètres d'entrée. Elle calcule et retourne (par pointeurs) les résultats suivants :

 la plus grande valeur parmi a et b;

 la plus petite valeur parmi a et b;

 la différence positive entre a et b (valeur absolue de (a - b)).

Références

Documents relatifs

Le puits Avec l’aide du Ministère de la Culture et de la Communication au titre de l›aide nationale à la création pour les arts du cirque (DGCA/DRAC Île-de-France) ; de la

Votation fédérale. Le bureau de la Société intercantonale des Industries du Jura, adresse la lettre suivante à ses sections, en leur envoyant des formu- laires de l'appel du Vorort

En cas de flux de bouclage élevés, la CREG s’attend à ce que les importations belges évoluent moins fortement à la hausse et s’accompagnent de prix en J-1 du marché

Elles pourraient arriver plus facilement à remonter au vrai besoin des créateurs, au sens que le projet a pour eux, à leur faire réaliser les réalités d’un projet

La distribution des formes du passé composé / imparfait est à peu près égale dans les trois enregistrements de Mona (autour de 50%), alors que l’imparfait

Rq : on aurait pu directement établir l’expression du titre massique, sans faire le calcul numérique intermédiaire de la concentration molaire :..

Rq : on aurait pu directement établir l’expression du titre massique, sans faire le calcul numérique intermédiaire de la concentration molaire :..

Désignation de l'activité,de l'unité ou du poste de travail:aide à domicile personnes agées etfamille Rédacteur:Employeur Personnes associées à l'évaluation des risques :aide