IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Devenir un Xcoder

Un livre gratuit pour commencer avec Cocoa à l'aide d'Objective-C
Image non disponible


précédentsommairesuivant

VI. Fonctions

VI-A. Introduction

Le plus long morceau de code que vous avez pu voir jusqu'ici comportait seulement cinq déclarations. Réaliser des programmes de plusieurs milliers de lignes doit vous sembler bien lointain, mais de par la nature d'Objective-C, nous devons aborder tout d'abord la façon dont les programmes sont organisés.

Si un programme devait consister en une longue et continue succession de déclarations, il serait difficile de trouver et de réparer les erreurs. De plus, une série particulière de déclarations peut apparaître en différents endroits de votre programme. S'il y avait un bug, vous devriez le réparer à ces différents endroits. Un cauchemar, parce qu'il est facile d'en oublier un (ou deux) ! C'est pourquoi un moyen d'organiser le code a été pensé, rendant la correction d'erreurs plus aisée.

La solution à ce problème est de regrouper les déclarations selon leurs fonctions. Par exemple, vous pouvez avoir tout un groupe de déclarations vous permettant de calculer la surface d'un cercle. Une fois le code de ce groupe de déclarations jugé fiable, vous n'aurez plus jamais à le revérifier lors de la recherche d'une erreur de programmation. Ce groupe de déclarations, appelé fonction, a un nom, et vous pouvez appeler ce groupe de déclarations par son nom pour exécuter son code. Ce concept d'utilisation de fonctions est tellement fondamental qu'il y a toujours au moins une fonction dans un programme : la fonction main(). Cette fonction main() est ce que le compilateur recherche, ainsi il saura où doit commencer le code lors de son exécution.

VI-B. La fonction main()

Étudions plus en détail cette fonction main(). [1]

 
Sélectionnez
//[1]
main()
{
    // Corps de la fonction main(). Placez votre code ici.
}

La déclaration [1.1] montre le nom de la fonction, par exemple "main", suivi par des parenthèses entrantes et sortantes. Alors que "main" est un mot réservé, et que la fonction main() est obligatoire, lorsque vous définissez vos propres fonctions, vous pouvez les nommer comme bon vous semble. Les parenthèses sont là pour une bonne raison, mais nous n'en parlerons que plus loin dans ce chapitre. Dans les lignes qui suivent [1.3, 1.5], il y a des accolades. Nous devons placer notre code à l'intérieur de ces accolades { }. Tout ce qui est placé entre ces accolades est appelé le corps de la fonction. J'ai repris un peu du code issu du premier chapitre et l'ai placé où il doit l'être [2].

 
Sélectionnez
//[2]
main()
{
    // Les variables sont déclarées ci-dessous
    float pictureWidth, pictureHeight, pictureSurfaceArea;
    // Nous initialisons les variables (nous donnons une valeur aux variables)
    pictureWidth = 8.0;
    pictureHeight = 4.5;
    // C'est ici que le calcul est réalisé
    pictureSurfaceArea = pictureWidth * pictureHeight;
}

VI-C. Notre première fonction

Si nous devions continuer à ajouter du code à l'intérieur de la fonction main(), nous finirions par rencontrer des difficultés pour corriger le code, or nous voulions éviter d'écrire du code non structuré. Écrivons un autre programme, mais cette fois-ci en le structurant. En dehors de l'indispensable fonction main(), nous allons créer une fonction circleArea() [3].

 
Sélectionnez
//[3]
main()
{
    float pictureWidth, pictureHeight, pictureSurfaceArea;
    pictureWidth = 8.0;
    pictureHeight = 4.5;
    pictureSurfaceArea = pictureWidth * pictureHeight;
}
circleArea()   // [3.9]
{
}

Ce fut facile, mais notre fonction personnalisée débutant à la déclaration [3.9] ne fait pour le moment rien. Notez que la spécification de la fonction est en dehors du corps de la fonction main(). En d'autres termes, les fonctions ne sont pas imbriquées.

Notre nouvelle fonction circleArea() doit être appelée depuis la fonction main(). Voyons comment nous pouvons faire cela [4].

 
Sélectionnez
//[4]
main()
{
    float pictureWidth, pictureHeight, pictureSurfaceArea,
    circleRadius, circleSurfaceArea;  // [4.4]
    pictureWidth  = 8.0;
    pictureHeight = 4.5;
    circleRadius  = 5.0; // [4.7]
    pictureSurfaceArea =  pictureWidth * pictureHeight;
    // Ici nous appelons notre fonction !
    circleSurfaceArea = circleArea(circleRadius); // [4.10]
}

