Big Tuto : Apprenez le C++

Chapitre 11 : Autres fonctionnalités du langage appliquées aux fonctions (3)

Tutoriel présenté par : Robert Gillard (Gondulzac)
Date de publication : 27 mars 2016
Date de révision : -

 

      1 - Retour sur les passages d'arguments dans une fonction (suite)

1.1 - Tableaux multidimensionnels (tableaux de tableaux)

   Dans le chapitre 3, à la fin du paragraphe 2 se rapportant aux tableaux, j'écrivais ceci : ''Je n'aborderai pas ici les tableaux multi-dimensionnels, je vous renvoie à ce sujet à un cours ou à un tutoriel C.'' frown

   Il se fait que pour parler du passage de tableau multidimensionnel dans une fonction, il nous faut cependant introduire la notion de tableau multidimensionnel en C++. En effet, ce langage a une conception quelque peu différente d'un tableau multidimensionnel par rapport à celle du langage C. wink


   En C++, on parlera plutôt de ''tableaux de tableaux'' et on définit un tableau dont les éléments sont des tableaux en initialisant deux dimensions :

- la dimension du tableau lui-même.
- et la dimension de ses éléments.

   Considérons le tableau d'entiers non signés suivant :

unsigned int tab[5][10];

   Nous initialisons ici un tableau de dimension 5, chaque élément étant un tableau d'unsigned int de dimension 10.

   Considérons le tableau de tableaux suivant :

   unsigned int tab[5][10][15];

   Nous avons ici un tableau de dimension 5 dont chaque élément est un tableau de 10 éléments dont chacun est lui-même un tableau de 15 valeurs unsigned int. indecision

 

1.2 – Initialisation des éléments d'un tableau multidimensionnel

   Prenons par exemple un tableau unsigned int tab[5][6].

unsigned int tab[5][6] = {            // Un tableau de 5 éléments, chacun étant un tableau de dim. 6
{ 0, 1, 2, 3, 4, 5 },                          // Ligne 1 : indexée à 0. Contient 6 éléments.
{ 6, 7, 8, 9, 10, 11 },                      // Ligne 2 : indexée à 1. Contient 6 éléments.
{ 12, 13, 14, 15, 16, 17 },              // Ligne 3 : indexée à 2. Contient 6 éléments.
{ 18, 19, 20, 21, 22, 23 },              // Ligne 4 : indexée à 3. Contient 6 éléments.
{ 24, 25, 26, 27, 28, 29 }               // Ligne 5 : indexée à 4. Contient 6 éléments.
};

   Ce tableau aurait pu s'écrire :

unsigned int tab[5][6] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, …..... 27, 28, 29 };

   ...ce qui est quand-même moins parlant que la première forme.

 

Retrouvez les projets complets de ce chapitre :

  

 

   Nous allons maintenant voir un exemple simple d'assignation des positions des éléments d'un tableau bi-dimensionnel à l'aide de leurs index :

//projet 069Tableaux3
//Remplissage et lecture d'un tableau bi-dimensionnel
#include<iostream>
 
using namespace std;
using uint = unsigned int;
 
 
int main()
{
 
const uint nb_lignes(4), nb_colonnes(5);
 
//On déclare un tableau d'unsigned int dont les dimensions sont des constantes
//nb_lignes et nb_colonnes
uint tab[nb_lignes][nb_colonnes];
 
//Remplissage d'un tableau bi-dimensionnel de 4 lignes et 5 colonnes
//Lignes
for (size_t i = 0; i != nb_lignes; ++i)
{
//Colonnes
for (size_t j = 0; j != nb_colonnes; ++j)
{
//On assigne à chaque position la valeur de leur index
tab[i][j] = i * nb_colonnes + j;
}
}
 
 
//Lecture du tableau
cout << "Remplissage et lecture d'un tableau bi-dimensionnel 4 lignes 5 colonnes";
cout << endl << endl;
for (size_t i = 0; i != nb_lignes; ++i)
{
for (size_t j = 0; j != nb_colonnes; ++j)
{
cout << tab[i][j] << " ";
}
cout << endl;
}
 
cout << endl;
 
cin.get();
return 0;
 
}

 

   Ce programme est réalisé en entier dans la fonction main(). On déclare en premier un tableau bi-dimensionnel dont les dimensions sont passées en constantes dans les crochets.
   La première partie de ce programme remplit le tableau en assignant à chaque position la valeur de son index. La seconde partie du programme affiche le tableau sous la forme de 4 lignes et 5 colonnes.

   Résultat dans la console :

 

   Dans cet exemple nous utilisons des indices mais rien ne nous empêche d'employer la boucle for du standard C++ 11. Ainsi, la boucle d'assignation des valeurs du tableau pourrait être réécrite bien plus simplement comme suit :

