Table des matières
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
intce qui signifie que cette fonction doit renvoyer unint - 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,
aetbet 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
aetb. 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 :
yqui est bien un entier, vaut 4 et prend la place de l'argumentade la fonction. Dans l'exécution,avaudra donc 4.18qui prend la place de l'argumentb.- 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
xen ligne 7 confirme quexa 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,
aest défini comme étantint *, c'est à dire un pointeur sur un entier.aest une adresse désignant une case contenant un entier.*adésigne le contenu de la case, donc un entier. D'ailleurs on le comprend puisque on noteint *ace qui veut bien dire que*aest unint. - le calcul ligne 5 porte sur
*a, donc le contenu de la case mémoire pointée para. - ligne 10, on appelle la fonction en transmettant
&x, c'est à dire l'adresse de la variablex. Donc, au lancement dechangec'est l'adresse dexqui est copiée dansa. Le pointeurapointe la case mémoire dex.*adésigne donc le contenu dexet les modifications portées à*aaffectent le contenu dex.
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'argumenta. Maisane va pas être un nouvel entier recopiant la valeur dex.asera en faitxlui même, c'est cela que signifie par référence. - ligne 12, contrairement au mécanisme normal, la modification de
aentraîne la modification de dexcar l'utilisation de&fait que ce sont les mêmes variables..
