Le langage C est très bien adapté a la programmation modulaire. Sa souplesse permet de hiérarchiser des fonctions. Un programme C est en structure comme une arborescence de fonctions, que ce soit des fonctions prédéfinies dans les bibliothèques standard (telles printf ou scanf), ou des fonctions utilisateurs à commencer par la fonction main.

La façon d'appeler les fonctions des bibliothèques standard est exactement la même que les fonctions utilisateurs. Il est dans les deux cas nécessaire que la fonction appelée soit convenablement déclarée. Pour les fonctions de la bibliothèque standard, cela consiste a inclure un fichier d'en-têtes qui contiennent les prototypes des fonctions prédéfinies à l'aide de la directive #include. Les prototypes des fonctions utilisateurs peuvent aussi être placées dans un fichier de ce type (possédant par conventions l'extension .h), et inclus dans les fichiers de code utilisant ces fonctions. Le compilateur peut ainsi vérifier (de façons plus ou moins précises) si la forme d'appel correspond bien à la définition qu'en donne la déclaration? contrôler notamment si le type de la valeur retournée par la fonction est bien celui attendu, si le nombre et le type d'arguments correspond bien, ...

Le compilateur crée des fichiers objets (d'extension .o ou .obj), correspondants aux fichiers de code source, ou seuls les appels aux fonctions externes sont répertoriés. Ces fichiers objets sont des fichiers binaires, traduction en code machine du code source. Ces fichiers ne sont pas exécutables car c'est seulement lors de l'édition de liens (linkage) que le lieur (linker) associe le code de la fonction (les instructions composant le corps de la fonction) et l'appel de la fonction (depuis un autre point du programme). En effet, ce n'est qu'après les deux opérations que sont la compilation et l'édition des liens que l'on peut obtenir un fichier exécutable. On peut même dire qu'il y a trois phases, si on prends en compte le préprocesseur.

Un Ch'tit exemple :

#include <stdio.h> /* directive du preprocesseur */ #include <math.h> /* bibliotheque de fonctions mathematiques */ int perimetre(int r) ; int surface(int r) ; void main() { int i,j; printf("Entrez moi le rayon du cercle : "); scanf("%d",&i); j = perimetre(i); printf("Le cercle a un perimetre de %d",j); j = surface(i); printf("Le cercle a une surface de %d",j); } int perimetre(int r) { /* Cette fonction renvoie le perimetre d'un cercle dont le rayon est passe en parametres */ int i; i = 2 * r * M_PI; /* Et oui, ici pi s'appele M_PI et se trouve dans math.h*/ return i; } int surface(int r) { /* Cette fonction renvoie la surface */ return (M_PI*r*r); }

Les fonctions sont de la forme : type nom(type1 argument1, type2 argument2, ...). Le type est, si la fonction renvoie une donnée : un type de données, int, char, float, char[] et le type est void si la fonction ne renvoie pas de données, dans ce cas, elle est appelée procédure. Les arguments sont le nom des arguments qui seront passés a la fonction par l'appelant. Dans l'exemple précédant, par exemple, la première fonction est int perimetre(int r). Le type de la fonction est int, cela signifie que la fonction doit retourner un entier grâce à l'instruction return (valeur). Les arguments sont ici au nombre de 1, il est de type entier (int) et se nomme r, dans la fonction, donc, a chaque fois que l'on aura besoin de la variable passée à la fonction, on l'appellera r. et le nom de la fonction est perimetre, donc, dans la fonction qui appelle cette fonction, on l'utilisera sous la forme : perimetre(valeur);.

Vous avez j'en suis sur remarqué les deux lignes avant la fonction main : int perimetre(int r) ; et int surface(int r) ;. Ce sont les prototypes des fonctions. Ces prototypes doivent être placés au début du fichier, après les directives du préprocesseur et avant la fonction main

Exercice :

Ecrire une fonction appelée expo, qui prends 2 arguments entiers n et m et qui retourne n^m. Ecrire une autre fonction appelée lireEntierPositif, qui demande un entier à l'utilisateur et qui lui demande tant que cet entier n'est pas positif, des que l'entier est positif, elle renvoie cet entier. solution


Papier Cailloux Ciseaux

On veut écrire un programme permettant de jouer au jeu "papier, caillou, ciseau". On codera le caillou par 0, le papier par 1 et le ciseau par 2. Pour déterminer lequel des deux joueurs a gagné, on utilisera l'algorithme suivant :

Soit J1 le pari du joueur 1 et J2 le pari du joueur 2.

- Le match est nul si J1 et J2 sont identiques,

- J1 gagne si J1 = (J2 + 1) modulo 3,

- J2 gagne dans les autres cas.

Pour ceci :

- Ecrire une fonction LireInf2 qui effectue la saisie contrôlée d'un entier compris entre 0 et 2.

- Ecrire une fonction arbitre qui reçoit les paris des deux joueurs et qui renvoie 0 si le match est nul, 1 si le joueur 1 a gagné ou 2 si c'est le joueur 2.

- Ecrire un programme qui arbitre 10 parties et qui affiche les scores.

solution


Nombres amis :

Les diviseurs d'un entier n sont tous les nombres de 1 à n-1 qui divisent n.

exemple : 6= 1 2 3

exemple : 36= 1 2 3 4 6 9 12 18

Ecrire une fonction sommediv qui accepte un entier n en paramètres et qui retourne la somme des diviseurs de n.

Deux entiers A et B sont dis amis si la somme des diviseurs de A égale B et la somme des diviseurs de B égale A.

Exemple : 220 et 284 sont amis

Ecrire une fonction amis qui reçoit deux entiers A et B et qui retourne 1 si ils sont amis, et 0 sinon.

Ecrire un programme qui donne la liste des couples de nombres amis inférieurs à un entier donné par l'utilisateur.

solution

Transmissions de paramètres :

Lors d'un appel d'une fonction truc(x);, ce n'est pas x qui est transmit, mais juste sa valeur. pour changer la valeur de x, il faut transmettre à la fonction l'adresse mémoire de x. On utilise l'opérateur & comme dans scanf("%d",&x); ceci permet d'affecter une valeur a x. Par exemple :

void echanger(int a, int b) { int temp; temp=a; a=b; b=temp; }

l'appel de echange(a,b); ne change pas les valeurs de a et de b. La fonction echange travaille sur des copies auxquelles on passe les valeurs de a et de b. Par contre :

void echanger(int * a, int * b) { int temp; temp=*a; *a=*b; *b=temp; }

Réalise l'échange en appelant echange(&a,&b);.

Explications :

Les opérateurs & (référence) et * (déréférence) sont inverse l'un de l'autre. Si x est une variable de type t, alors, &x est l'adresse de la variable x. C'est une expression de type t*. Si p est déclarée de type t*, alors *p est une expression de type t. On dit que p est un pointeur et que c'est une variable dont la valeur est une adresse.

Exercice :

Simplification d'une fraction

Ecrire une fonction simplifie2 qui prends 2 paramètres représentant le numérateur et le dénominateur d'une fraction et qui transforme ces entiers en numérateur et dénominateur d'une fraction équivalente simplifiée. Par exemple si les variables ont initialement pour valeurs 3 et 12, après l'appel de la fonction, leurs valeurs seront 1 et 4 ((3/12)=(1/4)). On supposera que les valeurs initiales représentent une fraction valide (dénominateur non nul)

Ecrire une fonction simplifie qui réalise le même travail que simplifie2 mais qui indique une erreur grâce à une valeur entière retournée si le dénominateur de la fonction est nul (!=0 si tout est ok, et 0 en cas d'erreur) il est possible de réutiliser la fonction précédente.

Ecrire un programme de test pour ces fonctions.

solution


Somme de fraction

Ecrire une procédure SommeFrac qui reçoit quatre paramètres représentant le numérateur et le dénominateur de deux fractions et qui affecte à deux autres paramètres le numérateur et le dénominateur de la fraction représentant la somme des deux fractions initiales. On supposera que l'on dispose d'une fonction pgcd (plus grand commun multiple) de prototype void pgcd(int, int);.

solution


Transformation de minuscule en majuscule

Ecrire une fonction TransformeMinMaj qui reçoit un argument représentant une valeur de type char et qui renvoie 1 si cette valeur est une lettre de l'alphabet (minuscule ou majuscule). La fonction doit mettre la variable reçue en majuscule se celle-ci étais en minuscule.

Ecrire un programme qui lit une suite de caractère sur une ligne et qui affiche uniquement les lettres de l'alphabet de la suite, en majuscules. Par exemple, si l'utilisateur entre la ligne a4H3n, le programme doit afficher AHN.

solution



Dernière révision :
Date de Création : 18 mars 1998
Copyright ©
Mathieu ARNOLD 1998