Introduction
Dans ce laboratoire, vous allez apprendre les fonctions en C++. Vous allez apprendre à définir et à appeler des fonctions, et à passer des arguments à des fonctions.
💡 Ce tutoriel est traduit par l'IA à partir de la version anglaise. Pour voir la version originale, vous pouvez cliquer ici
Dans ce laboratoire, vous allez apprendre les fonctions en C++. Vous allez apprendre à définir et à appeler des fonctions, et à passer des arguments à des fonctions.
Parfois, une certaine partie du code doit être utilisée plusieurs fois. Il est préférable de la placer dans une « sous - routine » - fonction, et d'appeler cette fonction plusieurs fois - pour faciliter la maintenance et la compréhension.
Deux parties sont impliquées dans l'utilisation d'une fonction : un appelant qui appelle la fonction, et la fonction appelée. L'appelant passe des arguments à la fonction. La fonction reçoit ces arguments, effectue les opérations programmées dans le corps de la fonction, et renvoie un résultat auquel l'appelant peut accéder.
Supposons que nous devions calculer l'aire d'un cercle plusieurs fois. Il est préférable d'écrire une fonction appelée getArea()
et de la réutiliser selon les besoins.
/* Test Function */
#include <iostream>
using namespace std;
const int PI = 3.14159265;
// Prototype de fonction (Déclaration de fonction)
double getArea(double radius);
int main() {
double radius1 = 1.1, area1, area2;
// Appel de la fonction getArea()
area1 = getArea(radius1);
cout << "area 1 est " << area1 << endl;
// Appel de la fonction getArea()
area2 = getArea(2.2);
cout << "area 2 est " << area2 << endl;
// Appel de la fonction getArea()
cout << "area 3 est " << getArea(3.3) << endl;
}
// Définition de fonction
// Retourne l'aire d'un cercle connaissant son rayon
double getArea(double radius) {
return radius * radius * PI;
}
Sortie :
area 1 est 3.63
area 2 est 14.52
area 3 est 32.67
En C++, vous devez déclarer un prototype de fonction (avant d'utiliser la fonction), et fournir une définition de fonction, avec un corps contenant les opérations programmées.
La syntaxe de la définition de fonction est la suivante :
returnValueType functionName ( parameterList ) {
functionBody ;
}
Un prototype de fonction indique au compilateur l'interface de la fonction, c'est-à-dire le type de retour, le nom de la fonction et la liste des types de paramètres (le nombre et le type des paramètres). La fonction peut maintenant être définie n'importe où dans le fichier. Par exemple,
// Prototype de fonction - placé avant d'utiliser la fonction.
double getArea(double); // sans le nom du paramètre
double getArea(double radius); // les noms de paramètres sont ignorés, mais servent à la documentation
Le type de retour "void"
Sans la nécessité de renvoyer une valeur à l'appelant, vous pouvez déclarer son type de valeur de retour comme void
. Dans le corps de la fonction, vous pouvez utiliser une instruction "return;
" sans valeur de retour pour renvoyer le contrôle à l'appelant.
Paramètres actuels vs. paramètres formels
Dans l'exemple ci-dessus, la variable (double radius)
déclarée dans la signature de getArea(double radius)
est connue sous le nom de paramètre formel. Sa portée est dans le corps de la fonction. Lorsque la fonction est appelée par un appelant, l'appelant doit fournir des paramètres appelés paramètres actuels (ou arguments), dont la valeur est ensuite utilisée pour le calcul effectif. Par exemple, lorsque la fonction est appelée via "area1 = getArea(radius1)
", radius1
est le paramètre actuel, avec une valeur de 1.1
.
Portée des variables locales de fonction et des paramètres
Toutes les variables, y compris les paramètres de fonction, déclarées à l'intérieur d'une fonction sont disponibles uniquement pour la fonction. Elles sont créées lorsque la fonction est appelée et libérées (détruites) après que la fonction ait retourné. Elles sont appelées variables locales car elles sont locales à la fonction et ne sont pas disponibles en dehors de la fonction.
C++ introduit les soi-disant arguments par défaut pour les fonctions. Ces valeurs par défaut seront utilisées si l'appelant omet l'argument actuel correspondant lors de l'appel de la fonction. Les arguments par défaut sont spécifiés dans le prototype de fonction et ne peuvent pas être répétés dans la définition de fonction. Les arguments par défaut sont résolus selon leur position. Par conséquent, ils ne peuvent être utilisés que pour substituer les arguments trailing pour éviter l'ambiguité. Par exemple,
/* Test Function default arguments */
#include <iostream>
using namespace std;
// Prototype de fonction - Spécifiez les arguments par défaut ici
int fun1(int = 1, int = 2, int = 3);
int fun2(int, int, int = 3);
int main() {
cout << fun1(4, 5, 6) << endl; // Aucun argument par défaut
cout << fun1(4, 5) << endl; // 4, 5, 3(par défaut)
cout << fun1(4) << endl; // 4, 2(par défaut), 3(par défaut)
cout << fun1() << endl; // 1(par défaut), 2(par défaut), 3(par défaut)
cout << fun2(4, 5, 6) << endl; // Aucun argument par défaut
cout << fun2(4, 5) << endl; // 4, 5, 3(par défaut)
// cout << fun2(4) << endl;
// erreur : trop peu d'arguments pour la fonction 'int fun2(int, int, int)'
}
int fun1(int n1, int n2, int n3) {
// ne peut pas répéter les arguments par défaut dans la définition de fonction
return n1 + n2 + n3;
}
int fun2(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
Sortie :
15
12
9
6
15
12
C++ introduit la surcharge de fonctions (ou polymorphisme de fonctions), qui vous permet d'avoir plusieurs versions du même nom de fonction, différenciées par la liste de paramètres (nombre, type ou ordre des paramètres). Les fonctions surchargées ne peuvent pas être différenciées par le type de retour (erreur de compilation). La version correspondant à la liste d'arguments de l'appelant sera sélectionnée pour l'exécution. Par exemple,
/* Test Function Overloading */
#include <iostream>
using namespace std;
void fun(int, int, int); // Version 1
void fun(double, int); // Version 2
void fun(int, double); // Version 3
int main() {
fun(1, 2, 3); // version 1
fun(1.0, 2); // version 2
fun(1, 2.0); // version 3
fun(1.1, 2, 3); // version 1 - double 1.1 converti en int 1 (sans avertissement)
// fun(1, 2, 3, 4);
// erreur : aucune fonction correspondante pour l'appel 'fun(int, int, int, int)'
// fun(1, 2);
// erreur : appel de la fonction surchargée 'fun(int, int)' est ambigu
// note : les candidats sont :
// void fun(double, int)
// void fun(int, double)
// fun(1.0, 2.0);
// erreur : appel de la fonction surchargée 'fun(double, double)' est ambigu
}
void fun(int n1, int n2, int n3) { // version 1
cout << "version 1" << endl;
}
void fun(double n1, int n2) { // version 2
cout << "version 2" << endl;
}
void fun(int n1, double n2) { // version 3
cout << "version 3" << endl;
}
Sortie :
version 1
version 2
version 3
version 1
Vous pouvez également passer des tableaux à une fonction. Cependant, vous devez également passer la taille du tableau à la fonction. C'est parce qu'il n'est pas possible de déterminer la taille du tableau à partir de l'argument de tableau à l'intérieur de la fonction appelée. Par exemple,
/* Function to compute the sum of an array */
#include <iostream>
using namespace std;
// Prototype de fonction
int sum(int array[], int size); // Il est également nécessaire de passer la taille du tableau
void print(int array[], int size);
// Testeur
int main() {
int a1[] = {8, 4, 5, 3, 2};
print(a1, 5); // {8,4,5,3,2}
cout << "sum is " << sum(a1, 5) << endl; // sum is 22
}
// Définition de fonction
// Retourne la somme du tableau donné
int sum(int array[], int size) {
int sum = 0;
for (int i = 0; i < size; ++i) {
sum += array[i];
}
return sum;
}
// Affiche le contenu du tableau donné
void print(int array[], int size) {
cout << "{";
for (int i = 0; i < size; ++i) {
cout << array[i];
if (i < size - 1) {
cout << ",";
}
}
cout << "}" << endl;
}
Sortie :
{8,4,5,3,2}
sum is 22
Il existe deux manières dont un paramètre peut être passé à une fonction : le passage par valeur et le passage par référence.
Passage par valeur
En passage par valeur, une "copie" de l'argument est créée et passée à la fonction. La fonction appelée travaille sur la "clône" et ne peut pas modifier la copie d'origine. En C/C++, les types fondamentaux (tels que int
et double
) sont passés par valeur.
/* Fundamental types are passed by value into Function */
#include <iostream>
using namespace std;
// Prototype de fonction
int inc(int number);
// Testeur
int main() {
int n = 8;
cout << "Avant l'appel de la fonction, n est " << n << endl; // 8
int result = inc(n);
cout << "Après l'appel de la fonction, n est " << n << endl; // 8
cout << "result est " << result << endl; // 9
}
// Définition de fonction
// Retourne number+1
int inc(int number) {
++number; // Modifie le paramètre, sans effet sur l'appelant
return number;
}
Sortie :
Avant l'appel de la fonction, n est 8
Après l'appel de la fonction, n est 8
result est 9
Passage par référence
D'un autre côté, en passage par référence, une référence de la variable de l'appelant est passée à la fonction. En d'autres termes, la fonction appelée travaille sur les mêmes données. Si la fonction appelée modifie le paramètre, la même copie de l'appelant sera également modifiée. En C/C++, les tableaux sont passés par référence. C/C++ ne permet pas aux fonctions de retourner un tableau.
/* Function to increment each element of an array */
#include <iostream>
using namespace std;
// Prototype de fonction
void inc(int array[], int size);
void print(int array[], int size);
// Testeur
int main() {
int a1[] = {8, 4, 5, 3, 2};
// Avant l'incrémentation
print(a1, 5); // {8,4,5,3,2}
// Effectuer l'incrémentation
inc(a1, 5); // Le tableau est passé par référence (ayant un effet de bord)
// Après l'incrémentation
print(a1, 5); // {9,5,6,4,3}
}
// Définition de fonction
// Incrémente chaque élément du tableau donné
void inc(int array[], int size) { // array[] n'est pas const
for (int i = 0; i < size; ++i) {
array[i]++; // effet de bord
}
}
// Affiche le contenu du tableau donné
void print(int array[], int size) {
cout << "{";
for (int i = 0; i < size; ++i) {
cout << array[i];
if (i < size - 1) {
cout << ",";
}
}
cout << "}" << endl;
}
Sortie :
{8,4,5,3,2}
{9,5,6,4,3}
const
Utilisez const
dès que possible lors du passage de références car cela vous empêche de modifier involontairement les paramètres et vous protège contre de nombreuses erreurs de programmation.
Dans une recherche linéaire, la clé de recherche est comparée avec chaque élément du tableau de manière linéaire. S'il y a une correspondance, elle renvoie l'index de l'élément correspondant ; sinon, elle renvoie -1. La recherche linéaire a une complexité de O(n).
/* Search an array for the given key using Linear Search */
#include <iostream>
using namespace std;
int linearSearch(const int a[], int size, int key);
int main() {
const int SIZE = 8;
int a1[SIZE] = {8, 4, 5, 3, 2, 9, 4, 1};
cout << linearSearch(a1, SIZE, 8) << endl; // 0
cout << linearSearch(a1, SIZE, 4) << endl; // 1
cout << linearSearch(a1, SIZE, 99) << endl; // 8 (non trouvé)
}
// Search the array for the given key
// If found, return array index [0, size-1]; otherwise, return size
int linearSearch(const int a[], int size, int key) {
for (int i = 0; i < size; ++i) {
if (a[i] == key) return i;
}
// a[0] = 1;
// Cela entraînera une erreur car a[] est const, ce qui signifie en lecture seule
return -1;
}
Sortie :
0
1
-1
Vous pouvez passer un paramètre de type fondamental par référence via le paramètre de référence désigné par &
.
/* Test Pass-by-reference for fundamental-type parameter
via reference declaration */
#include <iostream>
using namespace std;
int squareByValue (int number); // Pass-by-value
void squareByReference (int &number); // Pass-by-reference
int main() {
int n1 = 8;
cout << "Avant l'appel, la valeur est " << n1 << endl; // 8
cout << squareByValue(n1) << endl; // pas d'effet de bord
cout << "Après l'appel, la valeur est " << n1 << endl; // 8
int n2 = 9;
cout << "Avant l'appel, la valeur est " << n2 << endl; // 9
squareByReference(n2); // effet de bord
cout << "Après l'appel, la valeur est " << n2 << endl; // 81
}
// Passer le paramètre par valeur - pas d'effet de bord
int squareByValue (int number) {
return number * number;
}
// Passer le paramètre par référence en le déclarant comme référence (&)
// - avec effet de bord sur l'appelant
void squareByReference (int &number) {
number = number * number;
}
Sortie :
Avant l'appel, la valeur est 8
64
Après l'appel, la valeur est 8
Avant l'appel, la valeur est 9
Après l'appel, la valeur est 81
###2.8 Fonctions mathématiques
C++ fournit de nombreuses fonctions mathématiques couramment utilisées dans la bibliothèque <cmath>
sin(x), cos(x), tan(x), asin(x), acos(x), atan(x) :
Prennent un type d'argument et un type de retour de float, double, long double.
sinh(x), cosh(x), tanh(x) :
Fonctions trigonométriques hyperboliques.
pow(x, y), sqrt(x) :
Puissance et racine carrée.
ceil(x), floor(x) :
Renvoient l'entier supérieur et l'entier inférieur du nombre à virgule flottante.
fabs(x), fmod(x, y) :
Valeur absolue et modulo en virgule flottante.
exp(x), log(x), log10(x) :
Fonctions exponentielles et logarithmiques.
Le fichier d'en-tête cstdlib
(porté de stdlib.h
de C) fournit une fonction rand()
, qui génère un nombre entier pseudo-aléatoire compris entre 0 et RAND_MAX
(inclus).
/* Test Random Number Generation */
#include <iostream>
#include <cstdlib> // pour rand(), srand()
#include <ctime> // pour time()
using namespace std;
int main() {
// rand() génère un nombre aléatoire dans [0, RAND_MAX]
cout << "RAND_MAX est " << RAND_MAX << endl; // 32767
// Générer 10 nombres pseudo-aléatoires entre 0 et 99
// sans initialiser le générateur.
// Vous obtiendrez la même séquence chaque fois que vous exécuterez ce programme
for (int i = 0; i < 10; ++i) {
cout << rand() % 100 << " "; // nécessite le fichier d'en-tête <cstdlib>
}
cout << endl;
// Initialiser le générateur de nombres aléatoires avec l'heure actuelle
srand(time(0)); // nécessite les fichiers d'en-tête <cstdlib> et <ctime>
// Générer 10 nombres pseudo-aléatoires
// Vous obtiendrez une séquence différente à chaque exécution,
// car l'heure actuelle est différente
for (int i = 0; i < 10; ++i) {
cout << rand() % 100 << " "; // nécessite le fichier d'en-tête <cstdlib>
}
cout << endl;
}
Sortie :
RAND_MAX est 2147483647
83 86 77 15 93 35 86 92 49 21
29 0 83 60 22 55 97 80 68 87
- name: check if keyword exist
script: |
#!/bin/bash
grep -i 'rand' /home/labex/Code/test.cpp
error: Oops! We find that you didn't use "rand()" method in "test.cpp".
timeout: 3
Les avantages d'utiliser des fonctions sont les suivants :