size_t compteur(0);
 
for (auto &nb_lignes : tab)
{
for (auto &nb_colonnes : nb_lignes)
{
nb_colonnes = compteur;
++compteur;
}
}

 

   Une variable de type size_t est initialisée à 0 avant d'entrer dans la première boucle. La seconde boucle parcourt le nombre de colonnes du tableau (5) et initialise chaque position avec la valeur de la variable compteur qui est incrémentée à chaque tour.

   Les types de nb_lignes et nb_colonnes, déclarés ''auto'' sont des références sur des valeurs unsigned int.


   Exercice 1 :

   Réécrivez le projet 069Tableaux3 en utilisant la forme du standard C++ 11 ci-dessus. wink


        1.3 – Tableaux multidimensionnels et pointeurs

   De même qu'avec un tableau, si nous utilisons le nom d'un tableau multidimensionnel, il est automatiquement converti en un pointeur sur le premier élément de ce tableau. wink
   Un tableau multidimensionnel étant en réalité un tableau de tableaux, ce pointeur pointera sur le tableau intérieur représenté par les colonnes de ce tableau.

   Reprenons le tableau bi-dimensionnel de notre projet 069Tableaux3, soit :

uint tab[4][5];

   Dans cette déclaration, nous avons un tableau de dimension 4 dont chaque élément est lui-même un tableau de 5 valeurs unsigned int. Pour déclarer un pointeur sur ce tableau nous écrirons :

uint (*ptr)[5] = tab;

   Nous déclarons ainsi un pointeur sur un tableau de 5 entiers.

Attention ! surprise Les parenthèses sont obligatoires. wink En effet si nous avions écrit : uint *ptr[5], nous aurions déclaré un tableau de pointeurs sur des unsigned int. indecision

   Bien, revenons à notre pointeur sur un tableau. Nous savons que ce tableau comporte 4 lignes, donc :

uint ptr = &tab[0]    // ptr pointe sur la 1ere ligne du tableau.
…..
…..
uint ptr = &tab[3]    // ptr pointe sur la dernière ligne du tableau.

   En utilisant les pointeurs, nous pourrions réécrire les lignes de lecture du tableau bi-dimensionnel du projet 069Tableaux3 de la manière suivante :

