0% ont trouvé ce document utile (0 vote)
132 vues30 pages

Fonctions en langage C : Guide complet

Ce document décrit les fonctions en langage C. Il introduit les notions de fonctions, d'arguments, de valeurs de retour et présente un exemple simple de fonction. Le document explique également quelques règles concernant les fonctions.

Transféré par

Brahim
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
132 vues30 pages

Fonctions en langage C : Guide complet

Ce document décrit les fonctions en langage C. Il introduit les notions de fonctions, d'arguments, de valeurs de retour et présente un exemple simple de fonction. Le document explique également quelques règles concernant les fonctions.

Transféré par

Brahim
Copyright
© © All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Département de Mathématiques

et Informatique

Chapitre 4
Les fonctions

Filière SMIA
2013-2014
Azzedine DLIOU
Faculté Poly-disciplinaire Safi
Université Cadi Ayyad
Plan
 Introduction
 Exemple introductif
 Quelques règles
 Déclaration
 Fichiers en-têtes
 Transmission d’arguments
 Variables globales
 Variables locales
 Fonctions récursives
Introduction
 Comme tous les langages, C permet de découper un programme
en plusieurs parties nommées souvent « modules ».
 Cette programmation dite modulaire se justifie pour de multiples
raisons :
 Un programme écrit d’un seul tenant devient difficile dès qu’il
dépasse une ou deux pages de texte. Une écriture modulaire
permet de le scinder en plusieurs parties et de regrouper dans le
programme principal les instructions en décrivant les
enchaînements.
 La programmation modulaire permet d’éviter des séquences
d’instructions répétitives.
 La programmation modulaire permet le partage d’outils
communs qu’il suffit d’avoir écrits et mis au point une seule fois.
Introduction
 Une fonction, en langage C, est assez proches de la notion
mathématique correspondante.
 Une fonction dispose d’arguments (en C, comme dans la plupart
des autres langages, une fonction peut ne comporter aucun
argument).
 Argument = correspondent à des informations transmises à la
fonction.
 La fonction fournit un unique résultat scalaire (simple) ; désigné
par le nom même de la fonction, ce qui permet de le faire
apparaître dans une expression.
On dit d’ailleurs que la fonction possède une valeur et qu’un appel
de fonction est assimilable à une expression.
Introduction
 En C, une fonction pourra prendre des aspects différents. Par
exemple :
 La valeur d’une fonction pourra très bien ne pas être
utilisée ; c’est ce qui se passe fréquemment lorsqu’on
utilise printf ou scanf. De telles fonctions réalisent une
action.
 Une fonction pourra ne fournir aucune valeur.
 Une fonction pourra fournir un résultat non scalaire. (C
avancé)
 Une fonction pourra modifier les valeurs de certains de ses
arguments. (C avancé)
Exemple introductif
Exemple
#include <stdio.h>
/***** le programme principal (fonction main) *****/
main()
{
float fexemple (float, int, int) ; /* déclaration de fonction fexemple */
float x = 1.5 ;
float y, z ;
int n = 3, p = 5, q = 10 ;
/* appel de fexemple avec les arguments x, n et p */
y = fexemple(x, n, p) ;
printf ("valeur de y : %f\n", y) ;
/* appel de fexemple avec les arguments x+0.5, q et n-1 */
z = fexemple (x+0.5, q, n-1) ;
printf ("valeur de z : %f\n", z) ;
}
/*************** la fonction fexemple ****************/
float fexemple(float x, int b, int c)
{
float val ; /* déclaration d’une variable "locale" à fexemple */
val = x * x + b * x + c ;
return val ;
}
Exemple introductif
 Dans cette exemple, nous trouvons de façon désormais classique :
 un programme principal formé d’un bloc.
 Mais, cette fois, à sa suite, apparaît la définition d’une
fonction, possédant une structure voisine de la fonction main,
à savoir un en-tête et un corps délimité par des accolades ({ et
}).
 L’en-tête de cette fonction est plus élaboré que celui de la
fonction main puisque, outre le nom de la fonction (fexemple), on
y trouve :
 une liste d’arguments (nom + type),
 type de la valeur qui sera fournie par la fonction (on la
nomme indifféremment « résultat », « valeur de la fonction », «
valeur de retour »...).
Exemple introductif
float fexemple ( float x , int b , int c )
Type de la Nom de la Premier Deuxième Troisième
valeur de fonction argument argument argument
retour

