Choisissez votre style : colorisé, impression

Correction 11
Pointeurs et références

Les solutions suivantes ne sont évidemment pas uniques. Si vous en trouvez de meilleures (ou si vous trouvez des erreurs), faites-le savoir ! Merci.
Par ailleurs, les solutions proposées correspondent à l'état de vos connaissances au moment où la série est abordée. D'autres solutions pourront être envisagées une fois de nouveaux concepts acquis.
Exercice 1 Exercice 2 Exercice 3 Exercice 4

Exercice 1 : Pointeurs et références (niveau 1)

Question 1 :

Le code fourni produit l'affichage suivant :
2
3
2
2
3
3

Explication : ptri et ri permettent toutes deux de désigner indirectement la variable i. La différence majeure entre les deux dans cet exemple est que ri ne peut désigner que i alors que ptri peut désigner n'importe quel entier lors de l'exécution de ce programme.

Ainsi, l'affectation ri = j veut dire que la variable désignée par ri, càd i, prend la valeur de j (2 au moment de l'exécution). Cette instruction ne signifie pas que l'adresse de i devient celle de j. Ceci explique l'affichage d'un "2" produit par cette instruction.

Dans le cas de l'instruction ptri = &j, ptri qui désignait jusqu'alors i désigne désormais j, d'où l'affichage d'un "3".

Question 2 :

1
int& ri(i);
Correct : déclaration d'un alias pour la variable i
2
int* ptri(&i);
Correct : déclaration d'un pointeur sur un entier initialisé avec l'adresse de i
3
int& rj(0);
Faux : une référence non constante doit être associée à une variable
4
int* ptrj(0);
Correct en C++98 : le pointeur nul existe bel et bien
en C++11 : le 0 est à remplacer par nullptr
5
int& rk;
Faux : une référence doit absolument être liée à une variable
6
int* ptrk;
Correct (mais pas recommandable) : on peut très bien déclarer un pointeur sans l'initialiser

Exercice 2 : généricité

Exercice n°23 (pages 61 et 228) de l'ouvrage C++ par la pratique.
#include <iostream>
using namespace std;
 
int demander_nombre(int a, int b)
{
  /* échange les arguments s'ils n'ont pas été donnés dans *
   * le bon ordre.                                         */
  if (a > b) { int tmp(b); b=a; a=tmp; }
 
  int res;
  do {
    cout << "Entrez un nombre entier compris entre "
         << a << " et " << b <<" : ";
    cin >> res;
  } while ((res < a) or (res > b));
 
  return res;
}
 
int main () {
  double valeur1(3.14159265358);
  double valeur2(1.42857142857);
  double valeur3(-12.344556667);
  double* choix(0);
 
  switch (demander_nombre(1,3)) {
  case 1: choix = &valeur1; break;
  case 2: choix = &valeur2; break;
  case 3: choix = &valeur3; break;
  }
 
  cout << "Vous avez choisi " << *choix << endl;
 
  return 0;
}

Exercice 3 : structures et références (niveau 1)

Exercice n°26 (pages 64 et 231) de l'ouvrage C++ par la pratique.

3.1 Références

#include <iostream>
using namespace std;
 
struct Maison {
  string adresse;
};
 
struct Personne {
  string nom;
  Maison& home;
};
 
void affiche(const Personne& p) {
  cout << p.nom << " habite " << p.home.adresse << endl;
}
 
int main()
{
  Maison m1 = { "12 rue du chateau" };
  Personne p1 = { "Pierre", m1 };
  Personne p2 = { "Paul"  , m1 };
 
  Maison m2 = { "13 rue du chateau" };
  Personne p3 = { "Steve", m2 };
  Personne p4 = { "Sofia", m2 };
 
  affiche(p1);  affiche(p2);
  affiche(p3);  affiche(p4);
 
  return 0;
}

3.2 Limites des références

Les références ne pouvant pas être modifiées (en tant que telles, i.e. être déplacées), il faut ici les remplacer par des pointeurs :

#include <iostream>
using namespace std;
 
struct Maison {
  string adresse;
};
 
