Big Tuto : Apprenez le C++

Chapitre 8 : Les fonctions - 3ème partie

Tutoriel présenté par : Robert Gillard (Gondulzac)
Date d'écriture : 9 janvier 2016
Date de révision : -

      Préliminaires 

   Nous avons déjà bien avancé dans l'étude des fonctions mais il nous reste encore plusieurs points importants à découvrir. wink Nous allons d'ailleurs commencer sans plus tarder. cheeky

   Je vous rappelle que vous pourrez trouver les corrigés des exercices proposés dans le chapitre 7 au bas de ce chapitre. angel

 

Retrouvez les projets complets de ce chapitre :

  

Pour une raison de commodité personnelle, tous les projets de ce chapitre sont de nouveau compilés avec Visual Studio 2013.

   1 – Passage de tableaux à des fonctions

   Nous avons vu que la manière normale de gérer les arguments d'une fonction était d'utiliser la technique du passage par valeurs. Dans ce cas, la fonction travaille avec des copies locales des variables au lieu des variables elles-mêmes.

   Dans le cas où ces variables devaient être modifiées à l'intérieur d'une fonction, nous avons utilisé la technique du passage par références où la modification des valeurs se faisait par l'intermédiaire des adresses de ces variables. wink

   Si maintenant nous devons passer un tableau de type ''char'' à une fonction, nous avons le choix de travailler avec des variables indicées ou à l'aide de pointeurs.

   Attention : passer un tableau à une fonction est une opération lourde qu'il convient d'éviter, surtout si le tableau est quelque peu conséquent.

   Dans le chapitre 4 , nous avons dit que le nom d'un tableau (sans la paire de crochets qui le suit) était un pointeur sur le premier élément du tableau, ce qui avait à l'époque suscité une certaine polémique dans le forum du site. cheeky Mais il se fait, en effet, que dans la plupart des expressions, on utilise réellement un pointeur sur le premier élément d'un tableau. wink Dans ces cas, c'est le compilateur qui substitue automatiquement un pointeur sur le premier élément. Il s'ensuit que les opérations effectuées sur des tableaux sont souvent en réalité des opérations sur des pointeurs. 
   Une telle implication se vérifie lorsque l'on utilise un tableau pour initialiser une variable définie par le spécificateur de type ''auto'', dans ce cas le type déduit est un pointeur, pas un tableau.

   Un petit exemple va éclairer notre propos :

   int tab[] = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19}; //On déclare un tableau de 10 entiers.
   auto tab2 (tab); //tab2 est un pointeur d'entier qui pointe sur le premier élément de tab (nous venons de dire plus haut que le type déduit par ''auto'' est un pointeur).

 

   Quoique tab soit un tableau de 10 entiers, quand nous l'utilisons pour initialiser le tableau, le compilateur traite cette initialisation comme si nous avions écrit :

auto tab2(&tab[0]);

   Et il est bien clair que tab2 possède le type int* (pointeur sur un entier). wink

 

       1.1 – Maniement d'un tableau dans une fonction à l'aide d'indices

   Nous allons voir un exemple simple de maniement d'un tableau de caractères dans une fonction à l'aide d'indices :

 

//Projet 054Fonctions17
//Passage d'un tableau de char dans une fonction
//Utilisation d'indices
#include <iostream>
#include <conio.h>
 
using namespace std;
using uint = unsigned int;
 
// Déclaration de la fonction LisMot()
void LisMot(const char tab[]); //En lecture uniquement
 
 
int main()
{
char chaine[20];
 
cout << "Lecture de caracteres dans une fonction" << endl << endl;
cout << "Entrez un mot : ";
cin >> chaine;
 
LisMot(chaine);
 
_getch();
return 0;
}
 
