Documente Academic
Documente Profesional
Documente Cultură
Johann Cuenin
11 octobre 2014
2
Table des matières
1 Introduction 5
5 Les fonctions 23
5.1 Notion de fonction . . . . . . . . . . . . . . . . . . . . . . . . . . 23
5.2 Appel d’une fonction et algorithmes récursifs . . . . . . . . . . . 24
5.3 Transmission des paramètres d’une fonction et passage par référence 25
5.4 Pointeur sur une fonction . . . . . . . . . . . . . . . . . . . . . . 26
5.5 programmation modulaire . . . . . . . . . . . . . . . . . . . . . . 27
3
4 TABLE DES MATIÈRES
Chapitre 1
Introduction
5
6 CHAPITRE 1. INTRODUCTION
Chapitre 2
Bases de la programmation
en C++
7
8 CHAPITRE 2. BASES DE LA PROGRAMMATION EN C++
Chapitre 3
Maintenant que les types de base sont connus, nous allons, dans ce chapitre,
faire connaissance avec les types composés : les tableaux et structures. Ces
types composés permettent de stocker plusieurs variables et de travailler avec
sans lister les déclaration (tableaux). Les structures permettent quant à elle de
travailler avec des types utiles pour un utilisateur (cas simple, définir un nombre
complexe).
type nom_du_tableau[nbre_éléments] ,
9
10 CHAPITRE 3. LES TYPES COMPOSÉS
1 int main(){
2 const int N=5;
3 int i=0;
4 int tab1[N],tab2[N];
5 for(i=0 , i<N , i++){
6 tab1[i]=tab2[i];
7 }
8 return 0;
9 }
par exemple :
1 int main(){
2 const int N=5;
3 int tab[N]={1,2,3,4,5};
4 return 0;
5 }
Attention : si le nombre de données est inférieure à la taille du tableau, seuls
les premiers éléments seront initialisés. Si le nombre de données est supérieure
à la taille du tableau, le compilateur générera une erreur.
3.1.3 Remarques
Un tableau de caractères peut être initialisé directement par une chaîne de
caractères. Mais attention, il faut que le tableau ait au moins un élément de
plus car le compilateur complète toute chaîne de caractères par le caractère nul.
On peut considérer l’exemple suivant :
1 const int N=8;
2 char tab[N]="exemple";
Lors de l’initialisation d’un tableau, on peut ne pas spécifier le nombre d’élé-
ments.
1 double tab[]={2.6,1.,3.};
2 char tab[]="exemple";
mais pas
1 int tab[];
On peut déclarer un tableau à plusieurs dimensions. Par exemple, un tableau
en deux dimensions sera appelé matrice. Il s’agit en fait d’un tableau de tableaux.
Par exemple :
1 const int N=3,M=2;
2 int tab[M][N]{{1,2,3},{4,5,6}};
3.2. LES STRUCTURES 11
1 #include<iostream>
2 #include<stdlib>
3 #include<math.h>
4
7 struct complexe
8 {
9 double reel;
10 double imaginaire;
11 };
12
13 int main(){
14 struct complexe z;
15 z.reel=1;
16 z.imaginaire=2;
17 double norme=sqrt(z.reel*z.reel+z.imaginaire*z.imaginaire);
18 cout<<"la norme de z est "<<norme<<"."<<endl;
19 return 0;
20 }
12 CHAPITRE 3. LES TYPES COMPOSÉS
3.2.2 Remarques
on peut déclarer un objet de type structure même si le modèle n’a pas été
déclarer avant par la syntaxe suivante :
1 struct modele
2 {
3 type_1 champ_1;
4 ...
5 type_r champ_r;
6 }objet;
7 int main(){
8 complexe z;
9 return 0;
10 }
Chapitre 4
donne par exemple "i=3 son adresse est x". Mais attention, contrairement à i, &i
n’est pas une Lvalue, mais une constante. Bien qu’en général il n’est pas utile
de connaître la valeur exacte de l’adresse d’une variable d’autant que celle-ci
13
14 CHAPITRE 4. LES POINTEURS ET RÉFÉRENCES
type ∗ nom_du_pointeur;
Remarque : Il faut bien faire la distinction entre la valeur d’un pointeur qui
est toujours un entier et le type du pointeur qui dépend du type de l’objet vers
lequel il pointe.
Exemple : Définisson un pointeur p qui pointe vers un entier i
1 int i = 3;
2 int *p;
3 p = &i;
1 int main(){
2 int i=2, j=6;
3 int *p1, *p2;
4 p1=&i;
5 p2=&j;
6 *p1=*p2;
7 return 0;
8 }
on a donc avant la dernière ligne
objet adresse valeur
i x 2
j y 6
p1 z x
p2 t y
et
objet adresse valeur
i x 6
j y 6
p1 z x
p2 t y
après la dernière ligne. Le programme suivant donne un autre résultat.
1 int main(){
2 int i=2, j=6;
3 int *p1, *p2;
4 p1=&i;
5 p2=&j;
6 p1=p2;
7 return 0;
8 }
Ici on obtiendra "p2=x+8". En effet, p1 est un pointeur qui pointe sur un double,
codé sur 8 bytes.
Remarques : Les opérateurs de comparaison sont également applicables
aux pointeurs si tant est qu’ils pointent vers des objets de même type.
pour valeur &tab[0]. On peut donc utiliser un pointeur initialisé à tab pour
parcourir les éléments du tableau :
1 int main(){
2 const int N=5;
3 int tab[N]={1,2,6,0,10};
4 int *p;
5 for(p=&tab[0] ; p<=&tab[N-1] ; p++){
6 cout<"*p="<<*p<<endl;
7 }
8 return 0;
9 }
delete nom_pointeur;
Par exemple :
1 int *p;
2 p=new int;
3 *p=3;
4 delete p;
et
1 int i=2;
2 int *p=new int;
3 *p=i;
4 delete p;
Les valeurs et adresses des objets sont donnés dans les tableaux suivants :
objet adresse valeur
i x 2
p y x
*p x 2
et, avant le delete pour le second exemple
objet adresse valeur
i x 2
p y x
*p x 2
Dans le premier cas, la modification de i ou *p va modifier *p ou i respecti-
vement, car ils ot la même adresse. L’allocation n’est donc pas dynamique, elle
se fait par référence. Dans le second cas, la modification de i ou *p n’implique
pas la modification de *p ou de i. En effet, les adresses sont différentes. Il y a
donc une allocation dynamique.
4.3.1 Déclaration
Remarque préliminaire
L’opérateur "new" permet aussi d’allouer un espace pour plusieurs objets
contigus en mémoire :
4.3. POINTEURS ET TABLEAUX 19
1 int n=2;
2 int i=3, j=6;
3 int *p=new int[n];
4 *p=i;
5 *(p+1)=j;
6 delete []p;
Comme vu plus haut, les tableaux sont des pointeurs constants. Pour accéder
à l’élément d’indice i pour tab, on utilise tab[i]. Pour un pointeur, on peut utiliser
p[i]. On a dont la formule p[i]=*(p+i). Pointeurs et tableaux se manipulent donc
exatcement de la même manière. Mais la manipulation de tableaux et de non
de pointeurs a plusieurs inconvénients :
— tableaux de taille fixe,
— impossibilité de construire des tableaux bidimensionnels dont les lignes
n’ont pas toutes le même nombre d’éléments.
Mais tout cela devient possible dès que l’on manipule des pointeurs alloués
dynamiquement.
Tableaux dynamiques
Pour déclarer un tableau dynamiquement, on peut suivre la syntaxe ci-
dessous
1 int main(){
2 int n;
3 int *tab;
4 tab=new int[n];
5 delete[] tab;
6 return 0;
7 }
type ∗ ∗nom_du_pointeur;
20 CHAPITRE 4. LES POINTEURS ET RÉFÉRENCES
Les fonctions
23
24 CHAPITRE 5. LES FONCTIONS
Une fonction est complètement caractérisée par son nom mais aussi par le
type renvoyé ou par les types des variables passées en argument. Par exemple
les fonctions
1 void afficher(int i)
2 void afficher(float f)
sont deux fonctions différentes bien qu’ayant le même nom. C’est en fait
l’analogue des fonctions en mathématiques. En effet les fonctions
f : R → R+
x 7→ x2
et
f : R+ → R+
x 7→ x2
Attention ! ! ! ! Pour une fonction renvoyant une valeur, on doit pouvoir stocker
le résultat renvoyé ! Si on reprends l’exemple de la somme, l’appel peut aussi
s’écrire (on complète avec la fonction affichage) :
1 int main(){
2 int a, b, res;
3 cin>>a>>b;
4 res=somme(a,b);
5 afficher(res);
6 return 0;
7 }
Dans la liste d’instructions d’une fonction, on peut très bien en appeler une
ou plusieurs autres, si tant est qu’elles soient déclarées avant. On peut également
appeler la même fonction à l’intérieur d’elle-même de manière récursive. Cette
technique de programmation est très puissante et permet de faire des calculs
assez simplement. Par exemple, écrire une fonction qui permet de calculer la
puissance entière d’un nombre.
1 int puissance(int a, int n){
2 if(n==0){
3 return 1;
4 }
5 else{
6 return(a*puissance(a,n-1));
7 }
8 }
8 int main(){
9 int a=10, b=20;
10 cout<<"debut du programme principal : a="<<a<<", b="<<b<<endl;
11 remplace(a,b);
12 cout<<"fin du programme principal : a="<<a<<", b="<<b<<endl;
13 reurn 0;
14 }
8 int main(){
9 .....
10 remplace(&a, &b);
11 .....
12 }
On peut donc définir une fonction "opérateur binaire" que l’on va écrire
1 int operateur_binaire(int a, int b, int (*f)(int, int)){
2 return((*f)(a,b));
cela une multitude de petites fonction. Cela permettra d’éviter les redondances
dans le code et rendra la tâche de débugage plus simple. Enfin, ne pas hésiter à
fragmenter son projet en plusieurs fichiers. Concrètement :
— un premier fichier "fonctions.hpp" permettant de déclarer les fonctions.
— un deuxième "fonctions.cpp" dans lequel on écrira le code en dur des
différentes fonctions. On inclura le fichier "fonctions.hpp".
— enfin un dernier "main.cpp" contenant le programme principal, dans le-
quel on inclura le fichier "fonctions.h".
Le compilateur se chargera de faire le lien entre les différents fichiers. On sera
donc en présence d’un projet bien structuré (efforts à faire lors de votre projet !).
Ceci permettra d’avoir de bonnes bases pour la programmation orientée objets
qui sera introduite en master.