Remarque
 Les noms des arguments n’ont d’importance qu’au sein du corps de la
fonction.
 Ils servent à décrire le travail que devra effectuer la fonction quand on
l’appellera (en lui fournissant trois valeurs pour notre exemple).
 Dans le corps de la fonction, on y rencontre tout d’abord :
 Une déclaration : float val;
On dit que val est une variable locale à la fonction fexemple.
 L’instruction return val précise la valeur que fournira la fonction à
la fin de son travail.
Exemple introductif
 Dans la fonction main. On trouve :
 Une déclaration : float fexemple (float, int, int) ;
Elle sert à prévenir le compilateur que fexemple est une
fonction et elle lui précise le type de ses arguments ainsi
que celui de sa valeur de retour.
 L’utilisation de la fonction fexemple au sein de la fonction
main.
Elle est classique et comparable à celle d’une fonction
prédéfinie telle que scanf ou sqrt.
Quelques règles
 Arguments muets = ou encore « arguments formels » ou
« paramètres formels », se sont les noms des arguments
figurant dans l’en-tête de la fonction, leur rôle est de
permettre, au sein du corps de la fonction, de décrire ce
qu’elle doit faire avec.
 Arguments effectifs = ou encore « paramètres
effectifs » sont les arguments fournis lors de l’appel de la
fonction.
 On peut utiliser n’importe quelle expression comme
argument effectif ; c’est la valeur de cette expression
qui sera transmise à la fonction lors de son appel.
Quelques règles
1. L’instruction return peut mentionner n’importe quelle expression.
Par exemple :
float fexemple (float x, int b, int c)
{
return (x * x + b * x + c) ;
}
2. L’instruction return peut apparaître à plusieurs reprises dans une
fonction, Par exemple:
double absom (double a, double b)
{
double s ;
s=a+b;
if (s>0) return (s) ;
else return (-s);
}
Quelques règles
Remarques
1. Notez bien que non seulement l’instruction return définit la valeur du
résultat, mais, en même temps, elle interrompt l’exécution de la
fonction en revenant dans la fonction qui l’a appelée.
2. N’oubliez pas qu’en C tous les modules sont des fonctions, y compris le
programme principal.
3. Une fonction peut ne fournir aucune valeur :
a) elle peut soit disposer d’une ou plusieurs instructions return sans
expression, interrompant simplement l’exécution de la fonction;
b) Ou ne comporter aucune instruction return, le retour étant alors mis
en place automatiquement par le compilateur à la fin de la fonction.
4. Si le type de l’expression figurant dans return est différent du type du
résultat tel qu’il a été déclaré dans l’en-tête, le compilateur mettra
automatiquement en place des instructions de conversion.
5. Il est toujours possible de ne pas utiliser le résultat d’une fonction, même si
elle en produit un.
Quelques règles
 Quand une fonction ne renvoie pas de résultat, on le précise, à la
fois dans l’en-tête et dans sa déclaration, à l’aide du mot-clé
void. Par exemple :
void sansval (int n)
{
….
….
}
 Naturellement, la définition d’une telle fonction ne doit, en
principe, contenir aucune instruction return.
Certains compilateurs ne détecteront toutefois pas l’erreur.
Quelques règles
 Quand une fonction ne reçoit aucun argument, on place le
mot-clé void (le même que précédemment, mais avec une
signification différente !) à la place de la liste d’arguments.
Par exemple :
int sansArg (void)
{
….
….
}
Déclaration : différentes façons
 Si la définition de la fonction existe avant celle de la
fonction main : int Arg (float n)
{
….
}
main()
{
….
}
La déclaration de la fonction Arg, est facultative dans la
fonction main, car, lorsqu’il traduit la fonction main, le
compilateur connaît déjà la fonction Arg.
Déclaration : différentes façons
 La déclaration complète d’une fonction porte le nom de
prototype.
 Il est possible, dans un prototype, de faire figurer des noms