void LisMot(const char tableau[])
{
//Lecture des caractères
uint ctr(0);
 
while (tableau[ctr])
cout << tableau[ctr++];
cout << endl;
}

 

   Ce qui donne dans la console :

 

   Un tableau de caractères const char est passé à la fonction LisMot(). Je vous conseille d'utiliser le mot-clé const chaque fois que les éléments d'un tableau de char, string ou vector ne doivent pas être modifiés dans une fonction. wink

   Notre fonction LisMot() ne fait en effet que lire un mot entré au clavier. Une variable ''ctr'' de type unsigned int est initialisée à 0 comme compteur au début de la fonction. Comme nous savons qu'un tableau de char se termine par un caractère de fin de chaîne '\0' (voir chapitre 4 wink), nous pouvons utiliser la condition while (tableau[ctr]) qui est toujours vraie jusqu'à ce que l'on atteigne le caractère de fin de chaîne. La fonction rend alors la main au programme principal qui dans ce cas est la fonction main()angel

 

       1.2 – Maniement d'un tableau dans une fonction à l'aide de pointeurs

   Nous voyons maintenant un programme semblable qui utilise des pointeurs :
 

//Projet 055Fonctions18
//Passage d'un tableau de char dans une fonction
//Utilisation de pointeurs
#include <iostream>
#include <conio.h>
 
using std::cout;
using std::endl;
using uint = unsigned int;
 
// Déclaration de la fonction LisChaine()
void LisChaine(const char *ptr); //En lecture uniquement
 
 
int main()
{
const char arme[] { "Lame d'acier enchantee de la Terreur de Voileronce" };
 
cout << "Lecture de caracteres dans une fonction" << endl;
cout << "Utilisation de pointeurs" << endl << endl;
 
const char *ptr = arme;
LisChaine(arme);
 
_getch();
return 0;
}
 
 
void LisChaine(const char *ptr)
{
//Lecture des caractères
while (*ptr)
cout << *ptr++;
 
cout << endl;
}

 

Avec comme résultat dans la console :

 

   Premièrement, si vous regardez les directives ''using'', vous vous apercevrez que la directive ''using namespace std'' a été remplacée par les deux directives using std::cout et using std::endl.
   Pourquoi ceci ? surprise Et bien, il s'agit simplement d'une forme différente de ''using namespace std'' qui elle, reprend toutes les directives ''using'' dans l'espace de nom ''std''. En omettant ''using namespace std'' vous devrez définir chaque espace de nom utilisé dans un programme, c'est ce que nous avons fait ici. wink

   Cette parenthèse étant faite, vous voyez que dans la déclaration de la fonction LisChaine(), nous passons un pointeur de type ''const char'' en argument. Dans la fonction main(), nous faisons pointer un pointeur de même type sur le début de la chaîne ''arme'' et dans l'implémentation de la fonction LisChaine(), nous utilisons le même principe que lors de l'exemple précédent en quittant la boucle dès que le pointeur rencontre le caractère de fin de chaîne '\0'.

 

       1.3 – Utilisation et renvoi de plusieurs pointeurs

   Nous allons présenter un troisième exemple en ce qui concerne le passage de tableau de char dans une fonction. Dans le chapitre 5, projet 032Cstyle4, nous présentions la manière d'utiliser deux pointeurs pour calculer la longueur d'un tableau de char mais le code se trouvait en entier dans la fonction main(). Cette fois nous allons intégrer le code dans une fonction avec le retour du résultat dans la fonction principale. wink

 

//Projet 056Fonctions19
//Passage d'un tableau de char dans une fonction
//Calcul de la longueur du tableau à l'aide de 2 pointeurs et retour du résultat
#include <iostream>
#include <conio.h>
 
using std::cout;
using std::endl;
using uint = unsigned int;
 
