Instructions de structuration itérative
|
Instructions de structuration conditionnelle
- if
- switch
- Opérateur conditionnel
|
Fonctions
- Possibilité de déporter un algorithme ou une portion d'algorithme dans une "fonction"
-> Une application = un ensemble de fonctions s'utilisant les unes les autres dont une seule fonction "main" : fonction lancée au lancement de l'application
- Intérêts du développement avec découpage en fonctions
- Isoler les uns des autres les divers algorithmes développés
- Utiliser tout algorithme là ou on le souhaite en appelant la fonction qui l'implante au lieu de l'écrire directement
- Faciliter le découpage d'un problème complexe en problèmes élémentaires implantés sous la forme de fonctions
- ...
- Inconvénient
- Caractéristiques d'une fonction
- Un nom qui la désigne et qui sera utilisé lors de son appel
- Une liste ordonnée de paramètres (paramètres formels) qui devront être fournis lors de son appel (paramètres effectifs, paramètres d'appel)
- Liste éventuellement vide
- Description de chaque paramètre par son type et son nom (respect de l'ordre et du type des paramètres formels vis à vis des paramètres d'appels fournis)
- Eventuellement, une valeur retournée définie, s'il y en a une, par son type
- Possibilité de définir des paramètres de n'importe quel type, non pointeur ou pointeur
- Possibilité de retourner une valeur de n'importe quel type, non pointeur ou pointeur
- Surcharge
- Pas de surcharge contrairement à C++ ou à Java
-> Impossibilité d'avoir deux fonctions portant le même nom même si elles ont des listes de paramètres formels différentes (nombre de paramètres et/ou types des paramètres)
- Fonctions imbriquées
- Contrairement à certains langages, impossibilité de développer une fonction dans une fonction
- Un programme = une liste de fonctions (pas un arbre de fonctions)
- Entête d'une fonction
- Contenu
- Type retour
- Nom de la fonction
- Liste ordonnée des paramètres avec pour chacun d'eux le type et le nom
- Informations nécessaires au compilateur C pour vérifier que le corps de la fonction est syntaxiquement correct et peut être traduit en langage machine
- Autre nom pour entête : prototype
- Signature d'une fonction
- Contenu
- Nom de la fonction
- Liste ordonnée des types des paramètres
- Informations nécessaires au compilateur C pour vérifier qu'un appel de fonction correspond bien à une fonction qui existe
- Le passage de paramètres
- Un seul type de passage de paramètre : le passage par valeur
- Possibilité de passer en entête des paramètres de n'importe quel type
- Types "classiques"
- Types pointeurs
- "Passage par adresse" = passage en valeur d'une adresse (d'un pointeur)
- Méthode pour passer un paramètre destiné à être modifié par la fonction
- Développer un entête où le paramètre formel destiné à être modifié est passé par adresse
- Lors de l'appel à la fonction, passer l'adresse de la variable à modifier en paramètre effectif
- Dans la fonction, écrire à l'adresse reçue en entête
- Exemples
#include <stdio.h>
void permutation(int a,int b) {
printf("# %3d %3d #\n", a, b);
int aux = a;
a = b;
b = aux;
printf("# %3d %3d #\n", a, b);
}
void main(void) {
permutation(3, 5);
printf("\n");
int v1 = 8;
int v2 = 6;
printf("@ %3d %3d @\n", v1, v2);
permutation(v1, v2);
printf("@ %3d %3d @\n", v1, v2);
}
|
FonctionsPassageParValeur.c - FonctionsPassageParValeur.exe |
# 3 5 #
# 5 3 #
@ 8 6 @
# 8 6 #
# 6 8 #
@ 8 6 @ |
|
#include <stdio.h>
void permutation1(int a, int b) {
printf("=== %3d %3d\n", a, b);
int aux = a;
a = b;
b = aux;
printf("=== %3d %3d\n", a, b);
}
void permutation2(int* a, int* b) {
printf("### %3d %3d\n", *a, *b);
int aux = *a;
*a = *b;
*b = aux;
printf("### %3d %3d\n", *a, *b);
}
void main(void) {
int v1 = 8;
int v2 = 6;
printf("::: %3d %3d\n", v1, v2);
permutation1(v1, v2);
printf("::: %3d %3d\n", v1, v2);
printf("\n");
printf("::: %3d %3d\n", v1, v2);
permutation2(&v1, &v2);
printf("::: %3d %3d\n", v1, v2);
printf("\n");
}
|
FonctionsPassageParAdresse.c - FonctionsPassageParAdresse.exe |
::: 8 6
=== 8 6
=== 6 8
::: 8 6
::: 8 6
### 8 6
### 6 8
::: 6 8
|
|
- Récursivité
- Support de la récursivité par le langage C
- Exemple
#include <stdio.h>
long long factoriel(int n) {
if (n == 0) {
return 1;
}
return n * factoriel(n - 1);
}
void main(void) {
for (int nb = 0; nb <= 25; nb++) {
printf("%2d! = %25lld\n", nb, factoriel(nb));
}
}
|
FonctionRecursive.c - FonctionRecursive.exe |
0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
17! = 355687428096000
18! = 6402373705728000
19! = 121645100408832000
20! = 2432902008176640000
21! = -4249290049419214848
22! = -1250660718674968576
23! = 8128291617894825984
24! = -7835185981329244160
25! = 7034535277573963776
|
|
- Ordre d'écriture des fonctions
- Obligation qu'une fonction soit déclarée (prototypée) avant de pouvoir être utilisée dans une autre fonction
- Cas simple : écriture entière possible de toute fonction avant le premier endroit où elle est utilisée dans une autre fonction
- Problème : ordre de précédence parfois impossible à respecter
Exemple : récursivité où une fonction A utilise une fonction B et où la fonction B utilise la fonction A
- Solution : pas d'obligation que la fonction A soit écrite entièrement pour pouvoir être utilisée dans B, seule obligation : connaître (déclarer) son entête
-> Déclaration préalable de l'entête de la fonction A, puis écriture complète de la fonction B (qui utilise A), puis écriture complète de la fonction A selon l'entête déclaré
- Déclaration : Entête "classique" d'une fonction suivie d'un point virgule
- Déclaration simplifiable par suppression des noms des paramètres
-> Liste des paramètres restreinte à la liste des types des paramètres
Conséquence : perte d'expressivité
- Exemple
- Variables de type fonction
|