Les fonctions
Généralités
Une fonction est un bloc d’instructions éventuellement paramétré par un ou plusieurs arguments et pouvant fournir un résultat nommé souvent « valeur de retour ». On distingue la définition d’une fonction de son utilisation, cette dernière nécessitant une déclaration. La définition d’une fonction se présente comme dans cet exemple : float fexple (float x, int b, int c) // en-tête de la fonction { // corps de la fonction } L’en-tête précise le nom de la fonction (fexple) ainsi que le type et le nom (muet) de ses différents arguments (x, b et c). Le corps est un bloc d’instructions qui définit le rôle de la fonction. Au sein d’une autre fonction (y compris main), on utilise cette fonction de cette façon : float fepxle (float, int, int) ; // déclaration de fexple (« prototype ») ….. fexple (z, n, p) ; //appel fexple avec les arguments effectifs z, n et p exos_c++. La déclaration d’une fonction peut être omise lorsqu’elle est connue du compilateur, c’est-àdire que sa définition a déjà été rencontrée dans le même fichier source. Mode de transmission des arguments Par défaut, les arguments sont transmis par valeur. Dans ce cas, les arguments effectifs peuvent se présenter sous la forme d’une expression quelconque. En faisant suivre du symbole & le type d’un argument dans l’en-tête d’une fonction (et dans sa déclaration), on réalise une transmission par référence. Cela signifie que les éventuelles modifications effectuées au sein de la fonction porteront sur l’argument effectif de l’appel et non plus sur une copie. On notera qu’alors l’argument effectif doit obligatoirement être une lvalue du même type que l’argument muet correspondant. Toutefois, si l’argument muet est, de surcroît, déclaré avec l’attribut const, la fonction reçoit quand même une copie de l’argument effectif correspondant, lequel peut alors être une constante ou une expression d’un type susceptible d’être converti dans le type attendu. Ces possibilités de transmission par référence s’appliquent également à une valeur de retour (dans ce cas, la notion de constance n’a plus de signification). La notion de référence est théoriquement indépendante de celle de transmission d’argument ; en pratique, elle est rarement utilisée en dehors de ce contexte.
L’instruction return
L’instruction return sert à la fois à fournir une valeur de retour et à mettre fin à l’exécution de la fonction. Elle peut mentionner une expression ; elle peut apparaître à plusieurs reprises dans une même fonction ; si aucune instruction return n’est mentionnée, le retour est mis en place à la fin de la fonction. Lorsqu’une fonction ne fournit aucun résultat, son en-tête et sa déclaration comportent le mot void à la place du type de la valeur de retour, comme dans : void fSansValRetour (…) Lorsqu’une fonction ne reçoit aucun argument, l’en-tête et la déclaration comportent une liste vide, comme dans : int fSansArguments ().
Les arguments par défaut
Dans la déclaration d’une fonction, il est possible de prévoir pour un ou plusieurs arguments (obligatoirement les derniers de la liste) des valeurs par défaut ; elles sont indiquées par le signe =, à la suite du type de l’argument, comme dans cet exemple : exos_c++.chapitre n° 3 Les fonctions float fct (char, int = 10, float = 0.0) ; Ces valeurs par défaut seront alors utilisées lorsqu’on appellera ladite fonction avec un nombre d’arguments inférieur à celui prévu. Par exemple, avec la précédente déclaration, l’appel fct (‘a’) sera équivalent à fct (‘a’, 10, 0.0) ; de même, l’appel fct (‘x’, 12) sera équivalent à fct (‘x’, 12, 0.0). En revanche, l’appel fct () sera illégal. Conversion des arguments Lorsqu’un argument est transmis par valeur, il est éventuellement converti dans le type mentionné dans la déclaration (la conversion peut être dégradante). Ces possibilités de conversion disparaissent en cas de transmission par référence : l’argument effectif doit alors être une lvalue du type prévu ; ctte dernière ne peut posséder l’attribut const si celui-ci n’est pas prévu dans l’argument muet ; en revanche, si l’agument muet mentionne l’attribut const, l’argument effectif pourra être non seulement une constante, mais également une expression d’un type quelconque dont la valeur sera alors convertie dans une variable temporaire dont l’adresse sera fournie à la fonction. Variables globales et locales Une variable déclarée en dehors de toute fonction (y compris du main) est dite globale. La portée d’une variable globale est limitée à la partie du programme source suivant sa déclaration. Les variable globales ont une classe d’allocation statique, ce qui signifie que leurs emplacements en mémoire restent fixes pendant l’exécution du programme. Une variable déclarée dans une fonction est dite locale. La portée d’une variable locale est limitée à la fonction dans laquelle elle est définie. Les variables locales ont une classe d’allocation automatique, ce qui signifie que leurs emplacements sont alloués à l’entrée dans la fonction, et libérés à la sortie. Il est possible de déclarer des variables locales à un bloc. On peut demander qu’une variable locale soit de classe d’allocation statique, en la déclarant à l’aide du mot-clé static, comme dans : static int i ; Les variables de classe statique sont, par défaut, initialisées à zéro. On peut les initialiser explicitement à l’aide d’expressions constantes d’un type compatible par affectation avec celui de la variable. Celles de classe automatique ne sont pas initialisées par défaut. Elles doivent être initialisées à l’aide d’une expression quelconque, d’un type compatible par affectation avec celui de la variable.