Note : le reste du programme n'est pas affiché ici (voir [3]).

VI-D. Passer des arguments

Nous avons ajouté deux noms de variables de type float [4.4], et nous avons initialisé la variable circleRadius, par exemple en lui donnant une valeur [4.7]. Le plus intéressant est la ligne [4.10], où la fonction circleArea() est appelée. Comme vous pouvez le constater, le nom de la variable circleRadius a été placé entre parenthèses. C'est un argument de la fonction circleArea(). La valeur de cette variable circleRadius va être passée à la fonction circleArea(). Quand la fonction circleArea() a fait son travail en effectuant le calcul, elle doit retourner le résultat. Modifions la fonction circleArea() de [3] pour refléter ceci [5].

Note : seule la fonction circleArea() est montrée.

 
Sélectionnez
//[5]
circleArea(float theRadius) // [5.1]
{
    float theArea;
    theArea = 3.1416 * theRadius * theRadius;  // pi multiplié par r au carré   [5.4]
    return theArea;
}

En [5.1] nous définissons que pour la fonction circleArea() une valeur de type float est requise en entrée. Une fois reçue, cette valeur est stockée dans une variable nommée theRadius. Nous utilisons une seconde variable, par exemple theArea pour stocker le résultat du calcul en [5.4], nous devons alors la déclarer en [5.3], de la même façon que nous avons déclaré les variables dans la fonction main() [4.4]. Vous noterez que la déclaration de la variable theRadius est faite à l'intérieur de parenthèses [5.1]. La ligne [5.5] retourne le résultat à l'endroit du programme d'où la fonction a été appelée. Pour résultat, à la ligne [4.11], la variable circleSurfaceArea est définie avec cette valeur.

La fonction en exemple [5] est complète, excepté pour une chose. Nous n'avons pas spécifié le type de données que la fonction va retourner. Le compilateur attend que nous le fassions, nous n'avons alors d'autre choix que d'obéir et d'indiquer float comme type [6.1].

 
Sélectionnez
//[6]
float circleArea(float theRadius)  //[6.1]
{
    float theArea;
    theArea = 3.1416 * theRadius * theRadius;
    return theArea;
}

Comme l'indique le premier mot de la ligne [6.1], la valeur retournée par cette fonction (par exemple, la valeur de la variable theArea) est de type float. En tant que programmeur, vous devez vous assurer que la variable circleSurfaceArea dans la fonction main() [4.8] est de ce type également, afin que le compilateur ne nous harcèle pas à son propos.

Toutes les fonctions ne requièrent pas un argument. S'il n'y en a pas, les parenthèses () sont toujours requises, même si elles sont vides.

 
Sélectionnez
//[7]
int throwDice()
{
    int noOfEyes;
    // Code pour générer une valeur aléatoire entre 1 et 6
    return noOfEyes;
}

VI-E. Retourner des valeurs

Toutes les fonctions ne retournent pas de valeur. Si une fonction ne retourne pas une valeur, elle est de type void. La déclaration return est alors optionnelle. Si vous l'utilisez, le mot clé return ne doit pas être suivi d'une valeur/nom de variable.

 
Sélectionnez
//[8]
void beepXTimes(int x);
{
    // Code pour biper x fois
    return;
}

Si une fonction a plus d'un argument, comme la fonction pictureSurfaceArea() ci-dessous, les arguments sont séparés par une virgule.

 
Sélectionnez
//[9]
float pictureSurfaceArea(float theWidth, float theHeight)
{
    // Code pour calculer la surface
}

La fonction main() devrait, par convention, retourner un entier, et si oui, elle doit avoir une déclaration return aussi. Elle devrait retourner 0 (zéro, [10.9]), pour indiquer que la fonction a été exécutée sans problème. Comme la fonction main() retourne un entier, nous devons écrire "int" avant main() [10.1]. Plaçons tout le code que nous avons dans une liste.

 
Sélectionnez
//[10]
int main()
{
    float pictureWidth, pictureHeight, pictureSurfaceArea,
       circleRadius, circleSurfaceArea;
    pictureWidth = 8;
    pictureHeight = 4.5;
    circleRadius = 5.0;
    pictureSurfaceArea =  pictureWidth * pictureHeight;
    circleSurfaceArea = circleArea(circleRadius);      // [10.8]
    return 0;      // [10.9]
}
float circleArea(float theRadius)           // [10.12]
{
    float theArea;
    theArea = 3.1416 * theRadius * theRadius;
    return theArea;
}

