'>

les fonctions en c plus plus avec les structures

Utilisation des fonctions que nous pouvons structurer nos programmes de façon plus modulaire, l'accès à toutes les possibilités que peut offrir la programmation structurée à nous en C + +.

Une fonction est un groupe d'instructions qui est exécutée quand il est appelé à un certain point du programme. Ce qui suit est son format:

nom du type (parameter1, parameter2, ...) {instructions}

où:

    type est le spécificateur de type des données retournées par la fonction de données.
    nom est l'identifiant par lequel il sera possible d'appeler la fonction.
    paramètres (autant que nécessaire): Chaque paramètre est constitué d'un spécificateur de type de données, suivi par un identifiant, comme toute déclaration de variables régulière (par exemple: int x) et qui agit au sein de la fonction comme une variable locale régulière. Ils permettent de passer des arguments à la fonction lorsqu'elle est appelée. Les différents paramètres sont séparés par des virgules.
    comptes est le corps de la fonction. Il s'agit d'un bloc d'instructions entre accolades {}.


Ici vous avez le premier exemple de fonction:

1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18


   

 // function example #include <iostream> using namespace std; int addition ( int a, int b) { int r; r=a+b; return (r); } int main () { int z; z = addition (5,3); cout << "The result is " << z; return 0; }

   

  Le résultat est 8



Afin d'examiner ce code, tout d'abord rappeler quelque chose dit au début de ce tutoriel: un programme C + + commence toujours son exécution par la fonction principale. Nous allons donc commencer par là.

Nous pouvons voir comment la fonction principale commence par déclarer la variable z de type int. Juste après cela, on voit un appel à une fonction appelée plus. Prêter attention, nous serons en mesure de voir la similitude entre la structure de l'appel à la fonction et la déclaration de la fonction elle-même quelques lignes de code ci-dessus:



Les paramètres et les arguments ont une correspondance claire. Dans la fonction principale que nous avons appelé à l'addition passant deux valeurs: 5 et 3, qui correspondent à l'int a et b int paramètres déclarés pour la fonction addition.

Au point où la fonction est appelée depuis principale, la perte de contrôle par principal et transmis à fonctionner plus. La valeur des arguments passés à l'appel (5 et 3) sont copiés vers les variables locales INT A et INT B dans la fonction.

plus de fonction déclare une autre variable locale (int r), et au moyen de l'expression r = a + b, il attribue à r le résultat de a plus b. Parce que les paramètres réels passés pour A et B sont de 5 et 3 respectivement, le résultat est de 8.

La ligne de code suivante:



   

 return (r);



finalise fonction plus, et retourne à l'arrière de la commande à la fonction qui l'a appelée en premier lieu (dans ce cas, le principal). En ce moment, le programme suit son cours normal à partir du même point où il a été interrompu par l'appel à l'addition. Mais en plus, parce que la déclaration de retour, en plus de fonction spécifié une valeur: le contenu de la variable r (retour (R);), qui à ce moment avait une valeur de 8. Cette valeur devient la valeur de l'évaluation de l'appel de fonction.


Donc, étant la valeur renvoyée par une fonction de la valeur donnée à la fonction d'appel lui-même quand il est évalué, la variable z est définie sur la valeur retournée par addition (5, 3), qui est de 8. Pour expliquer d'une autre façon, vous pouvez imaginer que l'appel à une fonction (addition (5,3)) est littéralement remplacé par la valeur qu'elle retourne (8).

La ligne de code suivante dans le principal est le suivant:



   

 cout << "The result is " << z;



C'est, comme vous pouvez déjà attendre, produit l'impression du résultat sur l'écran.

Portée des variables

La portée des variables déclarées dans une fonction ou tout autre bloc interne n'est que leur propre fonction ou de leur propre bloc et ne peut pas être utilisé en dehors d'eux. Par exemple, dans l'exemple précédent, il aurait été impossible d'utiliser les variables a, b ou r directement dans la fonction principale, car ils étaient des variables locales à la fonction addition. En outre, il aurait été impossible d'utiliser la variable z directement au sein de la fonction plus, puisqu'il s'agit d'une variable locale à la fonction principale.


