Outils pour utilisateurs

Outils du site


nsi:langages:c:fonctions

Fonctions

Exemple simple

#include <stdio.h>
#include <stdlib.h>

int plus(int a, int b){
    return a + b;
}

int main() {
    int y = 4;
    int x = plus(y, 18);
    printf("%d\n", x);
    return 0;
}
ligne 4, signature

En ligne 4, on a défini une fonction plus c'est la signature de la fonction.

  • La signature commence par int ce qui signifie que cette fonction doit renvoyer un int
  • Il faut toujours indiquer le type de retour.
  • Si une fonction ne renvoie rien, il faut préciser void.
  • On précise également les arguments de la fonctions, a et b et là encore, on doit préciser leur type.
  • Le début et la fin de la fonction sont délimités par {...}
  • Comme d'habitude avec les fonctions, on ne connaît pas les valeurs de a et b. On sait seulement que ce seront des entiers. Les valeurs seront connues au moment de l'exécution de la fonction.
ligne 5, retour

Puisque la fonction a un retour de type int, il est indispensable qu'elle renvoie un entier. Ici, elle renvoie la somme de a et b ce qui sera bien un entier.

ligne 10, appel de la fonction

La fonction plus est appelée avec les arguments :

  • y qui est bien un entier, vaut 4 et prend la place de l'argument a de la fonction. Dans l'exécution, a vaudra donc 4.
  • 18 qui prend la place de l'argument b.
  • L'exécution de la fonction renvoie donc 22.
  • Le retour de la fonction est écrit dans la variable x, de type entier également.
  • L'affichage de x en ligne 7 confirme que x a pris la valeur 22.

Important : Pour permettre son exécution ligne 10, la fonction doit-être définie avant.

Il est possible de ne définir que la signature de la fonction et de ne donner le contenu que plus tard.

Les arguments ne sont pas modifiés

Prenons cet autre exemple :

#include <stdio.h>
#include <stdlib.h>

int add(int a, int b){
    a = a + b;
    return a;
}

int main() {
    int a = 5;
    int x = plus(a, 18);
    printf("%d\n", x);
    printf("%d\n", a);
    return 0;
}
Des variables différentes

Ligne 4 et ligne 10, on définit int a. Elles ont beau porter le même nom, ce sont deux variables différentes. L'affectaton ligne 13 a = a + b; n'a pas d'effet sur la variable a définie ligne 10.

Pour éviter les confusions, il est peut-être utile de changer de nom. On peut le faire ici dans le cadre de cette explication, mais c'est on ne peut pas toujours le faire : Dans un gros programme on a inévitablement des variables différentes portant le même nom. Le mécanisme dont on parle maintenant permet justement qu'elles vivent sans se perturber l'une l'autre.

#include <stdio.h>
#include <stdlib.h>

int add(int c, int b){
    c = c + b;
    return a;
}

int main() {
    int a = 5;
    int x = plus(a, 18);
    printf("%d\n", x);
    printf("%d\n", a);
    return 0;
}
Création d'une copie

Au moment de l'appel ligne 11 : int x = plus(a, 18);, on lance la fonction définie ligne 4 par int add(int c, int b){. Cela signifie qu'à son lancement, la fonction add initialise une nouvelle variable c dans laquelle il recopie la valeur qu'on lui fournit, ici le contenu de a.

Donc c est initialisé comme copie de a.

Quand on modifie c en ligne 5, cela n'a donc pas d'effet sur a.

Portée - scope

Quand on définit une variable, elle a une certaine portée. La portée est définie par les fonctions.

Dans le cas précédent, c n'existe que le temps de l'exécution de la fonction plus. Un appelle à la variable c en dehors de la fonction plus provoque une erreur.

Dès que la fonction se termine, l'espace mémoire alloué à c est libéré. La variable n'existe plus.

C'est vrai aussi des variables définies dans main : a et x sont définies dans main et sont inaccessibles depuis plus. Le seul moyen de les mettre en relation est d'utiliser les entrées - sorties de la fonction : En mettant a comme argument de plus, plus va travailler sur une copie de la valeur de a. À l'autre bout, x reçoit le résultat de l'exécution de plus. C'est la seule interaction possible.

On verra que l'on peut aller plus loin avec les pointeurs mais ce principe général reste valable.

Variable globale

Si une variable est définie en dehors des fonctions, elle peut être atteinte de façon globale. Voyons un exemple :

#include <stdio.h>
#include <stdlib.h>

int a = 25;

void change_a(){
    a = a + 1;
}

int main() {
    printf("%d\n",a);
    change_a();
    printf("%d\n",a);
    return 0;
}

La variable a définie ligne 4 a une portée globale. Lors de l'exécution de change_a, en ligne 7, c'est bien ce a global qui est modifié et dans les affichages lignes 11 et 13, c'est toujours le même a.

Modifier un argument

Supposons que l'on veuille modifier un argument (c'est souvent utile, par exemple : tri(tableau), il peut être utile que tri modifie le contenu de tableau.

Avec pointeurs

La méthode consiste à ne pas transmettre la variable elle-même comme argument mais l'adresse de la variable de façon à ce que la fonction agisse directement sur la case mémoire contenant la variable. Cela correspond aux pointeurs.

#include <stdio.h>
#include <stdlib.h>
 
void change(int *a){
    *a = *a + 1;
}
 
int main() {
    int x = 13;
    printf("%d\n",x);
    change(&x);
    printf("%d\n",x);
    return 0;
}
  • ligne 4, a est défini comme étant int *, c'est à dire un pointeur sur un entier. a est une adresse désignant une case contenant un entier. *a désigne le contenu de la case, donc un entier. D'ailleurs on le comprend puisque on note int *a ce qui veut bien dire que *a est un int.
  • le calcul ligne 5 porte sur *a, donc le contenu de la case mémoire pointée par a.
  • ligne 10, on appelle la fonction en transmettant &x, c'est à dire l'adresse de la variable x. Donc, au lancement de change c'est l'adresse de x qui est copiée dans a. Le pointeur a pointe la case mémoire de x. *a désigne donc le contenu de x et les modifications portées à *a affectent le contenu de x.
La version C++

En C++ on peut utiliser & qui est appelé dans ce cas ampersed (utile à savoir si vous devez faire une recherche !)

Cette méthode fonctionne sur C playground puisque le compilateur utilisé sur ce site est un compilateur C++.
#include <stdio.h>
#include <stdlib.h>

void change(int &a){
    a = a + 1;
}

int main() {
    int x = 13;
    printf("%d\n",x);
    change(x);
    printf("%d\n",x);
    return 0;
}

En ligne 4, dans la définition de change, l'argument a est précédé de &. Ce symbole indique que la variable est passée par référence. Je vais expliciter le mot ci-dessous.

Voyons l'exécution pour bien comprendre :

  • ligne 11, on appelle change(x). x à la place de l'argument a. Mais a ne va pas être un nouvel entier recopiant la valeur de x. a sera en fait x lui même, c'est cela que signifie par référence.
  • ligne 12, contrairement au mécanisme normal, la modification de a entraîne la modification de de x car l'utilisation de & fait que ce sont les mêmes variables..
nsi/langages/c/fonctions.txt · Dernière modification : de goupillwiki