d’arguments, lesquels sont alors totalement arbitraires; dans
le seul intérêt de pouvoir écrire des prototypes qui sont
identiques à l’entête de la fonction (au point-virgule près),
ce qui peut en faciliter la création automatique.
int fonction(int n, float x);
Ou sans les noms d’arguments :
int fonction(int, float);
Déclaration : Emplacement
 La tendance la plus naturelle consiste à placer la déclaration d’une
fonction à l’intérieur des déclarations de toute fonction l’utilisant.
 Dans ces conditions, nous avions affaire à une déclaration locale dont
la portée était limitée à la fonction où elle apparaisse.
 Il est également possible d’utiliser des déclarations globales, en les
faisant apparaître avant la définition de la première fonction.
Par exemple : float fexemple (float, int, int) ;
main()
{
.....
}
void fct1 (...)
{
.....
}
La déclaration de fexemple est connue à la fois de main et de fct1.
Déclaration : Utilité
 La forme la plus complète possible qu’on nomme
prototype (recommandée) peut être utilisé par le
compilateur de deux façons complètement différentes :
 Si la définition de la fonction se trouve dans le même
fichier source (que ce soit avant ou après la déclaration),
il s’assure que les arguments muets ont bien le type
défini dans le prototype. Dans le cas contraire, il signale
une erreur.
 Lorsqu’il rencontre un appel de la fonction, il met en
place d’éventuelles conversions des valeurs des
arguments effectifs dans le type indiqué dans le
prototype.
Déclaration : Utilité
float fexemple (float a, int b, int c) ;
main()
{
int n, p;
float x;
…..
fexemple (n+1, 2*x, p);
}
Un tel appel se traduit :
• L’évaluation de la valeur de l’expression n+1 (en int) et sa
conversion en float,
• L’évaluation de la valeur de l’expression 2*x (en float) et sa
conversion en int ; il y a donc dans ce dernier cas une conversion
dégradante.
Fichiers en-
en-tête
 Il existe un certain nombre de fichiers d’extension .h,
correspondant chacun à une classe de fonctions. On y trouve,
entre autres choses, les prototypes de ces fonctions.
 Ce point se révèle fort utile :
 d’une part pour effectuer des contrôles sur le nombre et le
type des arguments mentionnés dans les appels de ces
fonctions,
 d’autre part pour forcer d’éventuelles conversions.

.
Transmission des arguments
 En C, les arguments d’une fonction sont transmis par valeur.
 Pour illustrer ce mode de transmission, voyons l’exemple suivant :
Exemple d’utilisation
#include <stdio.h>
main()
{
void echange (int a, int b) ; Résultat :
int n=10, p=20 ;
printf ("avant appel : %d %d\n", n, p) ; avant appel : 10 20
echange (n, p) ; début echange : 10 20
printf ("après appel : %d %d", n, p);
} fin echange : 20 10
void echange (int a, int b) après appel : 10 20
{
int c ;
printf ("début echange : %d %d\n", a, b) ;
c=a;
a=b;
b=c;
printf ("fin echange : %d %d\n", a, b) ;
}
Transmission des arguments
Explication :
 Lors de l’appel de echange, il y a eu transmission de la valeur des expressions
n et p.
 On peut dire que ces valeurs ont été recopiées localement dans la fonction
echange dans des emplacements nommés a et b.
 C’est effectivement sur ces copies qu’a travaillé la fonction echange, de sorte
que les valeurs des variables n et p n’ont, quant à elles, pas été modifiées.
Solutions :
 Ce problème possède plusieurs solutions, à savoir :
 Transmettre en argument la valeur de l’adresse d’une variable (C
Avancé).
 Utiliser des variables globales (réservée à des cas exceptionnels).

Remarque
C’est bien parce que la transmission des arguments se fait « par valeur » que les
arguments effectifs peuvent prendre la forme d’une expression quelconque.
Variables globales
 En fait, en C, plusieurs fonctions (dont, bien entendu le
programme principal main) peuvent partager des variables
communes qu’on qualifie alors de globales.
Exemple d’utilisation
#include <stdio.h>
int i ; Résultat :
main()
Bonjour 1 fois
{
void fct (void) ; Bonjour 2 fois
for (i=1 ; i<=5 ; i++) Bonjour 3 fois
fct() ; Bonjour 4 fois
}
void fct (void) Bonjour 5 fois
{
printf ("Bonjour %d fois\n", i) ;
}
Variables globales
 Les variables globales ne sont connues du compilateur que dans la