VI-F. Faisons tout fonctionner

Comme vous pouvez le voir [10], nous avons une fonction main() [10.1] et une autre fonction que nous avons définie nous même [10.12]. Si nous devions compiler ce code, le compilateur bloquerait. À la ligne [10.8] il affirmerait ne connaître aucune fonction nommée circleArea(). Pourquoi ? Apparemment, le compilateur commence la lecture de la fonction main() et rencontre soudainement quelque chose qu'il ne connaît pas. Il ne va pas voir plus loin et vous donne cet avertissement. Pour le satisfaire, ajoutez juste une déclaration de fonction avant la déclaration contenant int main() [11.1]. Il n'y a rien de difficile, car c'est la même qu'à la ligne [10.12], sauf qu'elle se termine par un point-virgule. Maintenant le compilateur ne sera pas surpris quand il rencontrera cet appel de fonction.

 
Sélectionnez
//[11]
float circleArea(float theRadius);  // déclaration de fonction
int main()
{
    // Code de la fonction main...
}

Note : le reste du programme n'est pas affiché (voir [10]).

Nous allons bientôt compiler ce programme pour de vrai. Mais voyons tout d'abord quelques détails pratiques.

Lors de l'écriture d'un programme, il est souhaitable d'avoir à l'esprit une future réutilisation du code. Notre programme pourrait avoir une fonction rectangleArea(), comme affichée ci-dessous [12], et cette fonction pourrait être appelée dans notre fonction main(). Ceci est utile même si le code placé dans la fonction est seulement utilisé une fois. La fonction main() gagne en lisibilité. Si nous avons à déboguer notre code, il sera plus facile de trouver où les erreurs sont situées dans notre programme. Vous pourriez en découvrir dans une fonction. Au lieu d'avoir à parcourir une longue séquence de déclarations, vous avez alors juste à vérifier les déclarations de cette fonction, qui sont faciles à trouver, grâce aux accolades entrantes et sortantes.

 
Sélectionnez
//[12]
float rectangleArea(float length, float width)
{
    return (length * width); //[12.3]
}
Comme vous pouvez le voir, dans un cas simple comme celui-ci, il est possible d'avoir une seule déclaration [12.3] pour à la fois calculer et retourner le résultat. J'ai utilisé la variable superflue theArea en [10.14] simplement pour vous montrer comment déclarer une variable dans une fonction.

Alors que les fonctions que nous avons définies dans ce chapitre sont plutôt triviales, il est important de réaliser que vous pouvez modifier une fonction sans impact sur le code qui l'appelle aussi longtemps que vous ne changez pas la déclaration de cette fonction (c'est-à-dire, sa première ligne).

Par exemple, vous pouvez changer le nom des variables dans la fonction, et elle fonctionnera toujours (sans que cela n'affecte non plus le fonctionnement du reste du programme). Quelqu'un d'autre pourra écrire une fonction, et vous pourrez l'utiliser sans savoir ce qu'elle contient. Tout ce que vous avez à savoir est comment utiliser la fonction. Ce qui signifie savoir :

  • le nom de la fonction ;
  • le nombre, l'ordre et le type des arguments de la fonction ;
  • ce que la fonction retourne (la valeur de la surface du rectangle), et le type du résultat.
Dans l'exemple [12], ces réponses sont, respectivement :
  • rectangleArea ;
  • deux arguments, tous les deux de type float, où le premier représente la longueur, le second la largeur ;
  • la fonction retourne quelque chose, et le résultat est de type float (comme nous l'apprend le premier terme de la déclaration [12.1]).

VI-G. Variables protégées

Le code à l'intérieur de la fonction est protégé du programme principal, et des autres fonctions d'ailleurs.

Ce que cela signifie est que la valeur d'une variable au sein d'une fonction n'est par défaut pas affectée par une variable d'une autre fonction, même si elle a le même nom. C'est une des plus essentielles fonctionnalités d'Objective-C. Dans le chapitre 5, nous étudierons à nouveau ce comportement. Mais tout d'abord, nous allons débuter avec Xcode et lancer le programme ci-dessus [10].


précédentsommairesuivant

Licence Creative Commons
Le contenu de cet article est rédigé par Alex Clarke et est mis à disposition selon les termes de la Licence Creative Commons Attribution 3.0 non transposé.
Les logos Developpez.com, en-tête, pied de page, css, et look & feel de l'article sont Copyright © 2013 Developpez.com.