Cours programmation en langage C: Les fonctions

Ce cours s'adresse aux étudiants de première année en informatique et couvre les notions fondamentales des fonctions en langage C. Il explique la modularisation des programmes, la déclaration, la définition et l'utilisation des fonctions, ainsi que la gestion des variables locales et globales, le passage des paramètres, et le traitement des tableaux à une ou deux dimensions.

D'après le document Cours programmation en langage C: Les fonctions

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Document source

Cours programmation en langage C: Les fonctions

Computer Science · PDF · 12 pages · 2011

Afficher l'aperçu du document

Consulter le document original →

Ce cours s'adresse aux étudiants de première année en informatique et couvre les notions fondamentales des fonctions en langage C. Il explique la modularisation des programmes, la déclaration, la définition et l'utilisation des fonctions, ainsi que la gestion des variables locales et globales, le passage des paramètres, et le traitement des tableaux à une ou deux dimensions.

Modularisation de programmes en C

En langage C, la structuration des programmes se fait à l'aide de fonctions. Jusqu'ici, nous avons utilisé des fonctions prédéfinies comme printf ou sqrt, ainsi qu'une seule fonction nouvelle : la fonction principale main(). Pour des problèmes plus complexes, écrire tout dans main() conduit à des programmes longs, peu lisibles et répétitifs, ce qui gaspille de la mémoire.

La modularité consiste à diviser un programme en sous-programmes plus simples, appelés fonctions ou procédures, ce qui permet :

  • Une meilleure lisibilité
  • Une diminution du risque d'erreurs
  • La possibilité de tests sélectifs
  • La dissimulation des méthodes
  • La réutilisation de modules existants
  • La simplicité de l'entretien
  • La facilitation du travail en équipe
  • La hiérarchisation des modules

Exemple : Calcul de la factorielle

Version simple dans main() :

#include <stdio.h>
void main()
{
  int n, i, f=1;
  printf("saisir un entier    ");
  scanf("%d", &n);
  for (i=2; i<=n; i++)
    f *= i;
  printf("la factorielle de %d est %d\n", n, f);
  printf("fin du travail");
}

Version modulaire avec une fonction factorielle :

#include <stdio.h>
void factorielle(int n)
{
  int i, f=1;
  for (i=2; i<=n; i++)
    f *= i;
  printf("la factorielle de %d est %d\n", n, f);
}
void main()
{
  int n;
  printf("saisir un entier    ");
  scanf("%d", &n);
  factorielle(n);
  printf("fin du travail");
}

Blocs et portée des identificateurs

Une fonction en C est définie par un bloc d'instructions encadré par des accolades :

{ <déclarations locales> <instructions> }

Ce principe s'applique aussi aux blocs conditionnels ou boucles (if, while, for), qui peuvent contenir des déclarations locales.

Variables locales

Les variables déclarées dans un bloc sont visibles uniquement dans ce bloc. Par exemple :

if (n > 0) {
  int i;
  for (i=0; i<n; i++) ...
}

La variable i n'existe que dans ce bloc et disparaît à sa fin. Une variable locale masque toute variable du même nom dans les blocs englobants.

Exemple de portée des variables

#include <stdio.h>
void calculer()
{
  int n = 3;
  printf("la valeur de n dans la fonction calculer est %d\n", n);
}
void main()
{
  int n = 5;
  printf("la valeur de n avant l'appel de la fonction calculer est %d\n", n);
  calculer();
  printf("la valeur de n apres l'appel de la fonction calculer est %d\n", n);
}

Exécution :

la valeur de n avant l'appel de la fonction calculer est 5
la valeur de n dans la fonction calculer est 3
la valeur de n apres l'appel de la fonction calculer est 5

Variables globales

Les variables déclarées en dehors de toute fonction, généralement après les directives #include, sont accessibles par toutes les fonctions du programme. Exemple :

#include <stdio.h>
int y = 3;
void test()
{
  printf("la valeur de y dans test est %d\n", y);
}
void main()
{
  printf("la valeur de y, dans main, avant l'appel de test est %d \n", y);
  test();
  printf("la valeur de y, dans main, apres l'appel de test est %d \n", y);
}

Exécution :

la valeur de y, dans main, avant l'appel de test est 3
la valeur de y dans test est 3
la valeur de y, dans main, apres l'appel de test est 3

Déclaration, définition et appel de fonctions

Le nom d'une fonction apparaît généralement à trois endroits :

  1. Lors de la déclaration
  2. Lors de la définition
  3. Lors de l'appel

Une fonction est définie par :

  • Son nom
  • Le type, le nombre et les noms de ses paramètres
  • Le type de son résultat
  • Ses données locales
  • Les instructions à exécuter

Syntaxe générale :

<TypeRés> <NomFonct>(<TypePar1> <NomPar1>, <TypePar2> <NomPar2>, ...)
{
  <déclarations locales>
  <instructions>
}

Il n'y a pas de point-virgule après la définition des paramètres.