Par conséquent, la portée des variables locales est limitée au même niveau de bloc dans lequel elles sont déclarées. Néanmoins, nous avons également la possibilité de déclarer des variables globales; Ceux-ci sont visibles depuis n'importe quel point du code, à l'intérieur et à l'extérieur de toutes les fonctions. Pour déclarer des variables globales il vous suffit de déclarer la variable en dehors d'une fonction ou d'un bloc, ce qui implique, directement dans le corps du programme.

Et voici un autre exemple sur les fonctions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22


   

 // function example #include <iostream> using namespace std; int subtraction ( int a, int b) { int r; r=ab; return (r); } int main () { int x=5, y=3, z; z = subtraction (7,2); cout << "The first result is " << z << '\n' ; cout << "The second result is " << subtraction (7,2) << '\n' ; cout << "The third result is " << subtraction (x,y) << '\n' ; z= 4 + subtraction (x,y); cout << "The fourth result is " << z << '\n' ; return 0; }

   

  Le premier résultat est de 5
  Le second résultat est 5
  Le troisième résultat est 2
  Le quatrième résultat est 6



Dans ce cas, nous avons créé une fonction appelée soustraction. La seule chose que cette fonction ne consiste à soustraire les deux paramètres passés et à retourner le résultat.

Néanmoins, si nous examinons la fonction principale, nous verrons que nous avons fait plusieurs appels à fonctionner soustraction. Nous avons utilisé des méthodes différentes d'appel de sorte que vous voyez d'autres façons ou des moments où une fonction peut être appelée.

Afin de bien comprendre ces exemples, vous devez tenir compte encore une fois que l'appel d'une fonction peut être remplacée par la valeur que l'appel de la fonction elle-même va revenir. Par exemple, le premier cas (que vous devriez déjà savoir parce que c'est le même modèle que nous avons utilisé dans les exemples précédents):

 1
 2


   

 z = subtraction (7,2); cout << "The first result is " << z;



Si nous remplaçons l'appel de fonction par la valeur qu'elle retourne (soit 5), nous aurions:

 1
 2


   

 z = 5; cout << "The first result is " << z;



Aussi bien que



   

 cout << "The second result is " << subtraction (7,2);



a le même résultat que l'appel précédent, mais dans ce cas nous avons fait l'appel à la soustraction directement comme paramètre d'insertion pour cout. Il suffit de considérer que le résultat est le même que si nous avions écrit:



   

 cout << "The second result is " << 5;



depuis 5 est la valeur retournée par la soustraction (7,2).

Dans le cas de:



   

 cout << "The third result is " << subtraction (x,y);



La seule chose nouvelle que nous avons présenté est que les paramètres de soustraction sont des variables au lieu de constantes. C'est tout à fait valable. Dans ce cas, les valeurs transmises à fonctionner soustraction sont les valeurs de x et y, qui sont de 5 et 3 respectivement, ce qui donne comme résultat 2.

Le quatrième cas est plus de même. Il suffit de noter que, au lieu de:



   

 z = 4 + subtraction (x,y);



nous aurions pu écrire:



   

 z = subtraction (x,y) + 4;



avec exactement le même résultat. J'ai changé de place afin que vous puissiez voir que le signe point-virgule (;) va à la fin de l'instruction entière. Il ne doit pas nécessairement aller à droite après l'appel de la fonction. L'explication pourrait être une fois de plus que vous imaginez qu'une fonction peut être remplacée par sa valeur de retour:

 1
 2


   

 z = 4 + 2; z = 2 + 4;



Fonctionne avec aucun type. L'utilisation du vide.

Si vous vous souvenez de la syntaxe d'une déclaration de fonction:

nom du type (argument1, argument2 ...) déclaration