// Déclaration de la fonction LongueurChaine()
uint LongueurChaine(const char *ptr1, const char *ptr2);
 
 
int main()
{
char chaine[]{ "Il etait une fois... Roswyn !?" };
 
cout << "Une fonction qui calcule la longueur d'une chaine" << endl;
cout << "Utilisation de pointeurs" << endl << endl;
 
const char *ptr1 = nullptr;
const char *ptr2 = nullptr;
uint longChaine(0);
 
//On fait pointer les deux pointeurs sur le début de la chaîne
ptr1 = ptr2 = chaine;
cout << chaine << endl;
 
longChaine = LongueurChaine(ptr1, ptr2);
cout << "La longueur de la chaine est de " << longChaine << " caracteres" << endl;
 
_getch();
return 0;
}
 
 
uint LongueurChaine(const char *ptr1, const char *ptr2)
{
while (*ptr2)
*ptr2++;
 
return ptr2 - ptr1;
}

 

   Ce qui affiche dans la console :

 

   Heu... indecision C'est vrai que je devrais oublier le prénom de cette Damoiselle, sinon les mauvaises langues diront que je l'ai personnellement connue... laugh

   Bien, on passe aux choses sérieuses ! wink Cette fois, nous passons les deux pointeurs dans la déclaration de la fonction LongueurChaine(). Dans la fonction main(), nous définissons un tableau de char et nous faisons pointer les deux pointeurs sur le début du tableau. Nous définissons une variable longChaine de type unsigned int que nous initialisons à 0 et nous appelons la fonction LongueurChaine() à laquelle les deux pointeurs sont passés. L'implémentation de la fonction LongueurChaine() est connue, cette fonction retourne la différence des contenus des adresses pointées par les pointeurs de fin et de début de chaîne. Cette différence est égale à la longueur de la chaîne.

 

   Exercice 1 :

   Modifiez le programme précédent pour que la fonction retourne le produit des valeurs décimales des premier et dernier caractères de la chaine "Il etait une fois... Roswyn !?", c'est-à-dire le produit de la valeur décimale du caractère ''I'' par la valeur décimale du caractère ''?''.

   Vous devrez obtenir ces valeurs décimales à partir des pointeurs *ptr1 et *ptr2 dans la fonction.
   A titre d'information, ce produit est égal à 4599wink

 

        1.4 – Utilisation de conventions de la "Standard Library"

  Si nous regardons le code de la fonction LisChaine() de notre projet 055Fonctions18 :

 