Types de fonctions

  • Une fonction qui retourne un résultat de type T est dite de type T.
  • Une fonction ne peut pas retourner directement un tableau, une chaîne de caractères ou une fonction, mais peut retourner un pointeur.
  • Si une fonction ne retourne rien, son type est void.
  • Si une fonction n'a pas de paramètres, on peut écrire (void) ou ().
  • Par défaut, le type d'une fonction non déclaré est int.
  • Il est interdit de définir une fonction à l'intérieur d'une autre.
  • L'ordre des définitions n'a pas d'importance, mais une fonction doit être déclarée ou définie avant son appel.

Exemple : Fonctions saisir et maximum

#include <stdio.h>
int saisir()
{
  int a;
  printf("saisir un entier ");
  scanf("%d", &a);
  return a;
}
int maximum(int a, int b)
{
  int max;
  if (a > b) max = a;
  else max = b;
  return max;
}
void main()
{
  int x, y, max;
  x = saisir();
  y = saisir();
  max = maximum(x, y);
  printf("\n le maximum est %d", max);
}

Déclaration (prototype) d'une fonction

Une fonction doit être déclarée avant son utilisation pour informer le compilateur des types des paramètres et du résultat. Le prototype indique uniquement les types :

<TypeRés> <NomFonct>(<TypePar1>, <TypePar2>, ...);

Les noms des paramètres peuvent être inclus mais ne sont pas obligatoires.

Fonctions qui appellent des fonctions

Une fonction peut appeler une autre fonction. Exemple :

#include <stdio.h>
int saisir()
{
  int x;
  printf("saisir un entier    ");
  scanf("%d", &x);
  return x;
}
int somme(int x, int y, int z)
{
  return (x + y + z);
}
float moyenne(int x, int y, int z)
{
  int s;
  s = somme(x, y, z);
  return (float)(s / 3);
}
void main()
{
  int a, b, c;
  float m;
  a = saisir();
  b = saisir();
  c = saisir();
  m = moyenne(a, b, c);
  printf("la moyenne est %f", m);
}

Exemple pratique : Affichage d'un rectangle d'étoiles

Version simple :

#include <stdio.h>
void main()
{
  int l, c, i, j;
  printf("saisir nombre de lignes et nombre de colonnes");
  scanf("%d%d", &l, &c);
  for (i = 0; i < l; i++)
  {
    for (j = 0; j < c; j++)
      printf("*");
    printf("\n");
  }
}

Version modulaire avec fonctions ligne et rectangle :

#include <stdio.h>
void ligne(int c)
{
  int j;
  for (j = 0; j < c; j++)
    printf("*");
}
void rectangle(int l, int c)
{
  int i;
  for (i = 0; i < l; i++)
  {
    ligne(c);
    printf("\n");
  }
}
void main()
{
  int l, c;
  printf("saisir nbre de lignes et nbre colonnes");
  scanf("%d%d", &l, &c);
  rectangle(l, c);
}

Renvoyer un résultat avec return

La commande return <expression>; permet de :

  • Évaluer l'expression
  • Convertir automatiquement le résultat au type de la fonction
  • Renvoi du résultat
  • Terminaison immédiate de la fonction

Paramètres d'une fonction

Les paramètres sont des variables locales initialisées par les valeurs passées lors de l'appel. Le nombre, l'ordre et le type des paramètres doivent correspondre à la déclaration.

Si une fonction n'a pas de paramètres, on utilise void ou une liste vide.

Passage des paramètres par valeur

En C, les paramètres sont toujours passés par valeur : la fonction reçoit une copie des valeurs, et ne peut pas modifier les variables originales.

Exemple : Permutation de deux entiers

Permutation dans main() :

#include <stdio.h>
void main()
{
  int x, y, aide;
  printf(" saisir deux entiers   ");
  scanf("%d%d", &x, &y);
  printf("les valeurs avant permutation: x: %d et y:%d", x, y);
  aide = x;
  x = y;
  y = aide;
  printf("\n les valeurs après permutation: x: %d et y:%d", x, y);
}

Permutation dans une fonction (sans effet sur les variables originales) :

#include <stdio.h>
void permuter(int x, int y)
{
  int aide;
  aide = x;
  x = y;
  y = aide;
}
void main()
{
  int x, y;
  printf(" saisir deux entiers   ");
  scanf("%d%d", &x, &y);
  printf("les valeurs avant permutation: x: %d et y:%d", x, y);
  permuter(x, y);
  printf("\n les valeurs après permutation: x: %d et y:%d", x, y);
}

Exécution :

saisir deux entiers 4 7
les valeurs avant permutation: x: 4 et y:7
les valeurs après permutation: x: 4 et y:7

Passage de l'adresse d'une variable (passage par pointeur)

Pour modifier la valeur d'une variable dans la fonction appelante, on passe son adresse et on déclare le paramètre comme pointeur :