vous verrez que la déclaration commence par un type, qui est le type de la fonction elle-même (par exemple, le type de la donnée qui sera renvoyé par la fonction avec l'instruction de retour). Mais que faire si nous voulons retourner aucune valeur?

Imaginons que nous voulons faire une fonction juste pour montrer un message sur l'écran. Nous n'avons pas besoin de retourner n'importe quelle valeur. Dans ce cas, nous devrions utiliser le spécificateur de type void pour la fonction. Il s'agit d'un prescripteur spécial qui indique l'absence de Type.

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14


   

 // void function example #include <iostream> using namespace std; void printmessage () { cout << "I'm a function!" ; } int main () { printmessage (); return 0; }

   

  Je suis une fonction!



vide peut également être utilisé dans la liste des paramètres de la fonction permettant de spécifier explicitement que nous voulons que la fonction prenne pas de paramètres réels quand on l'appelle. Par exemple, la fonction PrintMessage aurait été déclaré comme:

 1
 2
 3
 4


   

 void printmessage ( void ) { cout << "I'm a function!" ; }



Bien qu'il soit optionnel pour spécifier les vide dans la liste des paramètres. En C + +, une liste de paramètres peut être simplement laissé vide si nous voulons une fonction sans paramètres.

Ce que vous devez toujours vous rappeler est que le format de l'appel d'une fonction comprend spécifiant son nom et en joignant ses paramètres entre parenthèses. La non-existence de paramètres ne nous dispense pas de l'obligation d'écrire les parenthèses. Pour cette raison, l'appel à PrintMessage:



   

 printmessage ();



Les parenthèses indiquent clairement qu'il s'agit d'un appel à une fonction et non pas le nom d'une variable ou d'un autre C + + déclaration. L'appel suivant aurait été incorrect:



   

 printmessage;



 Arguments passés par valeur et par référence.

Jusqu'à présent, dans toutes les fonctions que nous avons vus, les arguments passés aux fonctions ont été passés par valeur. Cela signifie que lorsque vous appelez une fonction avec des paramètres, ce que nous avons passés à la fonction étaient des copies de leurs valeurs, mais jamais les variables elles-mêmes. Par exemple, supposons que nous avons appelé notre premier ajout de fonction en utilisant le code suivant:

1
 2


   

 int x=5, y=3, z; z = addition ( x , y );



Ce que nous avons fait dans ce cas était d'appeler à fonctionner plus passer les valeurs de x et y, soit 5 et 3 respectivement, mais pas les variables x et y eux-mêmes.



De cette façon, lorsque la fonction est appelée outre, la valeur de ses variables locales a et b devenir 5 et 3 respectivement, mais toute modification de A ou B au sein de la fonction ajout n'aura aucun effet sur ​​les valeurs de x et y extérieures , parce que les variables x et y ne sont pas eux-mêmes passés à la fonction, mais seulement des copies de leurs valeurs au moment de la fonction a été appelée.

Mais il pourrait y avoir certains cas où vous avez besoin de manipuler de l'intérieur en fonction de la valeur d'une variable externe. Pour ce faire, nous pouvons utiliser des arguments passés par référence, comme dans la fonction double de l'exemple suivant:

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18


   

 // passing parameters by reference #include <iostream> using namespace std; void duplicate ( int & a, int & b, int & c) { a*=2; b*=2; c*=2; } int main () { int x=1, y=3, z=7; duplicate (x, y, z); cout << "x=" << x << ", y=" << y << ", z=" << z; return 0; }

   

  x = 2, y = 6, z = 14



La première chose qui devrait attirer votre attention est que dans la déclaration de reproduire le type de chaque paramètre a été suivi par un signe esperluette (&). Cette esperluette est ce qui spécifie que leurs arguments correspondants doivent être passées par référence plutôt que par valeur.

Quand une variable est passé par référence nous n'adoptons pas une copie de sa valeur, mais nous sommes en quelque sorte en passant la variable elle-même à la fonction et de toute modification que nous faisons pour les variables locales aura un effet sur leurs variables de contrepartie passés comme arguments dans l'appel de la fonction.


Pour l'expliquer d'une autre manière, nous associons a, b et c avec les arguments passés à l'appel de fonction (x, y et z) et tout changement que nous faisons sur un sein de la fonction aura une incidence sur la valeur de x à l'extérieur. Toute modification que nous faisons sur b affectera y, et même avec c et z.

C'est pourquoi la sortie de notre programme, qui montre les valeurs stockées dans x, y et z après l'appel à dupliquer, montre les valeurs de toutes les variables de trois principaux doublé.

Si lors de la déclaration de la fonction suivante:



   

 void duplicate ( int & a, int & b, int & c)



nous avions déclaré de cette façon:



   

 void duplicate ( int a, int b, int c)



c'est à dire sans les signes esperluette (&), on n'aurait pas passé les variables par référence, mais une copie de leurs valeurs à la place, et, par conséquent, la sortie sur l'écran de notre programme aurait été les valeurs de x, y et z sans ayant été modifié.

Le passage par référence est également un moyen efficace pour permettre une fonction pour retourner plus d'une valeur. Par exemple, voici une fonction qui renvoie les numéros précédents et suivants du premier paramètre passé.

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17


   

 // more than one returning value #include <iostream> using namespace std; void prevnext ( int x, int & prev, int & next) { prev = x-1; next = x+1; } int main () { int x=100, y, z; prevnext (x, y, z); cout << "Previous=" << y << ", Next=" << z; return 0; }

   

  Précédent = 99, Next = 101



Les valeurs par défaut des paramètres.
Lors de la déclaration d'une fonction, nous pouvons spécifier une valeur par défaut pour chacun des derniers paramètres. Cette valeur sera utilisée que si l'argument correspondant est laissé vide lors de l'appel à la fonction. Pour ce faire, nous avons tout simplement d'utiliser l'opérateur d'affectation et une valeur pour les arguments dans la déclaration de fonction. Si la valeur de ce paramètre n'est pas passé lorsque la fonction est appelée, la valeur par défaut est utilisée, mais si une valeur est spécifiée cette valeur par défaut est ignorée et la valeur passée est utilisé à la place. Par exemple:

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18


   

 // default values in functions #include <iostream> using namespace std; int divide ( int a, int b=2) { int r; r=a/b; return (r); } int main () { cout << divide (12); cout << endl; cout << divide (20,4); return 0; }

   

  6
  5



Comme nous pouvons le voir dans le corps du programme, il ya deux appels à fonctionner fracture. Dans la première partie:



   

 divide (12)



Nous avons seulement précisé un argument, mais la fonction fracture permet de connecter jusqu'à deux. Ainsi, la fonction fracture a supposé que le second paramètre est 2 puisque c'est ce que nous avons spécifié de se produire si ce paramètre n'a pas été adopté (notez la déclaration de fonction, qui se termine par int b = 2, et pas seulement int b). Par conséquent, le résultat de cet appel de fonction est 6 (12/2).

Dans le second appel:



   

 divide (20,4)



il ya deux paramètres, de sorte que la valeur par défaut de b (int b = 2) est ignorée et b prend la valeur passée en argument, qui est de 4, ce qui rend le résultat retourné égal à 5 (20/4).

Fonctions surchargées.
En C + + deux fonctions différentes peuvent avoir le même nom si leurs types de paramètres ou le nombre sont différents. Cela signifie que vous pouvez donner le même nom à plusieurs fonctions s'ils ont un nombre différent de paramètres ou de types différents dans leurs paramètres. Par exemple:

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24


   

 // overloaded function #include <iostream> using namespace std; int operate ( int a, int b) { return (a*b); } float operate ( float a, float b) { return (a/b); } int main () { int x=5,y=2; float n=5.0,m=2.0; cout << operate (x,y); cout << "\n" ; cout << operate (n,m); cout << "\n" ; return 0; }

   

  10
  2.5



Dans ce cas, nous avons défini deux fonctions avec le même nom, exploiter, mais l'un d'eux accepte deux paramètres de type int et l'autre les accepte de type float. Le compilateur sait que l'on appeler dans chaque cas, en examinant les types passés comme arguments lorsque la fonction est appelée. Si elle est appelée avec deux ints que ses arguments, il appelle à la fonction qui a deux paramètres int dans son prototype et si elle est appelée avec deux flotteurs il appellera à celui qui possède deux paramètres de flotter dans son prototype.

Dans le premier appel pour faire fonctionner les deux arguments passés sont de type int, par conséquent, la fonction avec le premier prototype est appelée; Cette fonction retourne le résultat de la multiplication des deux paramètres. Alors que le deuxième appel passe deux arguments de type float, de sorte que la fonction avec le second prototype est appelé. Celui-ci a un comportement différent: il divise un paramètre par l'autre. Ainsi, le comportement d'un appel d'opérer dépend du type des arguments passés parce que la fonction a été surchargé.

Notez qu'une fonction ne peut pas être surchargé seulement par son type de retour. Au moins un de ses paramètres doivent avoir un type différent.

fonctions inline.
La ligne prescripteur indique au compilateur que la substitution en ligne est préféré au mécanisme d'appel de fonction habituelle pour une fonction spécifique. Cela ne change pas le comportement d'une fonction elle-même, mais est utilisé pour suggérer au compilateur que le code généré par le corps de la fonction est insérée à chaque point de la fonction est appelée, au lieu d'être inséré qu'une seule fois et d'effectuer un appel régulier à elle , ce qui implique généralement une charge supplémentaire en temps d'exécution.

Le format de la déclaration est le suivant:

Nom de type inline (... arguments) {instructions ... }

et l'appel est à l'image de l'appel à toute autre fonction. Vous n'avez pas à inclure le mot-clé inline lors de l'appel de la fonction, uniquement dans sa déclaration.

La plupart des compilateurs déjà optimiser le code pour générer des fonctions inline quand il est plus commode. Cette spécification indique seulement que le compilateur en ligne est préféré pour cette fonction.

Récursivité.
Récursivité est la propriété que les fonctions doivent être appelées par eux-mêmes. Il est utile pour de nombreuses tâches, comme le tri ou de calculer la factorielle d'un nombre. Par exemple, pour obtenir la factorielle d'un nombre (n!) La formule mathématique serait:

 n!  = N * (n-1) * (n-2) * (n-3) ...  * 1


Plus concrètement, 5! (Factorielle de 5) serait:

 5!  = 5 * 4 * 3 * 2 * 1 = 120


et une fonction récursive pour calculer cela en C + + pourrait être:

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20


   

 // factorial calculator #include <iostream> using namespace std; long factorial ( long a) { if (a > 1) return (a * factorial (a-1)); else return (1); } int main () { long number; cout << "Please type a number: " ; cin >> number; cout << number << "! = " << factorial (number); return 0; }

   

  S'il vous plaît entrez un numéro: 9
  9!  = 362880



Remarquez comment en fonction factorielle, nous avons inclus un appel à elle-même, mais seulement si l'argument passé était supérieur à 1, sinon la fonction va effectuer une boucle récursive infinie dans laquelle une fois qu'il est arrivé à 0, il continuerait multipliant par tous les nombres négatifs ( probablement provoquer une erreur de débordement de pile sur l'exécution).

Cette fonction a une limite en raison du type de données que nous avons utilisé dans sa conception (long) pour plus de simplicité. Les résultats donnés ne seront pas valables pour des valeurs bien supérieures à 10! ou 15!, selon le système que vous compilez.

Déclaration de fonctions.
Jusqu'à présent, nous avons défini toutes les fonctions avant l'apparition des premiers appels à eux dans le code source. Ces appels étaient généralement en fonction principale que nous avons toujours laissé à la fin du code source. Si vous essayez de répéter quelques-uns des exemples de fonctions décrites jusqu'ici, mais en mettant la fonction principale avant toutes les autres fonctions qui ont été appelées à l'intérieur, vous aurez très probablement obtenir erreurs de compilation. La raison en est que, pour être en mesure d'appeler une fonction, il doit avoir été déclaré dans un moment antérieur du code, comme nous l'avons fait dans tous nos exemples.

Mais il ya une autre façon d'éviter d'écrire tout le code d'une fonction avant qu'il puisse être utilisé en principal ou dans une autre fonction. Ceci peut être réalisé en déclarant qu'un prototype de la fonction avant d'être utilisé, à la place de l'ensemble de définition. Cette déclaration est plus courte que l'ensemble de définition, mais assez significatif pour que le compilateur pour déterminer son type de retour et les types de ses paramètres.

Sa forme est:

nom du type (argument_type1, argument_type2, ...);

Elle est identique à une définition de fonction, sauf qu'il ne comprend pas le corps de la fonction elle-même (par exemple, les déclarations de fonction que dans les définitions normales sont enfermés dans des accolades {}) et au lieu de cela, nous terminons la déclaration de prototype avec un point-virgule obligatoire (;).

L'énumération paramètre n'a pas besoin d'inclure les identificateurs, mais seulement le type de prescripteurs. L'inclusion d'un nom pour chaque paramètre que dans la définition de la fonction est facultative dans la déclaration de prototype. Par exemple, nous pouvons déclarer une fonction appelée protofunction avec deux paramètres int avec l'une des déclarations suivantes:

 1
 2


   

 int protofunction ( int first, int second); int protofunction ( int , int );



Quoi qu'il en soit, y compris un nom pour chaque variable rend le prototype plus lisible.

 1
 2
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29


   

 // declaring functions prototypes #include <iostream> using namespace std; void odd ( int a); void even ( int a); int main () { int i; do { cout << "Type a number (0 to exit): " ; cin >> i; odd (i); } while (i!=0); return 0; } void odd ( int a) { if ((a%2)!=0) cout << "Number is odd.\n" ; else even (a); } void even ( int a) { if ((a%2)==0) cout << "Number is even.\n" ; else odd (a); }

   

  Tapez un numéro (0 pour quitter): 9
  Nombre est impair.
  Tapez un numéro (0 pour quitter): 6
  Nombre est pair.
  Tapez un numéro (0 pour quitter): 1030
  Nombre est pair.
  Tapez un numéro (0 pour quitter): 0
  Nombre est pair.



Cet exemple n'est en effet pas un exemple d'efficacité. Je suis sûr qu'à ce stade, vous pouvez déjà faire un programme avec le même résultat, mais en utilisant seulement la moitié des lignes de code qui ont été utilisés dans cet exemple. Quoi qu'il en soit cet exemple illustre la façon dont fonctionne le prototypage. En outre, dans cet exemple concret le prototypage d'au moins une des deux fonctions est nécessaire pour compiler le code sans erreurs.

Les premières choses que nous voyons sont la déclaration des fonctions paires et impaires:

 1
 2


   

 void odd ( int a); void even ( int a);



Cela permet à ces fonctions pour être utilisées avant qu'ils ne soient définis, par exemple, en principal, qui est maintenant situé là où certaines personnes trouvent que c'est un endroit plus logique pour le démarrage d'un programme: le début du code source.

Quoi qu'il en soit, la raison pour laquelle ce programme a besoin d'au moins une des fonctions qui doivent être déclarées avant qu'elle soit définie parce que les années impaires il ya un appel pour égaliser et même il ya un appel d'impair. Si aucune des deux fonctions avait été précédemment déclarée, une erreur de compilation se passerait-il, étant donné que soit bizarre ne serait pas visible de même (car il n'a pas encore été déclarée), ou même ne serait pas visible de l'étrange (pour la même raison) .

Avoir le prototype de toutes les fonctions en même temps au même endroit dans le code source se trouve pratique par certains programmeurs, ce qui peut être facilement atteint en déclarant tous les prototypes des fonctions au début d'un programme. 
Publié par Drupal Study