next up previous
Next: Structure d'un programme C Up: Initiation au langage C Previous: Tableaux, pointeurs et structures

Sous-sections

Les fonctions

  Les fonctions sont les éléments de base d'un programme C. Un programme C bien conçu contient en général de nombreuses petites fonctions plutôt que peu de grosses fonctions. Chaque fonction contient une série d'instructions qui seront exécutées à chaque fois que cette fonction sera appelée.

définition d'une fonction

    Pour définir une fonction, il faut donner le type de la valeur qu'elle produit, son nom, la liste de ses paramètres et enfin le corps de la fonction :

type nom (type1 param1, ..., typeN paramN)
{
    instruction 1
    ...
    instruction N
}

Voici, par exemple, la définition d'une fonction qui calcule la moyenne de deux nombres :

double moyenne ( double a, double b )
{
    return (a + b) / 2;
}

retour du résultat

    Le mot-clé return est suivi d'une expression. La valeur de cette expression sera le résultat de la fonction. La dernière instruction d'une fonction doit être une instruction return permettant de renvoyer le résultat.

Il est possible d'utiliser return n'importe où et plusieurs fois dans une fonction. La fonction s'arrêtera immédiatement et le résultat sera renvoyé. Néanmoins, dans le cadre d'une programmation structurée, l'instruction return ne devrait apparaître que comme dernière instruction sauf si cela nuit à la compréhension de la fonction.

appel d'une fonction

  Pour appeler une fonction, il suffit de mettre son nom suivi de la liste des valeurs à donner aux paramètres entre parenthèses. Un appel de fonction est considérée comme une expression du type du résultat de la fonction et la valeur de cette expression est le résultat de l'exécution de la fonction. Dans l'exemple suivant, c contiendra la valeur moyenne de 30 et 75 :

c = moyenne(30, 75);

le type du résultat de la fonction

  Le type de la valeur retournée par une fonction peut être n'importe quel type (un type de base ou même une structure). La fonction suivante calcule la somme de deux nombres complexes :

complexe AddComplexe(complexe op1, complexe op2) {
    complexe somme;
    
    somme.reel = op1.reel + op2.reel;
    somme.imag = op1.imag + op2.imag;
    return somme;
}

  Le type void permet de spécifier que la fonction ne renvoie aucun résultat. Dans ce cas, pour terminer l'exécution de la fonction, on peut utiliser le mot-clé return seul ou plus simplement atteindre la fin des instructions.

Le type void mit seul à la place de la liste des arguments permet aussi de spécifier que la fonction ne prend aucun argument. Voici une fonction qui ne fait qu'afficher un message sur la sortie standard :

void AffMessage(void) {
    printf("Voici un message\n");
}

corps de la fonction

 

On appelle corps de la fonction le bloc d'instructions qui commence après l'accolade ouvrante qui suit la liste des paramètres et qui se termine par l'accolade fermante correspondante.

Comme tout autre bloc, le corps de la fonction peut débuter par une série de définitions de variables. Ces variables sont appelées variables locales. Chaque appel de la fonction crée de nouvelles instances des variables locales.

Les fonctions C sont réentrantes. Cela signifie qu'elles peuvent être appelées récursivement. La suite de Fibonacci se définit récursivement de la manière suivante :
\begin{gather*}Fib(0) = 1 \text{ et } Fib(1) = 1 \\
Fib(n) = Fib(n-1) + Fib(n-2)
\end{gather*}

La fonction C suivante permet de calculer Fib(n)(de manière très inefficace) :

unsigned long Fib(unsigned long n) {
    unsigned long resultat;
    
    if (n < 2L) {
        resultat = 1L;
    } else {
        resultat = Fib(n - 1) + Fib(n - 2);
    }
    return resultat;
}

paramètres d'une fonction

        Il n'y a théoriquement pas de limite au nombre de paramètres (ou arguments) que peut prendre une fonction. Chaque paramètre de la liste des paramètres doit être défini par son type suivi de son nom. Comme pour le type du résultat, le type d'un paramètre peut être soit un type de base soit une structure ou une union.