#include <stdio.h>
void permuter(int *a, int *b)
{
  int aide;
  aide = *a;
  *a = *b;
  *b = aide;
}
void main()
{
  int x, y;
  printf(" saisir deux entiers   ");
  scanf("%d%d", &x, &y);
  printf("les valeurs avant permutation: x: %d et y:%d", x, y);
  permuter(&x, &y);
  printf("\n les valeurs après permutation: x: %d et y:%d", x, y);
}

Exécution :

saisir deux entiers 4 7
les valeurs avant permutation: x: 4 et y:7
les valeurs après permutation: x: 7 et y:4

Passage de l'adresse d'un tableau à une dimension

Il est impossible de passer un tableau entier par valeur. On passe donc l'adresse du premier élément, donnée par le nom du tableau. On peut déclarer le paramètre comme un tableau ou un pointeur :

  • int tab[]
  • int *tab

Exemple : Remplir et afficher un tableau

Version avec pointeurs :

#include <stdio.h>
void saisir2(int *a)
{
  printf("saisir nbre d'éléments");
  scanf("%d", a);
}
void remplir(int *p, int n)
{
  int i;
  for (i = 0; i < n; i++)
    scanf("%d", p + i);
}
void afficher(int *p, int n)
{
  int i;
  for (i = 0; i < n; i++)
    printf("%d \t", *(p + i));
}
void main()
{
  int tab[50], n;
  saisir2(&n);
  remplir(tab, n);
  afficher(tab, n);
}

Autres versions

Version utilisant un pointeur de parcours :

#include <stdio.h>
void saisir2(int *a)
{
  printf("saisir nbre d'éléments");
  scanf("%d", a);
}
void remplir(int *p, int n)
{
  int *h;
  for (h = p; h < p + n; h++)
    scanf("%d", h);
}
void afficher(int *p, int n)
{
  int *h;
  for (h = p; h < p + n; h++)
    printf("%d \t", *h);
}
void main()
{
  int tab[50], n;
  saisir2(&n);
  remplir(tab, n);
  afficher(tab, n);
}

Version utilisant la notation tableau :

#include <stdio.h>
void saisir2(int *a)
{
  printf("saisir nbre d'éléments");
  scanf("%d", a);
}
void remplir(int tab[], int n)
{
  int i;
  for (i = 0; i < n; i++)
    scanf("%d", tab + i);
}
void afficher(int tab[], int n)
{
  int i;
  for (i = 0; i < n; i++)
    printf("%d \t", *(tab + i));
}
void main()
{
  int tab[50], n;
  saisir2(&n);
  remplir(tab, n);
  afficher(tab, n);
}

Passage de l'adresse d'un tableau à deux dimensions

#include <stdio.h>
void remplir(int *tab, int l, int c)
{
  int i, j;
  for (i = 0; i < l; i++)
    for (j = 0; j < c; j++)
      scanf("%d", tab + i * 50 + j);
}
void afficher(int *tab, int l, int c)
{
  int i, j;
  for (i = 0; i < l; i++)
  {
    for (j = 0; j < c; j++)
      printf("%d", *(tab + i * 50 + j));
    printf("\n");
  }
}
void main()
{
  int mat[50][50];
  int l, c;
  printf("saisir nbre d'élémnets");
  scanf("%d%d", &l, &c);
  remplir((int *)mat, l, c);
  afficher((int *)mat, l, c);
}

Glossaire des termes clés

  • Fonction : Sous-programme qui réalise une tâche spécifique et peut retourner un résultat.
  • Bloc d'instructions : Ensemble d'instructions encadrées par des accolades { }.
  • Variable locale : Variable déclarée dans un bloc, accessible uniquement dans ce bloc.
  • Variable globale : Variable déclarée en dehors de toute fonction, accessible par toutes les fonctions.
  • Prototype de fonction : Déclaration d'une fonction indiquant son type et ses paramètres, sans corps.
  • Paramètre : Variable locale d'une fonction initialisée par la valeur passée lors de l'appel.
  • Passage par valeur : Transmission d'une copie de la valeur du paramètre à la fonction.
  • Passage par adresse (pointeur) : Transmission de l'adresse d'une variable pour permettre sa modification dans la fonction appelée.
  • Return : Instruction qui renvoie une valeur et termine l'exécution d'une fonction.
  • Tableau : Structure de données contenant plusieurs éléments du même type, accessible par indices.

Points clés à retenir

  • La modularisation améliore la lisibilité, la réutilisation et la maintenance des programmes.
  • Les fonctions sont définies par un type de retour, un nom, une liste de paramètres, et un bloc d'instructions.
  • Les variables locales sont visibles uniquement dans leur bloc, tandis que les variables globales sont accessibles partout.
  • Le passage des paramètres se fait toujours par valeur en C, sauf si on passe des pointeurs pour modifier les variables originales.
  • Les tableaux sont passés aux fonctions par adresse, généralement en passant l'adresse du premier élément.
  • La commande return permet de renvoyer un résultat et de terminer une fonction.
  • Il est interdit de définir une fonction à l'intérieur d'une autre.
  • Chaque fonction doit être déclarée ou définie avant d'être appelée.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions