Les Fonctions en C : Concepts et Exercices Corrigés
En programmation C, une fonction est un bloc de code autonome qui effectue une tâche spécifique. Elle permet de diviser un programme complexe en sous-programmes plus petits, facilitant ainsi la gestion, la lecture, et la maintenance du code. Une fonction en C se compose de trois parties principales :
- Déclaration de la fonction : Prototypage de la fonction avant son utilisation.
- Définition de la fonction : Contient le code qui réalise la tâche spécifique.
- Appel de la fonction : Point du programme où la fonction est exécutée.
Structure d’une Fonction en C
La structure d’une fonction en C est la suivante :
type_de_retour nom_de_fonction(type_argument1 nom_argument1, type_argument2 nom_argument2, ...) {
// Corps de la fonction
return valeur_de_retour;
}
- type_de_retour : Type de la valeur retournée par la fonction (par exemple,
int
,float
,void
). - nom_de_fonction : Nom unique attribué à la fonction.
- type_argument : Type des paramètres passés à la fonction.
- nom_argument : Nom des paramètres utilisés dans la fonction.
Exemple Simple : Fonction qui Additionne Deux Nombres
#include <stdio.h>
// Déclaration de la fonction
int addition(int a, int b);
int main() {
int x = 10;
int y = 20;
int resultat;
// Appel de la fonction
resultat = addition(x, y);
printf("La somme de %d et %d est %d\n", x, y, resultat);
return 0;
}
// Définition de la fonction
int addition(int a, int b) {
return a + b;
}
Dans cet exemple, la fonction addition
prend deux paramètres a
et b
, puis retourne leur somme.
Avantages de l’Utilisation des Fonctions
- Réutilisation du code : Une fonction peut être appelée plusieurs fois dans le programme.
- Organisation du code : Le programme est plus clair et mieux structuré.
- Facilité de maintenance : La modification d’une fonction n’affecte pas le reste du programme.
Exercices Corrigés
Exercice 1 : Calcul de la Factorielle d’un Nombre
Énoncé : Écrire une fonction factorielle
qui calcule la factorielle d’un nombre entier n
. La factorielle de n
est définie comme n! = n * (n-1) * (n-2) * ... * 1
.
Solution :
#include <stdio.h>
int factorielle(int n);
int main() {
int nombre;
printf("Entrez un nombre : ");
scanf("%d", &nombre);
printf("La factorielle de %d est %d\n", nombre, factorielle(nombre));
return 0;
}
int factorielle(int n) {
if (n == 0) {
return 1;
} else {
return n * factorielle(n - 1);
}
}
Explication : La fonction factorielle
utilise une méthode récursive pour calculer la factorielle. Si n
est 0, la fonction retourne 1 (car 0! = 1). Sinon, elle retourne n * factorielle(n-1)
.
Exercice 2 : Vérification d’un Nombre Premier
Énoncé : Écrire une fonction estPremier
qui vérifie si un nombre donné est premier ou non. Un nombre est dit premier s’il n’a que deux diviseurs : 1 et lui-même.
Solution :
#include <stdio.h>
#include <stdbool.h>
bool estPremier(int n);
int main() {
int nombre;
printf("Entrez un nombre : ");
scanf("%d", &nombre);
if (estPremier(nombre)) {
printf("%d est un nombre premier.\n", nombre);
} else {
printf("%d n'est pas un nombre premier.\n", nombre);
}
return 0;
}
bool estPremier(int n) {
if (n <= 1) return false;
for (int i = 2; i <= n / 2; i++) {
if (n % i == 0) return false;
}
return true;
}
Explication : La fonction estPremier
vérifie pour chaque nombre de 2 à n/2
si n
est divisible par ce nombre. Si c’est le cas, n
n’est pas premier. Sinon, n
est premier.
Exercice 3 : Calcul de la Puissance d’un Nombre
Énoncé : Écrire une fonction puissance
qui calcule la puissance p
d’un nombre x
, c’est-à-dire x^p
.
Solution :
#include <stdio.h>
int puissance(int x, int p);
int main() {
int base, exposant;
printf("Entrez la base : ");
scanf("%d", &base);
printf("Entrez l'exposant : ");
scanf("%d", &exposant);
printf("%d^%d = %d\n", base, exposant, puissance(base, exposant));
return 0;
}
int puissance(int x, int p) {
int resultat = 1;
for (int i = 0; i < p; i++) {
resultat *= x;
}
return resultat;
}
Explication : La fonction puissance
utilise une boucle pour multiplier la base x
par elle-même p
fois, ce qui donne x^p
.
Exercice 4 : Calcul de la Moyenne d’un Tableau
Énoncé : Écrire une fonction moyenne
qui prend en entrée un tableau d’entiers et sa taille, puis retourne la moyenne des éléments du tableau.
Solution :
#include <stdio.h>
float moyenne(int tableau[], int taille);
int main() {
int notes[] = {12, 15, 10, 8, 16, 20};
int taille = sizeof(notes) / sizeof(notes[0]);
printf("La moyenne des notes est : %.2f\n", moyenne(notes, taille));
return 0;
}
float moyenne(int tableau[], int taille) {
int somme = 0;
for (int i = 0; i < taille; i++) {
somme += tableau[i];
}
return (float)somme / taille;
}
Explication : La fonction moyenne
calcule d’abord la somme des éléments du tableau, puis divise cette somme par le nombre d’éléments pour obtenir la moyenne. La conversion en float
permet de gérer les nombres décimaux pour une moyenne précise.
Exercice 5 : Recherche d’un Élément dans un Tableau
Énoncé : Écrire une fonction rechercher
qui prend un tableau d’entiers, sa taille, et un élément à rechercher, puis retourne l’index de l’élément dans le tableau. Si l’élément n’est pas trouvé, la fonction retourne -1
.
Solution :
#include <stdio.h>
int rechercher(int tableau[], int taille, int element);
int main() {
int tableau[] = {3, 5, 7, 9, 11, 13};
int taille = sizeof(tableau) / sizeof(tableau[0]);
int element = 7;
int index = rechercher(tableau, taille, element);
if (index != -1) {
printf("Élément trouvé à l'index : %d\n", index);
} else {
printf("Élément non trouvé dans le tableau.\n");
}
return 0;
}
int rechercher(int tableau[], int taille, int element) {
for (int i = 0; i < taille; i++) {
if (tableau[i] == element) {
return i;
}
}
return -1;
}
Explication : La fonction rechercher
parcourt le tableau et compare chaque élément avec l’élément recherché. Si une correspondance est trouvée, elle retourne l’index de l’élément. Sinon, elle retourne -1
pour indiquer que l’élément n’est pas présent.
Exercice 6 : Inversion d’une Chaîne de Caractères
Énoncé : Écrire une fonction inverserChaine
qui prend une chaîne de caractères et la renverse.
Solution :
#include <stdio.h>
#include <string.h>
void inverserChaine(char chaine[]);
int main() {
char texte[] = "Programmation C";
printf("Chaîne originale : %s\n", texte);
inverserChaine(texte);
printf("Chaîne inversée : %s\n", texte);
return 0;
}
void inverserChaine(char chaine[]) {
int longueur = strlen(chaine);
for (int i = 0; i < longueur / 2; i++) {
char temp = chaine[i];
chaine[i] = chaine[longueur - i - 1];
chaine[longueur - i - 1] = temp;
}
}
Explication : La fonction inverserChaine
utilise une boucle pour échanger les caractères aux extrémités de la chaîne, progressant vers le centre. Ainsi, la chaîne est inversée en place.
Exercice 7 : Conversion de Celsius en Fahrenheit
Énoncé : Écrire une fonction celsiusVersFahrenheit
qui convertit une température donnée en degrés Celsius en Fahrenheit.
Solution :
#include <stdio.h>
float celsiusVersFahrenheit(float celsius);
int main() {
float temperatureC = 25.0;
printf("%.2f degrés Celsius équivaut à %.2f degrés Fahrenheit.\n",
temperatureC, celsiusVersFahrenheit(temperatureC));
return 0;
}
float celsiusVersFahrenheit(float celsius) {
return (celsius * 9 / 5) + 32;
}
Explication : La fonction celsiusVersFahrenheit
applique la formule de conversion (C * 9/5) + 32
pour transformer la température de Celsius en Fahrenheit.
Conseils pour Approfondir vos Connaissances
- Expérimentez avec les Fonctions : Modifiez les fonctions existantes pour leur faire accomplir des tâches similaires, comme la gestion des tableaux multidimensionnels ou la manipulation des chaînes de caractères.
- Utilisez les Bibliothèques Standard C : Explorez les fonctions déjà disponibles dans les bibliothèques standard C, comme
math.h
pour des fonctions mathématiques oustring.h
pour des opérations sur les chaînes de caractères. - Implémentez des Algorithmes Plus Complexes : Après avoir maîtrisé les bases, tentez d’implémenter des algorithmes plus complexes comme le tri de tableaux, la recherche binaire, ou les algorithmes de tri et de recherche plus avancés.
- Développez des Programmes Modulaires : Lorsque vous travaillez sur des projets plus importants, divisez-les en modules fonctionnels et utilisez des fonctions pour chaque tâche. Cela rend le code plus facile à lire et à maintenir.
Exercices sur les Cas Particuliers des Fonctions en C
Voici une série d’exercices qui traitent des cas particuliers liés à l’utilisation des fonctions en C, tels que les cas de recursivité, les fonctions avec pointeurs, la gestion des erreurs, et les fonctions avec des structures.
Exercice 1 : Fonction Récursive avec un Cas de Base Particulier
Énoncé : Écrire une fonction récursive sommeImpaire
qui calcule la somme des nombres impairs jusqu’à un nombre entier n
donné. Si n
est pair, la fonction doit ignorer n
et considérer n-1
.
Indications :
- Si
n
est égal ou inférieur à 0, la fonction doit retourner 0. - Si
n
est impair, ajoutern
à la somme des impairs précédents.
Solution Attendue :
#include <stdio.h>
int sommeImpaire(int n);
int main() {
int nombre = 10;
printf("La somme des impairs jusqu'à %d est : %d\n", nombre, sommeImpaire(nombre));
return 0;
}
int sommeImpaire(int n) {
if (n <= 0) return 0;
if (n % 2 == 0) n--; // Si n est pair, le rendre impair
return n + sommeImpaire(n - 2);
}
Explication : Cette fonction gère le cas particulier où n
est pair en le réduisant d’une unité pour le rendre impair avant de procéder à la somme récursive.
Exercice 2 : Fonction avec Pointeur et Gestion d’erreurs
Énoncé : Écrire une fonction divisionSecurisee
qui prend deux entiers a
et b
, et qui retourne le quotient de a
par b
via un pointeur. Si b
est égal à 0, la fonction doit retourner une erreur et ne pas tenter de diviser.
Indications :
- Utilisez un pointeur pour retourner le quotient.
- Gérez le cas où
b
est égal à 0 en retournant un code d’erreur.
Solution Attendue :
#include <stdio.h>
#include <stdbool.h>
bool divisionSecurisee(int a, int b, int *resultat);
int main() {
int a = 10, b = 0;
int quotient;
if (divisionSecurisee(a, b, "ient)) {
printf("Le quotient de %d par %d est : %d\n", a, b, quotient);
} else {
printf("Erreur : division par zéro.\n");
}
return 0;
}
bool divisionSecurisee(int a, int b, int *resultat) {
if (b == 0) return false;
*resultat = a / b;
return true;
}
Explication : Cette fonction utilise un pointeur pour retourner le résultat de la division et un booléen pour indiquer le succès ou l’échec de l’opération.
Exercice 3 : Fonction qui Modifie une Structure
Énoncé : Créez une structure Point
avec deux champs x
et y
représentant les coordonnées d’un point dans un plan 2D. Écrire une fonction deplacerPoint
qui prend un pointeur vers un Point
et deux entiers dx
et dy
, et modifie les coordonnées du point en ajoutant dx
et dy
respectivement.
Indications :
- La fonction doit modifier directement la structure passée en argument.
Solution Attendue :
#include <stdio.h>
typedef struct {
int x;
int y;
} Point;
void deplacerPoint(Point *p, int dx, int dy);
int main() {
Point p = {3, 4};
printf("Point avant déplacement : (%d, %d)\n", p.x, p.y);
deplacerPoint(&p, 2, -1);
printf("Point après déplacement : (%d, %d)\n", p.x, p.y);
return 0;
}
void deplacerPoint(Point *p, int dx, int dy) {
p->x += dx;
p->y += dy;
}
Explication : La fonction deplacerPoint
prend un pointeur sur une structure Point
et modifie directement les coordonnées x
et y
en leur ajoutant dx
et dy
.
Exercice 4 : Fonction qui Retourne un Tableau Dynamique
Énoncé : Écrire une fonction genererTableauCarres
qui prend un entier n
et retourne un tableau dynamique contenant les carrés des nombres de 1 à n
. Si n
est inférieur ou égal à 0, la fonction doit retourner un tableau vide (de taille 0).
Indications :
- Utilisez l’allocation dynamique de mémoire pour créer le tableau.
- Gérez le cas où
n
est négatif ou nul en retournant un pointeur NULL.
Solution Attendue :
#include <stdio.h>
#include <stdlib.h>
int* genererTableauCarres(int n);
int main() {
int n = 5;
int *tableau = genererTableauCarres(n);
if (tableau != NULL) {
printf("Tableau des carrés de 1 à %d : ", n);
for (int i = 0; i < n; i++) {
printf("%d ", tableau[i]);
}
printf("\n");
free(tableau); // Libérer la mémoire allouée
} else {
printf("Le tableau est vide ou nulle.\n");
}
return 0;
}
int* genererTableauCarres(int n) {
if (n <= 0) return NULL;
int *tableau = (int*)malloc(n * sizeof(int));
if (tableau == NULL) {
printf("Erreur d'allocation de mémoire.\n");
exit(1);
}
for (int i = 0; i < n; i++) {
tableau[i] = (i + 1) * (i + 1);
}
return tableau;
}
Explication : La fonction genererTableauCarres
alloue dynamiquement un tableau pour stocker les carrés des nombres de 1 à n
. Si n
est inférieur ou égal à 0, la fonction retourne NULL
, indiquant un tableau vide.
Exercice 5 : Fonction de Gestion d’Erreurs avec Pointeurs Nuls
Énoncé : Écrire une fonction sommeTableauSecurisee
qui prend un tableau d’entiers et sa taille, puis retourne la somme des éléments. Si le pointeur du tableau est NULL
ou si la taille est négative, la fonction doit retourner une erreur.
Indications :
- Vérifiez les entrées pour détecter les erreurs potentielles (pointeur
NULL
, taille négative). - Retournez un code d’erreur spécial si une condition invalide est détectée.
Solution Attendue :
#include <stdio.h>
int sommeTableauSecurisee(int *tableau, int taille);
int main() {
int tableau[] = {1, 2, 3, 4, 5};
int taille = sizeof(tableau) / sizeof(tableau[0]);
int somme = sommeTableauSecurisee(tableau, taille);
if (somme == -1) {
printf("Erreur : tableau NULL ou taille invalide.\n");
} else {
printf("La somme du tableau est : %d\n", somme);
}
return 0;
}
int sommeTableauSecurisee(int *tableau, int taille) {
if (tableau == NULL || taille <= 0) return -1;
int somme = 0;
for (int i = 0; i < taille; i++) {
somme += tableau[i];
}
return somme;
}
Explication : La fonction sommeTableauSecurisee
vérifie d’abord si le tableau est NULL
ou si la taille est invalide. Si c’est le cas, elle retourne -1
pour indiquer une erreur. Sinon, elle calcule et retourne la somme des éléments du tableau.
Conclusion
Ces exercices couvrent divers cas particuliers dans la gestion des fonctions en C, tels que la gestion des erreurs, la manipulation de structures, l’utilisation de la récursivité, et l’allocation dynamique de mémoire. En les pratiquant, vous renforcerez votre capacité à écrire des fonctions robustes et à gérer efficacement les cas exceptionnels dans vos programmes C.