for (auto ptr = tab; ptr != tab + 4; ++ptr)
{
for (auto ptr2 = *ptr; ptr2 != *ptr + 5; ++ptr2)
cout << *ptr2 << " ";
cout << endl;
}

 

   Ceci demande quelques explications. cheeky

   Nous savons que notre tableau comporte 4 lignes et 5 colonnes. Dans la première boucle, nous initialisons un pointeur ptr au début de la première ligne du tableau tab. Le pointeur ptr sera incrémenté jusque tab + 3 (nous avons 4 lignes, donc le tableau représentant les lignes possède les indices 0,1, 2, 3).

   Dans la seconde boucle, nous initialisons un pointeur ptr2 sur l'emplacement mémoire suivant le dernier de notre première boucle et ceci pour obtenir la valeur contenue à cette adresse. Et à chaque tour de cette boucle, nous affichons la valeur pointée par ptr2 dans chaque colonne, soit le pointeur déréférencé *ptr2.

   Et cet exemple nous amène tout naturellement à un second exercice. cheeky Allez, un petit challenge ! laugh

 

   Exercice 2 :

   En utilisant les pointeurs, écrivez une fonction qui affichera les éléments d'un tableau bi-dimensionnel d'entiers (vous pouvez reprendre l'exemple du code ci-dessus comme corps de la fonction). Le tableau devra être initialisé dans la fonction main().

   Le tableau sera déclaré int tab[5][10];

   Solution 1 – Utilisez des indices pour initialiser le tableau.

   Solution 2 – Initialisez le tableau avec la boucle for du C++ 11.

   Et dans les deux cas, vous devriez avoir ce résultat dans la console : 

 

   2 – Conversions explicites de types

  Dans le chapitre 2 (Types de données – Variables et constantes), nous avons introduit la notion de conversion de type avec un exemple sur le résultat de la division de 2 entiers. Il se fait que le C++ nous permet actuellement de spécifier explicitement un type de ''cast'' à effectuer sur une valeur.
   Ceux-ci sont dénommés static_cast, const_cast, reinterpret_cast et dynamic_cast. Pour le moment, nous parlerons des trois premiers types. wink

 

        2.1 – static_cast

   Nous avons donné un exemple de conversion de type avec ''static_cast'' dans le chapitre 2 mais nous pouvons ajouter qu'un static_cast est souvent utile lorsqu'on affecte un type arithmétique plus grand à un type plus petit.

   Par exemple, si :

int somme(0);
int y = 5;
double x = 10;
somme = y + x;

   Nous voulons affecter x (de type double) à y (de type int, donc plus petit). Si nous compilons ce programme, le résultat affiché sera exact (15), mais le compilateur nous signalera un avertissement disant que l'on risque une perte de valeur.

warning C4244: '=' : conversion from 'double' to 'int', possible loss of data

   Pourquoi ? surprise

   Donnons une nouvelle valeur à la variable x, soit x = 10.095 et additionnons maintenant x à y :

somme = y + x;
cout << somme;

   Mais la valeur de ''somme'' est toujours 15, alors que j'ai ajouté 10.095 à 5 !? surprise

   Et oui, la variable somme étant déclarée de type int, le résultat sera un int et vous aurez une perte de précision égale à 0,095. Dans de nombreux cas cette perte de valeur n'aura pas d'incidence sur le programme, par exemple dans les cas de positionnement d'objets à l'écran. wink Pour éviter ce ''warning'' vous n'aurez qu'à effectuer un static_cast du type le plus petit vers le type le plus grand :

somme = static_cast<double>(y) + x;

   Mais supposons que vous ayez à peser de … l'or ! indecision, soit 5g et 10,095g. Pour que le résultat de votre calcul soit exact, il vous faudra absolument donner le type double à la variable somme, vous éviterez ainsi de perdre 95 mg d'or ! angry


        2.2 – const_cast

   Une conversion const_cast ne peut opérer une conversion que sur un pointeur ou une référence const.

Exemple :

const char *charPtr;
char *ptr = const_cast<char*>(charPtr);

   Nous effectuons un const_cast sur *charPtr qui est un pointeur sur un char constant. Ceci convertit l'objet en un type non constant qui pourra pointer sur un autre objet mais dans ce cas le compilateur ne nous préviendra plus que nous voulons écrire sur cet objet.

   Une conversion explicite const_cast est surtout utilisée dans la surcharge de fonction, nous allons bientôt le voir. wink


        2.3 – reinterpret_cast

   Une conversion explicite reinterpret_cast est quelquefois utilisée pour transformer un type donné en un type compatible. L'exemple suivant va réinterpréter le type int en type char :

int *iptr;
char *charPtr = reinterpret_cast<char*>(iptr);

   Soit ce petit exemple :    

//projet 070reinterpret_cast
//Un exemple de cast d'un int en char
#include<iostream>
#include<string>
 
using namespace std;
 
 
int main()
{
int nombre = 65;
int *iptr;
iptr = &nombre;
 
cout << "Entier choisi = " << *iptr << endl << endl;
 
cout << "On fait une conversion 'reinterpret_cast' pour convertir l'entier en char" << endl;
char *charPtr = reinterpret_cast<char*>(iptr);
 
//Affiche le caractère
cout << "Le caractere est " << *charPtr << endl <<endl;
 
//On initialise une chaîne avec le caractère
cout << "Initialisation d'un type string avec le caractere charPtr :" << endl;
string chaine(charPtr);
cout << "chaine = " << chaine << endl << endl;
 
cout << "On fait pointer *charPtr sur la derniere lettre de l'alphabet :" << endl;
*charPtr = nombre + 25;
cout << "*charPtr = " << *charPtr << endl;
 
 
cin.get();
return 0;
}

 

   On initialise un entier avec la valeur 65 ainsi qu'un pointeur sur cet entier. On procède ensuite à une conversion reinterpret_cast de cet entier vers un char, ce qui nous donne le caractère majuscule 'A'.
   Nous voyons ensuite qu'il est également possible d'initialiser une chaîne de type string avec le caractère contenu dans la zone mémoire pointée par charPtr, c'est-à-dire le caractère 'A'.

   On fait ensuite pointer charPtr sur la dernière lettre de l'alphabet et on l'affiche. wink

   Ce qui affiche dans la console :

 

Remarque : C++ recommande dans la mesure du possible d'éviter toutes les opérations de 'cast' et notamment les conversions explicites reinterpret_cast, celles-ci pouvant conduire à des effets inattendus selon les types mis en œuvre.


   3 – Compléments sur les types de retour d'une fonction

        3.1 – Un exemple de valeur de retour à l'aide d'opérateurs conditionnels

   Dans le chapitre 7 (Les fonctions, deuxième partie), nous avions vu un exemple de fonction retournant la plus grande de deux chaînes à l'aide d'un booléen. Nous allons ici revoir cette fonction qui retournera également la plus grande de deux chaînes, mais cette fois sous la forme d'une référence sur une chaîne const. La valeur de retour sera évaluée à l'aide d'un opérateur conditionnel.

   Un opérateur conditionnel est, comme son nom l'indique, une condition prenant la forme suivante:

condition ? expression 1 : expression 2

   Forme dans laquelle ''condition'' est évaluée à ''true'' ou ''false'' (vrai ou faux). Si la condition est vraie, alors ''expression 1'' sera évaluée, sinon c'est ''expression 2'' qui sera évaluée.

   Nous voyons un exemple en nous basant sur le projet 051Fonctions14 :

//Projet 071ConditionnelOp
//Comparaison de la longueur de deux chaînes
//Retour d'une référence sous la forme d'un opérateur conditionnel
#include <iostream>
#include <string>
 
using namespace std;
using uint = unsigned int;
 
 
// Déclaration de la fonction EstPlusGrand()
const string &EstPlusGrand(const string &chaine1, const string &chaine2);
 
 
int main()
{
string plusGrandeChaine;
 
const string ch1{ "Assourbanipal" };
const string ch2{ "Assourdan" };
 
cout << endl;
cout << "Une fonction qui renvoie une reference sur la plus grande" << endl;
cout << "des chaines 'Assourbanipal' et 'Assourdan'" << endl << endl;
 
plusGrandeChaine = EstPlusGrand(ch1, ch2);
cout << "la plus grande chaine est " << plusGrandeChaine << endl;
cout << "Son nombre de caractères est de " << plusGrandeChaine.size();
 
cout << endl;
 
cin.get();
return 0;
}
 
 
const string &EstPlusGrand(const string &rchaine1, const string &rchaine2)
{
return (rchaine1 > rchaine2 ? rchaine1 : rchaine2);
}

 

   Dans cet exemple on déclare une fonction EstPlusGrand() dont le type de retour est une référence sur une chaîne const. La fonction est appelée dans la fonction main() avec les deux chaînes en paramètres et son résultat renvoie une référence sur la plus grande des deux chaînes dans la variable string ''plusGrandeChaine''.

   Et le résultat dans la console :

 

   3.2 – Valeurs de retour de la fonction main()

   Nous savons que toute fonction ayant un type de retour doit retourner une valeur. La fonction main() est cependant une exception à cette règle, le programme suivant étant parfaitement compilable :    

#include<iostream>
#include<conio.h>
 
int main()
{
std::cout << "Cette fonction main() ne retourne aucune valeur..." << std::endl;
_getch();
}

 

   Comme dans tous les programmes C++, le type de retour de cette fonction est ''int''. Mais ne voyant pas de valeur retournée dans la fonction ci-dessus, c'est le compilateur qui implicitement ajoutera lui-même la valeur de retour 0. Comme nous le savons, une valeur de retour égale à 0 indiquera que le déroulement du programme s'est fait sans rencontrer de problème tandis que la plupart des autres valeurs indiquera une erreur. wink

   Le fichier ''cstdlib'' possède deux variables du pré-processeur qui indiquent un succès ou une erreur lors du déroulement du programme. Il s'agit des variables EXIT_FAILURE et EXIT_SUCCESS, définies dans cstdlib. Une fonction main() utilisant ces variables s'écrira :

#include<iostream>
#include<cstdlib>
#include<conio.h>
 
int main()
{
std::cout << "Cette fonction main() retourne des variables du preprocessur" << std::endl;
 
if (erreur_quelconque)
return EXIT_FAILURE;
else
return EXIT_SUCCESS;
 
_getch();
}

 

   4 – Surcharge de fonctions et références

   Dans le chapitre 6 (Les fonctions – première partie) nous avons dit que nous reviendrions sur le concept de surcharge de fonction dès que nous aurions introduit les notions de pointeurs et de références dans les fonctions.

   Le projet 071ConditionnelOp ci-dessus nous donne une bonne occasion d'en parler maintenant. angel
   Nous allons réécrire le projet 071ConditionnelOp en lui ajoutant une seconde fonction surchargée EstPlusGrand() à laquelle nous passerons cette fois deux chaînes non const en arguments.

   Nous allons voir que l'une ou l'autre fonction surchargée sera appelée selon que l'on passe des arguments 'const' ou 'non const'. Dans ce dernier cas, un const_cast sur les arguments de la fonction nous permettra de renvoyer une référence sur un const string (la plus grande des deux chaînes). 

//Projet 072const_cast
//Comparaison de la longueur de deux chaînes
//Fonctions surchargées renvoyant une réf sur un const string
#include <iostream>
#include <string>
 
using namespace std;
using uint = unsigned int;
 
// Déclaration des fonctions surchargées EstPlusGrand()
const string &EstPlusGrand(const string &chaine1, const string &chaine2);
string &EstPlusGrand(string &chaine1, string &chaine2);
 
 
int main()
{
 
string plusGrandeChaine;
const string ch1{ "Assourbanipal" };
const string ch2{ "Assourdan" };
 
string ch3{ "Assourouballit" };
string ch4{ "Assournazirabal" };
 
cout << endl;
cout << "Une fonction qui renvoie une reference constante sur la plus grande" << endl;
cout << "des chaines const 'Assourbanipal' et 'Assourdan'" << endl << endl;
 
plusGrandeChaine = EstPlusGrand(ch1, ch2);
cout << "La fonction surchargee avec passage d'arguments 'CONST' est appelee" << endl;
cout << "la plus grande chaine est " << plusGrandeChaine << endl;
cout << "Son nombre de caracteres est de " << plusGrandeChaine.size();
cout << endl << endl;
 
cout << "Une fonction qui renvoie une reference sur la plus grande" << endl;
cout << "des chaines non const 'Assourouballit' et 'Assournazirabal'" << endl << endl;
 
plusGrandeChaine = EstPlusGrand(ch3, ch4);
cout << "La fonction surchargee avec passage d'arguments 'NON CONST' est appelee" << endl;
cout << "la plus grande chaine est " << plusGrandeChaine << endl;
cout << "Son nombre de caracteres est de " << plusGrandeChaine.size();
cout << endl << endl;
 
cin.get();
return 0;
 
}
 
 
//Fonction surchargée avec passage d'arguments const
//Renvoie une référence sur une chaine 'const'
const string &EstPlusGrand(const string &rchaine1, const string &rchaine2)
{
return (rchaine1 > rchaine2 ? rchaine1 : rchaine2);
}
 
 
//Fonction surchargée avec passage d'arguments non const
//Renvoie une référence sur une chaîne const'
//par une opération const_cast des deux chaînes.
string &EstPlusGrand(string &rchaine1, string &rchaine2)
{
auto &r1 = const_cast<const string&>(rchaine1);
auto &r2 = const_cast<const string&>(rchaine2);
 
if (rchaine1 > rchaine2)
{
return const_cast<string&>(r1);
}
 
else
return const_cast<string&>(r2);
}

 

   Il n'est pas bien difficile de voir ce que nous avons fait. Nous déclarons deux fonctions surchargées EstPlusGrand() de type string. La première des deux fonctions a une référence sur un string constant comme type de retour et deux paramètres de type const string. La seconde fonction a une référence sur un string non const comme type de retour et deux paramètres de type string.


   Dans les fonctions surchargées, nous allons comparer la plus grande de deux chaînes de type const string ainsi que deux chaînes de type string. Dans la fonction main(), l'appel à la fonction surchargée adéquate se fera d'après les types des arguments passés à la fonction (vous pouvez éventuellement revoir la partie traitant des fonctions surchargées dans le chapitre 6 wink).

   Notre fonction string &EstPlusGrand(string &rchaine1, string &rchaine2) à qui l'on passe deux arguments de type string renverra quant-à-elle une référence sur une chaîne const, liée à un de nos arguments non constant. C'est pourquoi nous effectuons, par souci de sécurité, un const_cast sur une chaîne non const dans notre instruction de retour.

   Voici le résultat de ce programme dans la console :

   Exercice 3 :

   Réécrivez ce projet en remplaçant les références par des pointeurs dans la déclaration de la fonction string &EstPlusGrand(string &chaine1, string &chaine2);


   5 – Pointeurs sur fonctions

   Reprenons la déclaration de la fonction EstPlusGrand() du projet 051Fonctions14 de notre chapitre 7, soit :

bool EstPlusGrand(const string &chaine1, const string &chaine2);

   Le type de retour de cette fonction est un booléen. Maintenant, si nous voulons déclarer un pointeur sur cette fonction, nous déclarerons un pointeur à la place du nom de la fonction :

bool (*ptrFunc) (const string &chaine1, const string &chaine2);

   Remarquez les parenthèses entourant le pointeur. Si ces parenthèses étaient omises, nous déclarerions une fonction dénommée ptrFunc retournant un pointeur sur un booléen !

   Revenons au pointeur ptrFunc qui pointe sur notre fonction. Nous dirons que ptrFunc est un pointeur qui pointe sur une fonction prenant deux chaînes const string en arguments et qui retourne un booléen.

   Ceci étant acquis, nous pouvons réécrire le projet 051Fonctions14 en utilisant un pointeur sur notre fonction. smiley

//Projet 073PtrSurFonct
//Un pointeur sur une fonction
//Comparaison de la longueur de deux chaînes
 
#include <iostream>
#include <string>
 
using namespace std;
using uint = unsigned int;
 
//Déclaration de la fonction EstPlusGrand()
bool EstPlusGrand(const string &chaine1, const string &chaine2);
 
// Déclaration d'un pointeur sur la fonction
bool (*ptrFunc) (const string &chaine1, const string &chaine2);
 
int main()
{
 
const string ch1{ "Assourbanipal" };
const string ch2{ "Assourdan" };
 
//On assigne l'adresse de la fonction au pointeur
ptrFunc = EstPlusGrand;
 
//On appelle la fonction à l'adresse pointée par ptrFunc
 
if ((ptrFunc)(ch1, ch2))
cout << "La chaine " << ch1 << " est plus grande que la chaine " << ch2 << endl;
else
cout << "La chaine " << ch2 << " est plus grande que la chaine " << ch1 << endl;
 
cout << "La longueur de " << ch1 << " est de " << ch1.size() << " caracteres" << endl;
cout << "La longueur de " << ch2 << " est de " << ch2.size() << " caracteres" << endl;
 
cin.get();
return 0;
 
}
 
 
bool(EstPlusGrand) (const string &rchaine1, const string &rchaine2)
{
return (rchaine1 > rchaine2);
}

 

   6 – Corrigés des exercices du chapitre 10

   Exercice 1 :

   Il était demandé : En vous référant au projet 057Fonctions20 du chapitre 8 et au passage explicite d'une longueur de tableau, écrivez une fonction qui lit 10 entiers (0... 9).

Le tableau sera initialisé dans la fonction main() et sa longueur sera de type size_t.
Utilisez le schéma suivant :
Déclaration de la fonction.
Ecriture de la fonction main()
Ecriture de la définition de la fonction.

   L'exemple de la fonction LisTab(), présentée dans le chapitre 10 passait un tableau en argument et il vous a été demandé de modifier cet exemple en passant de préférence un pointeur. Voici le code : 

//Projet Chap10Exercice_1
//Passage explicite d'une longueur de tableau 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;
 
// Déclaration de la fonction LisTab()
void LisTab(const int *ptr, size_t longueur_tableau);
 
 
int main()
{
 
// La longueur du tableau est de type size_t
int tableau[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 
cout << "Une fonction qui lit des valeurs entieres d'un tableau" << endl;
cout << "avec passage explicite de la longueur du tableau" << endl;
cout << "Utilisation des methodes begin() et end() de la Standard Library" << endl << endl;
 
// On passe un pointeur sur le tableau et sa longueur en paramètres de la fonction
// LisTab()
LisTab(tableau, end(tableau) - begin(tableau));
 
_getch();
return 0;
 
}
 
void LisTab(const int *ptr, size_t longueur_tableau)
{
for (size_t i(0); i != longueur_tableau; ++i)
{
cout << *ptr + i << " ";
}
 
cout << endl;
}  

 

   Déclaration de la fonction :

   Nous déclarons une fonction LisTab() dont le type de retour est ''void'' et possédant deux paramètres, un pointeur sur un tableau d'entiers constants et une longueur de tableau de type size_t.

   Dans la fonction main() :

   Nous initialisons un tableau de 10 entiers (0...9) et on appelle la fonction LisTab() en lui passant le nom du tableau (transformé en pointeur) ainsi que sa longueur end(tableau) – begin(tableau) que nous obtenons, nous l'avions vu dans le chapitre précédent, par cette forme utilisant les méthodes begin() et end() de la Standard Library.

   Dans la fonction LisTab() :

   Nous obtenons les valeurs du tableau à l'aide du pointeur déréférencé *ptr qui est incrémenté jusqu'à atteindre la fin du tableau.

   Vous deviez obtenir quelque chose de ce genre dans la console :

 

   Exercice 2

   Il était demandé : Ecrivez une fonction qui affiche une liste d'initialiation de 10 entiers (0...9). La liste sera affichée dans la fonction et la somme de ses éléments sera renvoyée dans la fonction main() où elle sera affichée.
   Voici le code : 
 
//Projet Chap10Exercice_2
//Une fonction qui renvoie la somme de 10 entiers d'une liste d'initialisation
 
#include <iostream>
#include <string>
#include <initializer_list>
 
using namespace std;
 
int Somme(initializer_list<int> tab);
 
 
int main()
{
initializer_list<int> tableau;
 
tableau = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
 
cout << endl;
cout << "Creation d'une liste d'initialisation de 10 entiers ( 0...9 )" << endl;
cout << "La somme des elements de la liste d'initialisation est " << Somme(tableau);
cout << endl;
 
cin.get();
return 0;
}
 
 
int Somme(initializer_list<int> tab)
{
int som = 0;
 
for (auto debut = tab.begin(); debut != tab.end(); ++debut)
{
cout << *debut << " ";
som += *debut;
}
 
cout << endl;
 
return som;
}  

 

   Nous allons utiliser une liste d'initialisation, donc premièrement il ne faut pas oublier d'inclure le fichier header <initializer_list>.
   La déclaration de notre fonction ''Somme'' se fait en passant en argument un tableau qui contiendra une liste d'initialisation d'entiers.

   Dans la fonction main(), nous initialisons un tableau qui va contenir nos 10 entiers (0...9) et on appelle la fonction Somme(). Je rappelle que le nom ''tableau'' passé à la fonction est transformé en pointeur par le compilateur pour pointer sur le premier élément de ce tableau.

   Dans la définition de la fonction ''Somme'' nous faisons une itération sur tous les éléments du tableau. Comme begin() renvoie un pointeur sur le début du tableau, nous devons déréférencer la variable ''début'' pour accéder à ses éléments et les afficher.
   Chaque valeur est ensuite ajoutée à la variable ''som'' qui additionne tous les éléments du tableau. Cette variable est ensuite retournée dans la fonction main() où elle est affichée.

   Ce qui donne dans la console :

 

     Voilà, c'est tout pour ce qui est de ce chapitre. Les corrigés des exercices proposés dans ce chapitre seront présentés à la fin du chapitre 12. cool

       @ bientôt pour le chapitre 12 - Entrées/sorties – lecture et écriture de fichiers.

            Gondulzak.  angel
 

   

 

Connexion

CoalaWeb Traffic

Today113
Yesterday240
This week1424
This month5098
Total1744305

28/04/24