passage par valeur

Les paramètres peuvent être considérés comme des variables locales à la fonction. Lors de l'appel de la fonction, la valeur de chaque paramètre est recopiée dans un nouvel espace mémoire réservé pour ce paramètre.

Une fonction peut donc localement modifier le contenu de ses paramètres. Les valeurs utilisées lors de l'appel ne seront absolument pas modifiées. Dans l'exemple suivant, la variable a à la fin de la fonction f reste égale à 1 puisque c'est la valeur de a et non pas la variable a qui est envoyée à la fonction g :

void g (int param) {
    ...
    param = 150;
    ...
}
    
void f (void) {
    int a = 1;
    ...
    g(a);
    ...
}

utilisation des pointeurs comme paramètres

Le passage des paramètres par valeur ne permet donc pas de modifier une variable de la fonction appelante. Il semble donc que la seule interaction que puisse avoir une fonction avec l'extérieur est le renvoi de son résultat (ou l'utilisation de variables globales). Mais en fait, grâce aux pointeurs, il est possible d'agir à distance. Il suffit pour cela d'envoyer non pas la valeur d'une variable mais son adresse en mémoire (c'est à dire un pointeur sur cette variable). La fonction appelée peut alors modifier le contenu de cet emplacement mémoire (et donc le contenu de la variable elle-même).

Voici une fonction qui divise une variable de type int par un diviseur. Le résultat de la fonction est le reste de cette division. Le premier paramètre est un pointeur sur la variable à diviser et le second paramètre est le diviseur :

int DiviseEtReste(int * val, int diviseur) {
    int reste = (*val) % diviseur;
    *val /= diviseur;
    return reste;
}

On utilise aussi souvent des pointeurs pour éviter de recopier des grosses structures ou pour travailler sur des tableaux de valeurs. Voici, par exemple, une fonction permettant de calculer la moyenne des valeurs stockées dans un tableau. Le premier paramètre est un pointeur sur le tableau et le second est le nombre de valeurs stockées :

double MoyenneTableau(double *Tab, int nbVal) {
    double somme = 0;
    int indice;
    
    for (indice = 0; indice < nbVal; indice++) {
        somme += Tab[indice];
    }
    
    return somme / nbVal;
}

Pour utiliser cette fonction, on peut l'appeler de la manière suivante :

void f(void) {
    double Tableau[1000];
    double moyenne;
    ...
    /* initialisation des valeurs de Tableau */
    ...
    moyenne = MoyenneTableau(Tableau, 1000);
    ...
}

la fonction main

    La fonction dont le nom est main est une fonction particulière dans un programme C. C'est elle qui est exécutée en premier lorsqu'on lance un programme. Le programme s'arrête lorsque l'exécution de cette fonction se termine.

Elle peut être définie de différentes manières. Un programme simple définit main de la manière suivante :

int main(void) {
    ...
}

Le type de main est int afin de permettre de retourner au système d'exploitation un code d'erreur (0 si tout se passe bien).

        Elle peut aussi recevoir une liste d'arguments provenant du système d'exploitation (pour ceux qui le permettent comme UNIX par exemple). Elle est alors déclarée de la manière suivante :

int main( int argc, char * argv[]) {
    ...
}

argv est un tableau de pointeurs sur des chaînes de caractères. Chaque chaîne de ce tableau contient le texte d'un paramètre fourni par le système d'exploitation. argc contient le nombre de paramètres stockés dans le tableau. argv[0] contient en général le nom du programme en cours. C'est par ce moyen qu'un programme C peut récupérer les options d'une ligne de commande UNIX par exemple.

choses diverses sur les fonctions

Il est possible d'utiliser des pointeurs sur des fonctions ou de créer des fonctions à nombre de paramètres variables (comme printf) mais nous ne l'expliquerons pas dans ce document car cela dépasse très largement le cadre d'une introduction au C.


next up previous
Next: Structure d'un programme C Up: Initiation au langage C Previous: Tableaux, pointeurs et structures

Copyright © EMAC - 1997 - Paul GABORIT