partie du programme source suivant leur déclaration.
 On dit que leur portée (ou encore leur espace de validité) est
limitée à la partie du programme source qui suit leur
déclaration.
Exemple  Les variables n et x sont accessibles à la
fonction fct1, mais pas au programme
main()
{ principal.
....  En pratique, il possible de déclarer des
} variables globales à n’importe quel endroit
int n ; du programme source qui soit extérieur
float x ;
fct1 (...)
aux fonctions, pour d’évidentes raisons de
{ lisibilité, on préférera regrouper les
.... déclarations de toutes les variables globales
} au début du programme source.
Variables globales

Remarques

 D’une manière générale, les variables globales existent


pendant toute l’exécution du programme dans lequel elles
apparaissent.
 Ces variables se voient initialisées à zéro, avant le début de
l’exécution du programme, sauf, bien sûr, si vous leur attribuez
explicitement une valeur initiale au moment de leur déclaration.
Variables locales
 Les variables définies au sein d’une fonction, qui peut être main, sont dites
locales à la fonction dans laquelle elles sont déclarées.
 Les variables locales ne sont connues qu’à l’intérieur de la fonction où elles
sont déclarées. Leur portée est donc limitée à cette fonction.
 Les variables locales n’ont aucun lien avec des variables globales de même
nom ou avec d’autres variables locales à d’autres fonctions.
Commentaires :
Exemple
 La variable p de main n’a
int n ;
main() aucun rapport avec la variable p de
{ fct1.
int p ;  De même, la variable n de
....
}
fct1 n’a aucun rapport avec la
fct1 () variable globale n.
{  Notez qu’il est alors
int p ; impossible, dans la fonction fct1,
int n ;
} d’utiliser cette variable globale n.
Variables locales
Remarques
 Par défaut, les variables locales ont une durée de vie limitée à celle
d’une exécution de la fonction dans laquelle elles figurent.
 Plus précisément, leurs emplacements ne sont pas définis de manière
permanente comme ceux des variables globales.
 Un nouvel espace mémoire leur est alloué à chaque entrée dans la
fonction et libéré à chaque sortie. Il sera donc généralement différent
d’un appel au suivant.
 On traduit cela en disant que la classe d’allocation de ces
variables est automatique.
 De la même façon, les valeurs transmises en arguments à une
fonction sont traitées de la même manière que les variables locales.
Leur durée de vie correspond également à celle de la fonction.
Variables locales
 Il est toutefois possible de demander d’attribuer un emplacement permanent
à une variable locale et qu’ainsi sa valeur se conserve d’un appel au suivant. Il
suffit pour cela de la déclarer à l’aide du mot-clé static.
Remarque
Le mot static employé sans indication de type est équivalent à static int.
Exemple
#include <stdio.h>
main() Résultat :
{
void fct(void) ;
int n ;
appel numéro : 1
for ( n=1 ; n<=5 ; n++) appel numéro : 2
fct() ;
} appel numéro : 3
void fct(void)
{
appel numéro : 4
static int i ; appel numéro : 5
i++ ;
printf ("appel numéro : %d\n", i) ;
}
Variables locales

Remarques
 Comme pour les variables globales : les variables locales de
classe statique sont, par défaut, initialisées à zéro.
 Prenez garde à ne pas confondre une variable locale de classe
statique avec une variable globale. En effet, la portée d’une telle
variable reste toujours limitée à la fonction dans laquelle elle est
définie.
Fonctions récursives
 Le langage C autorise la récursivité des appels de fonctions. Celle-
ci peut prendre deux aspects :
 récursivité directe : une fonction comporte, dans sa définition,
au moins un appel à elle-même,
 récursivité croisée : l’appel d’une fonction entraîne celui d’une
autre fonction qui, à son tour, appelle la fonction initiale (le
cycle pouvant d’ailleurs faire intervenir plus de deux
fonctions).
Exemple Classique
long fac (int n)
{
if (n>1) return (fac(n-1)*n) ;
else return(1) ;
}

Vous aimerez peut-être aussi