struct Personne {
  string nom;
  Maison* home;
};
 
void affiche(const Personne& p) {
  cout << p.nom << " habite " << (*(p.home)).adresse << endl;
  // Note : (*X).Y peut aussi s'écrire X->Y, par exemple ici :
  //     (p.home)->adresse
}
 
int main()
{
  Maison m1 = { "12 rue du chateau" };
  Personne p1 = { "Pierre", &m1 };
  Personne p2 = { "Paul"  , &m1 };
 
  Maison m2 = { "13 rue du chateau" };
  Personne p3 = { "Steve", &m2 };
  Personne p4 = { "Sofia", &m2 };
 
  affiche(p1);  affiche(p2);  affiche(p3);  affiche(p4);
 
  // déménagement de Pierre (p1)
  p1.home = &m2;
  cout << "maintenant : "; 
  affiche(p1);  affiche(p2);  affiche(p3);  affiche(p4);
 
  return 0;
}
 


Exercice 4 : Intégrales revisitées (pointeurs sur fonctions, niveau 2)

Exercice n°27 (page 65 et 235) de l'ouvrage C++ par la pratique.
 #include <iostream>
 #include <string>
#include <cmath>
#include <array>

 using namespace std;

 // ----------------------------------------------------------------------
 double f1(double x) { return x*x;             }
 double f2(double x) { return sqrt(exp(x));    }
 double f3(double x) { return log(1.0+sin(x)); }

 // ----------------------------------------------------------------------
 typedef double (* Fonction)(double);
// ou typedef function <double (double)> Fonction;
// mais dans ce cas il faut inclure <functional>
 
 // option légèrement plus élaborée que ce qui est suggéré par l'énoncé
 struct aChoisir {
 	string description;
 	Fonction f;
 };

 // ----------------------------------------------------------------------
 constexpr int MAXF(5);
/* notez la syntaxe particulière ici : ne pas mettre les  accolades
   autour des structure dans le array!
*/
const array <aChoisir, MAXF> choix = {  "x carré",                f1  ,
									    "racine d'exponentielle", f2  ,
                                        "log(1+sin(x))",          f3  ,
										   "sinus",               sin , 
										   "exponentielle",       exp 
 };

/*  remplacer sin et exp par : (double (*)(double))sin et
	(double (*)(double)) exp dans la version avec les functional de C++11
*/
 // ----------------------------------------------------------------------
 double demander_nombre();
 unsigned int demander_fonction();
 double integre(Fonction f, const double a, const double b);
 
 // ======================================================================
 int main()
 {
 	unsigned int rep(demander_fonction());

  	double a(demander_nombre());
	double b(demander_nombre());

	cout.precision(12);
	cout << "Integrale de " << choix[rep].description << " entre " << a 
		 << " et " << b << " :" << endl;
	cout << integre(choix[rep].f, a, b) << endl;
	return 0;
 }

// ======================================================================
 double demander_nombre() 
 { 
 	double res;
	cout << "Entrez un nombre réel : " << flush; 
	cin >> res;
	return res; 
 }

// ======================================================================
 unsigned int demander_fonction()
 {
	unsigned int rep;
	do {
		cout << "Vous pouvez choisir parmi les fonctions suivantes :" << endl;
		for (unsigned int i(0); i < MAXF; i++)
			cout << "   " << i+1 << "- " << choix[i].description << endl;
		cout << "De quelle fonction voulez vous calculer l'intégrale [1-5] ? "
			 << flush;
		cin >> rep;
	} while ((rep < 1) || (rep > MAXF));

	return --rep;
 }

// ======================================================================
 double integre(Fonction f, const double a, const double b)
 {
	double res;
	res =  41.0 * ( f(a) + f(b) )
		+ 216.0 * ( f((5*a+b)/6.0) + f((5*b+a)/6.0) )
		+  27.0 * ( f((2*a+b)/3.0) + f((2*b+a)/3.0) )
		+ 272.0 * f((a+b)/2.0) ;
	res *= (b-a)/840.0;
	return res;
}

 


Dernière mise à jour : $Date: 2025/11/13 12:01 $