void LisChaine(const char *ptr)
{
//Lecture des caractères
 
while (*ptr)
cout << *ptr++;
-----

 

   ... nous nous apercevons que nous passons un pointeur à la fonction et que pour afficher la chaîne, l'itération se fait par ce pointeur. Rien ne nous empêche d'utiliser les membres begin() et end() de la Standard Library, se référant à la première position et à la dernière plus une position (one past the end) d'un tableau (pour rappel, voir Chapitre 5 – 1.3 Introduction aux itérateurs wink).

   Nous pourrions donc réécrire cette fonction traitant un tableau d'entiers de la manière suivante :

 

void LisTab(int *ptrdebut, int *ptrfin)
{
while (ptrdebut != ptrfin)
cout << *ptrdebut++;
}

 

   Et le reste du programme :

 

//Projet 057Fonctions20
//Passage d'un tableau de char dans une fonction
//Utilisation des membres begin() et end() de la Standard Library
#include <iostream>
#include <conio.h>
 
using namespace std;
using std::cout;
using std::endl;
//using uint = unsigned int;
 
// Déclaration de la fonction LisTab()
void LisTab(int *debut, int *fin);
 
 
int main()
{
int tab[] = { 3, -2, -9, 6, 12, 21, -17, -11, 7, 1 };
cout << "Une fonction qui lit les valeurs entieres d'un tableau" << endl;
cout << "Utilisation des membres begin() et end() de la Standard Library" << endl << endl;
 
//*debut est un pointeur sur le début du tableau
int *debut = begin(tab);
 
//*fin est un pointeur sur l'élément suivant la fin du tableau
int *fin = end(tab);
 
LisTab(debut, fin);
 
_getch();
return 0;
}

 

   Et le résultat dans la console :

 

   Dans la fonction main(), nous définissons un tableau de 10 entiers (nombres positifs et négatifs).
   On utilise les membres begin() et end() de la SL pour obtenir un pointeur *debut sur le premier élément du tableau et un second pointeur *fin pointant sur l'élément suivant le dernier élément du tableau (one past the end). On appelle ensuite la fonction lisTab() à laquelle on passe les pointeurs de début et fin de tableau. wink

   Dans la fonction LisTab(), nous incrémentons le pointeur *debut jusqu'à la fin du tableau et on affiche tous les éléments du tableau. L'affichage se fait dans la fonction.

   Voyons maintenant le petit exercice suivant :

 

   Exercice 2 :

   Modifiez le programme précédent afin de retourner toutes les valeurs négatives du tableau dans la fonction principale.

   Vous devriez avoir le résultat suivant dans la console : 


   Un second exemple d'utilsation des conventions de la Standard Library serait d'utiliser un itérateur pour parcourir tous les éléments d'une chaîne de caractères dans une fonction. C'est ce que nous allons voir ici.
   En nous référant au projet 039iterator2 du chapitre 5, nous allons cette fois écrire une fonction qui transforme tous les caractères minuscules d'une chaîne de caractères en majuscules et qui renvoie celle-ci dans la fonction main() :

 

//Projet 058Fonctions21
//Une fonction qui transforme les caractères minuscules d'une chaîne en majuscules
//Utilisation d'un iterateur de type string::const_iterator
#include <iostream>
#include <string>
#include <cctype>
 
using namespace std;
 
string Majuscules(string chaine, string::const_iterator it);
 
 
int main()
{
string laoTseu("Le plus long voyage commence par un premier pas !");
string::const_iterator iter;
cout << "Le plus long voyage commence par un premier pas !" << endl << endl;
 
cout << "Appel de la fonction 'Majuscules(string, string::const_iterator)'" << endl;
laoTseu = Majuscules(laoTseu, iter);
cout << laoTseu;
 
cin.get();
return 0;
}
 
 
string Majuscules(string ch, string::const_iterator it)
{
cout << "On utilise la fonction 'toupper' de la librairie cctype" << endl;
cout << "et on parcourt la chaine a l'aide d'un iterateur" << endl;
 
for (auto it = ch.begin(); it != ch.end(); ++it)
*it = toupper(*it); //Transforme les caractères en majuscules
 
cout << endl;
return ch;
}

 

   Dans la fonction main(), nous définissons une chaîne de type ''string'' et dénommée "Le plus long voyage commence par un premier pas !" Et ceci me fait dire que nous avons déjà fait quelques pas dans notre voyage à travers le C++, mais il y en aura encore beaucoup d'autres, nous ne sommes pas encore au bout, loin de là ! laugh

   Bien, nous définissons ensuite un itérateur, et plus précisément un const::string iterator (voir chapitre 5 – Types d'itérateurs wink). A l'appel de la fonction Majuscules(), on passe la chaîne laoTseu et l'itérateur en paramètres.

   La fonction Majuscules() appelle elle-même la fonction ''toupper'' du fichier include ''cctype'' (voir Chapitre 5 – Fonctions de la librairie cctype) qui transforme chaque caractère minuscule de la chaîne en caractère majuscule.
   Le résultat de la transformation des caractères est alors renvoyé à la variable ''laoTseu'' dans la fonction main().

   Rappel : un itérateur se comportant comme un pointeur, il doit être déréférencé.

   Et le résultat dans la console : 


        1.5 – Utilisation d'une boucle for (C++ 11) pour la lecture ou l'écriture d'une chaîne de type string dans une fonction

    Dans le projet 036Strings4 du chapitre 5, nous avions montré une forme concise de l'implémentation d'une boucle ''for'' que la nouvelle norme du C++ 11 recommande pour la lecture ou la modification d'une chaîne de type ''string''. Nous avions présenté cette nouvelle forme dans le fichier main() lui-même mais nous allons ici l'appliquer à une fonction.

   Rappelons la forme syntaxique de la boucle :

   for (déclaration : expression)
           Instruction(s)

 

   Dans cet exemple, nous allons passer une chaîne de caractères à une fonction et la lecture de la chaîne se fera à l'aide de la nouvelle forme de la boucle ''for''.

   La fonction renverra tous ses caractères dans une autre chaîne.  

 

//Projet 059Fonctions19
//Une fonction qui lit une chaîne de caractères
//à l'aide de la boucle for de la nouvelle norme c++ 11
//et qui renvoie tous les caractères dans une seconde chaîne
#include <iostream>
#include <string>
 
 
using namespace std;
 
string LisChaine(string rasoir);
 
 
int main()
{
string arme("Katana tranchant du Samourai du Pont des Etoiles");
//On déclare une seconde chaîne vide
string chaine;
 
cout << endl;
cout << "Appel de la fonction 'LisChaine(string)'" << endl;
chaine = LisChaine(arme);
//On affiche tous les caractères renvoyés dans la seconde chaîne
cout << chaine << endl;
 
cin.get();
return 0;
}
 
 
string LisChaine(string rasoir)
{
string chaine;
cout << "On utilise la boucle 'for' du C++ 11" << endl;
 
//On lit tous les caractères de la chaîne arme et on les transfère dans la nouvelle.
for (auto c : rasoir)
chaine += c;
 
return chaine;
}

 

   Je pense que les commentaires du programme se suffisent à eux-mêmes. Notez que le type ''auto'' de la variable ''c'' lui confère automatiquement le type charwink

   La lecture de la boule ''for'' doit se lire :

   Extraire chaque caractère de la chaîne ''rasoir'' et l'écrire dans la nouvelle chaîne ''chaine''.
   Pour terminer, remarquez la forme d'addition ''+='' qui s'applique également au type ''string''.


    Ce programme affiche dans la console :

 

   Nous allons voir un second exemple de la nouvelle forme d'utilisation de la boucle ''for'' en renvoyant les caractères de la chaîne du projet précédent, transformés en majuscules. Ce projet, s'il remplit la même tâche que le projet 058Fonctions21, n'utilisera pas, quant à lui, les méthodes begin() et end() de la Standard Library. Vous voyez que la richesse du langage C++ nous permet, dans de nombreux cas, d'obtenir un même résultat à l'aide de fonctionnalités différentes. cheeky

   Projet 060Fonctions23 : Je n'écris ici que l'implémentation de la fonction LisChaine() du programme précédent, le reste étant tout-à-fait identique au projet 059Fonctions19.

 
string LisChaine(string rasoir)
{
string chaine;
cout << "On utilise la boucle 'for' du C++ 11" << endl;
 
for (auto &c : rasoir)
{
//On transforme tous les caractères de la chaîne 'arme' en majuscules
c = toupper(c);
chaine += c;
}
 
return chaine;
}

 

   Rien de spécial dans cette fonction sauf que la chaîne devant être modifiée dans la fonction, ''&c'' est une référence de la variable ''c'' de type char.

   Ce qui affiche dans la console :

 
   Bien, je crois que c'est assez d'exemples pour ce chapitre mais je vous propose quand-même un nouveau petit challenge que, j'en suis certain, vous vous hâterez de réaliser... laugh
 

     Un petit challenge ( Exercice 3 )

   En vous inspirant des exemples de ce chapitre et en utilisant la fonction ''isspace()'' du tableau des fonctions''cctype'' du chapitre 5, écrivez une fonction qui transforme tous les espaces de la chaîne ''Katana tranchant du Samourai du Pont des Etoiles'' par un caractère de soulignement. Ce caractère est char(95). La nouvelle chaîne sera renvoyée et affichée dans la fonction main().
 
   Exercice 3_1 : Réalisez cet exercice en utilisant un itérateur dans la fonction.
   Exercice 3_2 : Utilisez un indice de 0 à chaine.size() - 1.

   Résultat à obtenir dans les deux cas: ''Katana_tranchant_du_Samourai_du_Pont_des_Etoiles''.


     2 – Corrigés des exercices du chapitre 7

   Exercice 1 : Il fallait modifier le projet 050Fonctions13, en passant des pointeurs sur des valeurs constantes à la place de références.
 
Déclaration de la fonction :
 
// Déclaration de la fonction Somme
uint Somme(const uint *nombre1, const uint *nombre2);
 
 
Appel à la fonction dans le main() :
 
resultat = Somme(&nb1, &nb2);
 
 
Fonction Somme() :
 
uint Somme(const uint *valeur1, const uint *valeur2)
{
return *valeur1 + *valeur2;
} 

 

   Il n'y avait rien de difficile dans cet exercice. Vous pouvez faire une comparaison avec le projet 048Fonctions11 : permutation de deux nombres à l'aide de pointeurs. wink


   Exercice 2 : Il fallait modifier le projet de notre exemple ludique (projet 052Fonctions15) en renvoyant plusieurs valeurs sous forme de références à la place de pointeurs.

 

Déclaration de la fonction :
 
// Déclaration de la fonction Survivants()
uint Survivants(uint &nb_fantassins, uint &nb_archers);
 
 
Appel à la fonction dans le main() :
 
nb_survivants = Survivants(nb_fantassins, nb_archers);
 
 
Fonction Survivants() :
 
uint Survivants(uint &nb_fantassins, uint &nb_archers)
{
uint nb_fantassins_perdus(0);
uint nb_archers_perdus(0);
 
cout << "ENTREZ IMPERATIVEMENT DES NOMBRES COMPRIS ENTRE ( 0 - 10 )" << endl << endl;
 
cout << "Combien de fantassins avez-vous perdus ";
cin >> nb_fantassins_perdus;
 
while ((nb_fantassins_perdus < 0) || (nb_fantassins_perdus > 10))
{
cout << "Entrez un nb >=0 ou <=10 ";
cin >> nb_fantassins_perdus;
}
 
cout << endl;
cout << "Combien d'archers avez-vous perdus ";
cin >> nb_archers_perdus;
 
while ((nb_archers_perdus < 0) || (nb_archers_perdus > 10))
{
cout << "Entrez un nb >=0 ou <=10 ";
cin >> nb_archers_perdus;
}
 
 
nb_fantassins -= nb_fantassins_perdus;
nb_archers -= nb_archers_perdus;
 
return nb_fantassins + nb_archers;
} 

 

   Il n'y avait rien de très difficile dans cet exercice. Vous pouvez faire une comparaison avec le projet 049Fonctions12 : permutation de deux nombres, à l'aide de références.


   Pour ce genre d'exercices où vous devez passer soit des pointeurs soit des références à une fonction, retenez que :
- Dans le cas des pointeurs, vous passerez les pointeurs en arguments lors de la déclaration et de la définition de la fonction tandis qu'à l'appel de cette fonction vous passerez les adresses sur lesquelles les pointeurs pointent.
- Dans le cas des références, vous passerez les références en arguments lors de la déclaration et de la définition de la fonction tandis qu'à l'appel de cette fonction vous passerez simplement le nom des variables auxquelles les références se réfèrent.

   Corrigé de notre petit challenge du chapitre 7 :

   Cet exercice demandait de modifier le projet 053Fonctions16 en ajoutant les positions de toutes les occurrences du caractère 'o' dans la chaîne ''Nabuchodonosor''

 

   Premier corrigé :

   Exercice 3_1 : Par le passage d'un tableau supplémentaire à la fonction avec retour du tableau à la fonction principale. Les commentaires suivront le code.  

 

//Projet Chap7Exercice_3_1
//Pointeurs et références dans les fonctions
//Une fonction qui renvoie un tableau
#include <iostream>
#include <conio.h>
#include <string>
 
using namespace std;
using uint = unsigned int;
 
// Déclaration de la fonction Recherche_char()
string::size_type Recherche_char(const string &chaine, const char c, string::size_type &nb_occurrences, uint tab[]);
 
 
int main()
{
//La chaine sur laquelle se porte la recherche
const string chaine{ "Nabuchodonosor" };
 
//Le caractère à rechercher
const char c = 'o';
 
//Le nb d'occurrences de 'o' dans "Nabuchodonosor"
string::size_type compteur(0);
uint tab[10];
 
Recherche_char(chaine, c, compteur, tab);
 
cout << endl;
cout << "Il y a " << compteur << " 'o' dans " << chaine << endl;
cout << "Le premier 'o' se trouve en position " << tab[0] << endl << endl;
 
for (uint i = 0; i < compteur; ++i)
cout << "Un caractere " << c << " se trouve en position " << tab[i] << " dans" << chaine << endl;
 
_getch();
return 0;
}
 
 
string::size_type Recherche_char(const string &chaine, const char caract, string::size_type &nb_occurrences, uint tab[])
{
for (decltype(chaine.size()) i = 0; i != chaine.size(); ++i)
{
//Si un caractère 'o' est trouvé
if (chaine[i] == caract)
{
//On place sa position dans le tableau passé à la fonction
tab[nb_occurrences] = i;
 
//et on incrémente l'indice du tableau
++nb_occurrences;
}
 
}
//On retourne le tableau complet.
return tab[nb_occurrences];
}

 

   Dans la déclaration de notre fonction Recherche_char(), nous passons un nouveau tableau tab[] de type unsigned int.


   Ce tableau est initialisé dans la fonction main() et pourra contenir un maximum de 10 éléments. Ce chiffre est choisi pour avoir un tableau le plus petit possible à passer à la fonction (nous savons qu'il n'y a pas 10 caractères 'o' dans le nom de notre monarque Babylonien wink), mais nous verrons plus tard que dans l'ignorance de la grandeur d'un tableau, nous préférerons utiliser un vector.


   Nous faisons ensuite appel à la fonction Recherche_char() en lui passant le tableau tab en argument supplémentaire. Remarquez qu'ici nous n'avons plus besoin de la variable pos1 puisque, pour trouver la première position, nous allons utiliser la valeur de tab[0] du tableau retourné par la fonction. wink


   Nous voyons donc que la définition de notre fonction Recherche_char() s'en trouve simplifiée.

   En effet, pour la raison citée ci-dessus, nous pouvons nous débarrasser de la variable position1 ainsi que du test sur l'égalité de cette variable avec chaine.size() qui n'ont plus d'utilité. Après avoir vérifié qu'un caractère recherché se trouve dans le tableau ''chaine'', on incrémente la variable nb_occurrences qui, nous le savons, va contenir le nombre de caractères 'o' contenus dans le nom du Grand Roi.

   Je suppose que vous aussi, vous aviez un résultat semblable ? indecision

 

   Second corrigé
   Exercice 3_2 : Par le passage d'un pointeur *ptrTab à la fonction Recherche_char() qui doit retourner ce pointeur dans la fonction main(). Comme pour l'exercice précédent, nous écrirons d'abord le code de cet exercice et donnerons les explications nécessaires par la suite. 

 

//Projet Chap7Exercice_3_2
//Pointeurs et références dans les fonctions
//Une fonction qui renvoie un pointeur sur une chaîne
#include <iostream>
#include <conio.h>
#include <string>
 
using namespace std;
using uint = unsigned int;
 
// Déclaration de la fonction Recherche_char()
string::size_type Recherche_char(const string &chaine, const char c, string::size_type &nb_occurrences, uint *ptrTab);
 
 
int main()
{
//La chaine sur laquelle se porte la recherche
const string chaine{ "Nabuchodonosor" };
 
 
//Le caractère à rechercher
const char c = 'o';
 
//Le nb d'occurrences de 'o' dans "Nabuchodonosor"
string::size_type compteur(0);
 
//Déclaration d'un tableau de 10 uint et un pointeur sur le 1er élément du tableau
uint tab[10];
uint *ptrTab = tab;
 
Recherche_char(chaine, c, compteur, ptrTab);
cout << endl;
cout << "Il y a " << compteur << " 'o' dans " << chaine << endl;
cout << "Le premier 'o' se trouve en position " << *ptrTab << endl << endl;
 
for (uint i = 0; i < compteur; ++i)
cout << "Un caractere " << c << " se trouve en position " << *ptrTab++ << "dans " << chaine << endl;
 
_getch();
return 0;
}
 
 
string::size_type Recherche_char(const string &chaine, const char caract, string::size_type &nb_occurrences, uint *ptr)
{
uint tab[10];
*ptr = tab[0];
 
for (decltype(chaine.size()) i = 0; i != chaine.size(); ++i)
{
if (chaine[i] == caract)
{
//Le tableau contiendra les positions de toutes les occurences de 'o'
//dans la chaîne
tab[nb_occurrences] = i;
 
//Le pointeur déréférencé prend la valeur des positions de chaque
//occurrence
*ptr = tab[nb_occurrences];
 
//On incrémente l'indice du tableau
++nb_occurrences;
 
//On incrémente le pointeur à chaque nouveau caractère trouvé
ptr++;
}
}
 
//On remet le pointeur sur le 1er élément du tableau
*ptr = tab[0];
return *ptr;
} 

 

   Nous constatons déjà que, comme dans l'exercice précédent, nous pouvons nous passer de la variable pos1 de la fonction main(), et de la variable position1 de la fonction Recherche_char().


   Dans la déclaration de la fonction Recherche_char(), nous ajoutons cette fois un pointeur *ptrTab déclaré dans la fonction main() et que nous faisons pointer sur un tableau tab[10] qui sera lui aussi destiné à recevoir les positions des occurrences du caractère 'o' dans la chaîne ''Nabuchodonosor''.


   A l'appel de la fonction Recherche_char() dans main(), nous passons le pointeur *ptrTab en paramètre.

 

   Dans la définition de la fonction Recherche_char(), nous faisons pointer ce pointeur sur le premier élément d'un tableau, soit tab[0]. Dès qu'un caractère 'o' est trouvé dans la chaîne, le pointeur déréférencé prend la valeur de la position de la nouvelle occurrence, et le pointeur est incrémenté. wink

   Lorsque la fin de chaîne a été rencontrée, on remet le pointeur sur le premier élément du tableau et le pointeur est retourné à la fonction main() où se fait l'affichage du résultat.

   Et dans les deux cas vous auriez dû obtenir quelque chose de ce genre dans la console cheeky :

 

 

   Voilà pour ce qui est de ce petit challenge. J'espère qu'il vous aura permis de mieux appréhender l'utilisation des pointeurs et des tableaux dans les fonctions. wink

Comme nous l'avions déjà signalé lors du chapitre 3, si vous ne connaissez pas le nombre d'éléments que contiendra une liste, créez un vector sinon utilisez les tableaux. Dans le prochain chapitre nous reverrons cet exercice en passant une référence sur un vector en paramètre et ceci, afin d'éviter l'utilisation d'un pointeur ou d'un tableau.

 
   Les corrigés des exercices proposés dans ce chapitre seront présentés à la fin du chapitre 9.
 
   @ bientôt pour le Chapitre 9 : Autres fonctionnalités du langage appliquées aux fonctions (1) !
            Gondulzak.  angel
 

   

 

Connexion

CoalaWeb Traffic

Today28
Yesterday157
This week540
This month2833
Total1742040

18/04/24