{!
/* instruction ou bloc d'instructions */!
}!
• Le bloc d'instructions est exécuté uniquement si l'expression logique est VRAIE
• Les accolades de début et de fin de bloc ne sont pas nécessaires si une seule instruction est conditionnée
• Exemples #
int a = 1, b = 0;!
if (a) printf(« %d », a); ! /* le test est VRAI */!
if (b) printf(« %d », b);! /* FAUX */!
if (b<a) { a--; b++; } ! ! /* VRAI */!
if (a == 0) {a = a+b; b--; a = a+b;} /* VRAI */!
if (a = 0) a++; ! ! ! /* FAUX */!
{!
/* bloc d'instructions */!
}!
else !
{ /* alternative */!
/* bloc d'instructions */!
}!
• Exemple :#
int i = 0, j = 1;!
!if (i > 0) !
! j++;!
!else !/* alternative : if (i <= 0) { ... } */!
j--;!
if (i == 0) { /* Bloc d’instructions */ }!
else if (i == 1) { /* Bloc d’instructions */ }!
else if (i == 2) { /* Bloc d’instructions */ }!
else { /* Bloc d’instructions */ }!
• Les conditions sont évaluées du haut vers le bas jusqu’à ce que l’une d’entre elles soit vraie
• Le dernier else traite le cas où aucune condition précédente n’est remplie
• avec switch!
switch <expression>) {!
case <constante1> : <bloc d’instructions> break;!
case <constante2> : <bloc d’instructions> break;!
case <constante3> : <bloc d’instructions> break;!
default : <bloc d’instructions>!
}!
• Les instructions sont exécutées à partir de l’étiquette de branchement jusqu’au moment où l’on rencontre
« break » ou la fin de « switch ».
• L’étiquette « default » est branchée si aucune des autres étiquettes ne correspond à la valeur (constante) de l’expression conditionnant « switch »
condition ? expression1 : expression2
•
Si la condition est vérifiée, l’expression prend la valeur d’expression1, sinon elle prend la valeur d’expression2.
Exemple :
Max = ( ( a > b ) ? a : b)
for (<initialisation> ; <expression logique> ; <itération suivante>)!
{!
/* bloc d’instructions */!
}!
!
• La boucle « for » utilise souvent (comme les autres types de boucle) une variable d’indice de boucle
• <initialisation>!
• Quelle valeur de départ doit prendre la variable d’indice de boucle ?
• Exemple: i = 0!
• <expression logique>!
• Le bloc d’instruction est exécuté tant que l’expression logique est VRAIE
• Exemple: i < 10!
• <itération suivante>!
• Quelle instruction pour passer à l’itération suivante ? Progression de la variable d’indice de boucle ?
• Exemple: i++!
for(i = 0; i < 10; i++)!
{!
printf(« %d », i+1);!
}!
/* Affiche les 10 premiers entiers naturels */!
• Possibilité de mettre plusieurs instructions dans les champs
<initialisation> et <itération suivante> (séparation avec une « , »)
int i, j;!
for(i = 0, j = 11; i<10; i+=2, j-=2) ! {!
printf(« %d %d »,i+1, j-1);!
}!
• Remarque: Si une seule instruction est itérée alors les accolades ne sont pas obligatoires
while(<expression logique>) ! {!
/* bloc d'instructions */!
}!
!
• Le bloc d'instructions est exécuté tant que l'expression logique a la valeur VRAI
Affichage des 10 premiers entiers naturels
int i;!
i = 1;!
while(i <= 10) ! {!
printf(« %d », i); /* cela marche-t-il ? */!
}!
Affichage des 10 premiers entiers naturels
int i;
i = 1;!
while(i <= 10) ! {!
printf(« %d », i); ! /* NE PAS OUBLIER !*/!
i++; ! /* L'INCREMENT DE LA BOUCLE !*/!
}!
•
Exemple
• Calcul de la partie entière d'un logarithme à base 10 d'un entier positif (on ignore la fin a priori !!!)
int c = 0, m, n;!
scanf (« %d », &n); m = n;!
while (n >= 10) { n /= 10; c++; }!
printf («\n log10(%d) = %d », m, c);!
• Similaire à la boucle « while » (à une exception prés)
do {!
/* bloc d instructions *!
} while (<expression logique>);!
!
• Exécute le bloc d instructions tant que l expression logique est vraie
• Le test est fait en fin d itération (conséquence : au moins 1 passage dans la boucle)
• Exemple
• Affichage des 10 premiers entiers naturels
int i = 1;!
do {!
printf(« %d », i++);!
} while (i <= 10);!
!
• Attention: cette boucle est inadaptée dans ce cas !!
• L’instruction break provoque une sortie immédiate de la boucle (for, while, do) ou du switch le plus proche
• L’instruction continue relance immédiatement la boucle dans laquelle elle se trouve
int i, j, c;!
for (i=j=0 ; (c=getchar( )) !=EOF ; i++)!
{!
if (c== \n ) break ;!
if (c== ) continue ;!
j++ ;!
}!
• fonction principale « main( ) »
• printf, scanf, autres...
• Autres fonctions
•
Parties de code source qui permettent de réaliser le
même type de traitement plusieurs fois ou sur des objets
différents
• Modifier des données globales. Ces données sont dans une zone de mémoire qui peut être modifiée par le reste du programme.
• Communiquer avec le reste du programme par une interface.
L'appel de la fonction correspond à un échange de données à travers cette interface, au traitement de ces données (dans le corps de fonction), et à un retour de résultat via cette interface.
ouvrantes et fermantes.
• Une définition de fonction contient :
• une interface (un entête)
• un corps de fonction.
int add(int a, int b) !/*interface-entête*/!
! !{ ! ! ! !/*corps*/!
! ! int c ;!
! ! c=a+b;!
! ! return c;!
! !}!
- type et du nom de la fonction - parenthèse ouvrante
- types et noms des paramètres - parenthèse fermante.
bloc
<déclaration des variables locales>!
<bloc d instructions>!
<retour de la fonction>!
}!
!
• <type>
• N’importe quel type de donnée prédéfini ou pas, pointeur ou non
• Caractérise le type de valeur qui va être calculée et renvoyée par la fonction
• <déclaration des variables locales>
• Toute variable déclarée dans une fonction (y compris la fonction main( )) est connue exclusivement dans cette fonction.
• <retour de la fonction>
• Une fonction renvoie toujours une seule valeur. Syntaxe: return(<valeur>);
• Rq : pas de retour = type void
• Syntaxiquement identique à une déclaration de variables
• Décrit l’ensemble des valeurs (typées) qui doivent être pris en
paramètre par la fonction (à l’appel). Le bloc d’instructions est appliqué sur ces paramètres
• Exemple : définition d’une fonction « f » prenant en paramètres 2 valeurs de type entier et renvoyant une valeur de type entier
int f(int valeur1, int valeur2)!
!! !{!
… !
! }!
{ !
v++; ! }!
!
main( ) ! { !
int t = 2;!
f(t);!
}!
Que vaut « t » après l’appel à « f » ?
main() { int t = 2; f(t); }!
• 2 éventualités
• Passage de paramètres « par valeur » (par copie)
• « t » est inchangé dans « main( ) » quelles que soient les modifications qu’il peut subir dans « f( ) » : t vaut 2 après l’appel à f( )!
• Passage de paramètres « par variable »
• Les modifications faites à « t » dans « f( ) » sont
préservées dans « main( ) » : t vaut 3 après l’appel à f( )!
(par copie) !!!!!!
• la fonction appelante fait une copie de la valeur passée en
paramètre et passe cette copie à la fonction appelée à l'intérieur d'une variable créée dans l'espace mémoire géré par la pile
d'exécution
•
Exemple :
Définition Appelint plus(int a,int b) int x=4,y=6,z;
{
a = a + b; z = plus(1,23);
return(a); z = plus(x,y);
}
les valeurs 1 et 23 sont empilées dans des variables anonymes dont les types correspondent aux types de paramètres de la fonction (dans ce cas deux entiers) ;
• Etape 2 :
la fonction plus() est appelée, ce qui se traduit par l'empilement de l'adresse de retour et du pointeur de contexte courant. La fonction plus() dispose de deux variables qu'elle connait sous les noms "a"
et "b". Ces deux variables sont les copies des valeurs dont nous avons parlé au point précédent. Elles ont donc pour valeurs initiales respectivement 1 et 23 ;
mettant la valeur 24 ;
• Etape 4
la fonction se termine en retournant cette valeur 24, cette valeur est stockée dans un registre du processeur réservé à cet effet ;
• Etape 5
les variables créées par l'appel sont détruites (l'espace sur la pile est restitué, le pointeur de pile est remis à sa
valeur initiale).
• Etape 6
la valeur stockée dans le registre du processeur est
affectée à la variable z (correspondant à l'affectation).
• même principe en commençant par le calcul des variables x et y et l empilement de ces valeurs
•
Le passage des paramètres par valeur empêche de
modifier des objets de la fonction appelante, SAUF si la
fonction appelante passe les adresses de ces objets, et
non les objets eux-mêmes (cf. Pointeurs)
• déclaration
• définition
• prototype
•
Déclaration : annoncer que tel identificateur correspond à une fonction, qui renvoie tel type
•
Définition : une déclaration où, en plus, on donne le code de la fonction elle-même
•
Prototype : déclaration de fonction où le type des
arguments est également donné
• int f(void);/* declaration de f( ), renvoyant un int, prototype (0 arg) */
• int f(void) /* definition de f( ) avec declaration avec prototype */
{ return 42; }
• int f(x) /* definition de f( ) avec declaration sans prototype */
int x; { return x; }
• int f( ) /* definition de f( ) avec declaration sans prototype */
{ return 42; }
• utiliser des définitions et déclarations avec prototype
•
Comme tout objet en C, une fonction doit être déclarée avant son utilisation.
•
Où déclarer les prototypes ?
• Un prototype de fonction doit être déclaré avant l'utilisation de la fonction
• il est conseillé de regrouper tous les prototypes d'un module (fichier xxx.c) dans un en-tête (<xxx.h>). Ce dernier n'a plus alors qu'à être inclus dans le code qui utilise ces fonctions. C'est le cas des
fonctions de la bibliothèque standard.
•
void f( ) {!
…!
f( )!
…!
}!
•
Approche similaire à la notion de récurrence employée en mathématiques
•
La « récursion » se distingue de l itération.
• A priori
• Tous les problèmes peuvent être traités de façon récursive
• Tous les problèmes peuvent également être traité de façon itérative
retournant aucun résultat.
• « n » sera le paramètre de la fonction
• Itérativement void f(int n) {!
!! ! int i;!
!! ! for(i = 1; i <= n; i++){!
printf(« %d », i); ! }!
!! ! } !!
• Récursivement void f(int n) {!
if (n > 1) f(n-1);!
printf(« %d », n);!
}!