Vous êtes sur la page 1sur 97

Cours Algorithmique Avancée

et Programmation

EILCO – ING 1

1
Structuration du cours
• 3x2h cours, 4x4h TP en C
• 2x2h cours, 3x4h TP en C++ (dont 2h de TP noté)

• Environnement de développement : Code::Blocks

• Notes : examen final, investissement en TP (?), TP noté


• Moyenne module ≈ 0,5 x exam + 0,3 x TP + 0,2 x CC
(ou 0,7 x exam + 0,3 x TP)

2
Programmation
• Un ordinateur est une machine de calcul disposant de son
propre langage. Le langage est différent selon la machine
utilisée (Windows/Linux/Mac ; Android/iPhone ; processeur
16b, 32b, 64b)
• Un langage de programmation permet de donner des
commandes à un ordinateur à l'aide d'un langage plus
compréhensible pour l'homme, plus structuré, plus portable
sur les différents types de machines.
• Les langages de programmation sont traduits en langage
machine au moment de la compilation, qui dépend de la
machine utilisée (on y reviendra)
• De nombreux langages de programmation existent, dont C et
C++.
3
Algorithmique élémentaire

Actions élémentaires

4
Programme
• programme : processus de calcul qui effectue des actions sur
des données
• Nous allons étudier quatre premières actions élémentaires :
– lecture d'une donnée
– écriture d'un résultat
– déclaration d'une donnée
– exécution d'une procédure ou fonction prédéfinie

5
Lecture d'une donnée
La lecture d'une donnée consiste à faire entrer un objet en
mémoire centrale à partir d'un équipement externe.
• Dans le cadre du cours, l'entrée se fera par le clavier, on
parlera d'entrée standard
• Une fois lu, l'objet placé en mémoire portera un nom appelé
identificateur. Ce nom sera cité chaque fois qu'on utilisera
l'objet en question dans le programme

Pseudo-code : C/C++ :
lire(x) scanf (on y reviendra)

6
Écriture d'un résultat
C'est l'opération inverse de la lecture d'une donnée. Il s'agit de
récupérer le résultat sur un équipement externe. C'est l'action
d'écriture.
Dans le cadre de ce cours, les résultats seront affichés
« écrits »sur l'écran. Ce sera la sortie standard.

pseudo-code :
/* l'identificateur v désigne une valeur en mémoire */
écrire(v)
/* v est écrit sur la sortie standard */
C/C++ :
printf (on y reviendra)
7
Déclaration d'un nom
La plupart des langages de programmation nécessitent que les
identificateurs soient déclarés avant d'être utilisés. C'est le cas
en C et en C++ par exemple.

Les noms des identificateurs doivent être choisis afin d'être


« significatifs ».

On distingue généralement les constantes dont les valeurs ne


changeront jamais dans un programme des variables.

8
Déclaration de constantes
constantes
nblettres = 26 /* nombre de lettres de l'alphabet */
Nbtours = 33

En C/C++ :
Mot-clé const : const int nblettres;

9
Déclaration de variables
Dans le cas d'une déclaration de variable, on indique avec
l'identificateur l'ensemble de valeurs que peut prendre la variable
(pour lui réserver un espace suffisant en mémoire). L'ensemble
de valeurs que peut prendre la variable est appelé le type.

variables
réponse type caractère
racine1, racine2 type réel

Note : nous reverrons le concept de types ultérieurement

10
Affectation
L'affectation est l'opération qui modifie ou écrase la valeur
contenue par un identificateur pour lui affecter une nouvelle
valeur.
L'affectation est représentée symboliquement par x ← e.

En C/C++ : x = e.
Attention, cette opération ne correspond pas à l'opération
d'égalité en mathématiques, elle a un sens de droite à gauche !

11
Premier programme
Algorithme Calcul
/* déclaration des variables */
variable x,y type entier

/* lecture d'un entier placé dans x */


lire(x)
/* affectation */
y ← x*x
/* écriture du résultat */
écrire(y)

12
Appel à une fonction existante
On suppose fourni à l'utilisateur un algorithme « fct_sin »
permettant de calculer le sinus d'un nombre.
Un tel algorithme, à la manière d'une fonction mathématique, prend
un paramètre en entrée et fournit un résultat en sortie.
Il existe des fonctions ayant plusieurs paramètres en entrée/sortie

Pseudo-code :
variable x,y type entier
lire(x)
y ← fct_sin(x)
écrire(y)

13
Algorithmique élémentaire

Les types élémentaires

14
Présentation
• Les objets que peuvent contenir les variables sont
généralement classés en catégories ou types. Les objets de
même type sont susceptibles d'être soumis aux mêmes
actions (e.g. j'additionne un nombre à un nombre mais pas un
nombre à un caractère)
• Les types représentent l'ensemble des valeurs que peuvent
prendre les objets de même type
• Les types élémentaires sont prédéfinis par le langage (entier,
réel, booléen, …)
• Le programmeur peut également construire ses propres types
élémentaires pour spécifier un domaine particulier

15
Le type Entier
• Le type entier représente partiellement l'ensemble ℤ des
mathématiciens (ici l'ensemble est fini)
• Un entier est représenté par sa représentation binaire. Un mot
de n bits permet de représenter 2n nombres positifs sur
l'intervalle [0,2n-1]. On utilise la représentation dite de
complément à 2 pour stocker les nombres négatifs [-2n-1,2n-1-1]
• Sur 4 bits 6 est représenté par 0110
• Sur 4 bits -6 est représenté par 1010
• On a bien 0110+1010=0000
• Les opérations classiques s'appliquent sur le type entier ainsi
que les opérations de comparaison

16
Déclaration
• La déclaration d'une variable entière est précédée du type
• Les langages de programmation définissent différentes
plages de valeurs acceptées pour les entiers, correspondant
à différentes tailles mémoire maximales
• Plusieurs variables peuvent être déclarées simultanément
entier court noteEtudiant ;
entier valeur ;
entier long tailleUnivers, nbEtoiles ;
En C/C++ :
short int noteEtudiant; (ou unsigned short int noteEtudiant;)
int valeur;
long int tailleUnivers, nbEtoiles;
17
Le type Réel
• A l'instar du type Entier, le type réel sert à définir partiellement
l'ensemble R des mathématiciens
• Ce ne sont que des approximations plus ou moins fidèles des
nombres réels. Le type réel décrit un nombre fini de
représentants du réel (10233,0000000000000002 et
10233,00000000000000023 risquent d'être confondus)
• Ils ne sont pas uniformément répartis. Plus de la moitié est
concentrée sur l'intervalle [-1,1]
• On parle aussi de flottants
• Les réels et les entiers sont des types disjoints

18
Déclaration des réels
réel court longueur, largeur ;
réel long racinede2 ;

C/C++ : float, double, long double

19
Le type booléen
• Type très simple, mais très utilisé en informatique
• Type comprenant 2 valeurs : vrai et faux
• les opérations applicables sur le type booléen sont le ou, le et,
et le non
• En C : pas de booleén, on utilisera un type de nombre (souvent
int) avec 0 pour faux et tout autre valeur pour vrai. En C++ :
bool. Exemple de déclaration : bool present = true ; (ou false)
• Table de vérité

20
Le type caractère
• Le type caractère permet de représenter des lettres, des
chiffres, des symboles...

• Déclaration :
caractère lettre, note ;
note = 'A' ;
lettre = '{' ;

• En C/C++ :
char note = 'A' ;

21
Dépassement de capacité
• On dit qu'il y a dépassement de capacité, lorsque les
opérations arithmétiques produisent des résultats en dehors
de leur ensemble de définition. Certains langages signalent
les dépassements de capacité, d'autres pas.

22
Conversions de type
• Les langages de programmation pratiquent la conversion
automatique lorsque celle-ci est nécessaire à un calcul
entier court n ← 12 ;
réel court x ← 3.2 ;
réel long y ← n+x ; // conversion de n en réel court puis du résultat de n+x
en réel long

• Il est possible de forcer des conversions. On parle de cast.


On place le type à forcer entre parenthèse, suivi de la valeur
ou variable à caster.
(int) 2.3548 → 2 (perte de précision)

23
Types en C/C++

24
Algorithmique élémentaire

Les expressions

25
Définitions
• Les expressions permettent de composer des opérandes et
des opérateurs
• Les opérandes correspondent à des identificateurs de
variables, de constantes ou encore à des appels de fonctions
• On distingue les opérateurs par leur arité
– unaires : par exemple sin, cos
– binaires : par exemple +
– ternaires, n-aires...
• Les opérations peuvent être composées (plusieurs
opérateurs) et tous les langages définissent un niveau de
priorité
• Les expressions retournent un résultat

26
Règles de priorité
• Du moins prioritaire au plus prioritaire (C et C++)
• = (affectation)
• || (ou)
• && (et)
• == != (égalité et inégalité)
• < > >= <= (opérateurs relationnels)
• + -
• * / % (multiplication, division, modulo)
• ! ++ -- (négation, incrémentation, décrémentation)
• ( ) (parenthésage)
• A niveau de priorité égal, l'évaluation se fait de la gauche vers
la droite

27
Exemples
• x+y+z
• x+y*z
• (x+y)*z
• z=x+y
• z = !x && y+z

28
Type d'une expression
• Toute expression retournant un résultat, l'expression retourne
donc un résultat typé
• 25 + x (avec x de type entier) retourne un entier
• ( j >= 5) et (z < -2) retourne ???
• Il existe un certain nombre de conversions dites implicites qui
sont effectuées automatiquement par le langage

29
Exemple
• Écrire un programme qui lit sur l'entrée standard une valeur
représentant une somme d'argent et affiche le nombre de
billets de 100, 50 et 10€ qu'elle représente

30
Algorithmique élémentaire

Le choix

31
Énoncés conditionnels
• Tous les langages proposent des énoncés conditionnels qui
permettent d'exécuter ou non une action prise en fonction
d'un critère de choix.
• On deux grands formes d'énoncé conditionnel
– l'énoncé si (if) gouverné par un prédicat binaire (le plus utilisé)
– l'énoncé selon (switch) si plusieurs choix sont possibles

32
L'énoncé si
• Dans le cadre d'un choix binaire (c'est-à-dire une expression
booléenne), on utilise l'énoncé conditionnel si
si B alors E1 sinon E2 finsi

• L'énoncé est E1 exécuté si le prédicat booléen B est vrai,


sinon ce sera l'énoncé E2 qui le sera.
• Il est fréquent que l'action à effectuer dans le cas où le
prédicat booléen est faux soit vide, on a ainsi une forme
réduite de l'énoncé si.

33
L'énoncé si
pseudo-code
/* x est un entier quelconque */
si x < 0 alors
x ← -x
sinon
x← 0
finsi
En C/C++ :
if ( x<0 ) {
x=-x ;
}
else { x=0; }
34
Résolution d'une équation du
second degré
équation : ax2 + bx + c = 0
si D>0 : 2 racines, si D=0 : 1 racine double, si D<0 : pas de
solution

35
L'énoncé selon
Pseudo-code En C/C++
selon x switch(x)
{
cas x=0 case 0 :
Écrire(faux) printf(''faux'');
cas x=1 break;
case 1 :
Écrire(vrai)
printf(''vrai'');
par défaut break;
Ecrire(ni 0, ni 1) default :
printf(''ni 0, ni 1'');
finselon
break;
}

36
Rappels d'algorithmique

Les énoncés itératifs

37
Énoncés itératifs
• Le principe de l'énoncé itératif est la répétition d'une action

Dans la plupart des langages, l'énoncé itératif se décline en trois


classes principales :
• L'énoncé tant que
• L'énoncé répéter
• L’énoncé pour

38
L'énoncé tant que
• Sa syntaxe est généralement :
Tant que B faire E fin tant que
• Où B est une expression booléenne. Tant que l'évaluation de
l'expression B retourne la valeur vrai, l'énoncé E est exécuté.
La boucle s'achève lorsque B est faux
• Si B est faux dès le départ, l'énoncé E n'est pas exécuté
• C/C++ :
while ( i<0 ){
i=i+1 ;
}

39
Exemple
• Fonction calculant la factorielle d'un entier passé en
paramètre
Algorithme factorielle
Variables i, fact, n type entier
lire(n)
i←0
fact ← 1
tant que i < n faire
i←i+1
fact ← fact x i
fin tant que
écrire( fact)

40
Trace d'exécution
• Une trace d'exécution correspond à une écriture à la main des
valeurs prises par les variables au cours des différentes étapes
d'un programme.
• On s'en sert particulièrement pour débugger un programme.
Algorithme factorielle
Variables i, fact, n type entier
i fact
lire(n)
i←0 0
fact ← 1 1
tant que i < n faire
i←i+1 2
fact ← fact * i 3
fin tant que
écrire( fact) 4
5

41
Algorithme de multiplication
• Le principe de base de l'algorithme de multiplication procède
par sommes successives. Le produit x*y consiste à sommer y
fois la valeur x.
• On peut améliorer cet algorithme en multipliant x par 2 et en
divisant y par 2 chaque fois que sa valeur est paire. Les
opérations de multiplication et de division par deux sont des
opérations très efficaces en informatique

42
Algorithme produit
Variables x,y,p type entier
lire(x,y)
p←0
tant que y > 0 faire
tant que y est pair faire
y←y/2
x ← x*2
fin tant que
p←p+x
y←y–1
fin tant que
écrire( p )

43
La fonction puissance
• L'algorithme d'élévation à la puissance suit le même principe
que l'algorithme permettant la multiplication de deux entiers.
Le calcul de xy consiste à faire y fois le produit de x.
• De même, ce calcul peut être accéléré, lorsque y est pair, x
est élevé au carré tandis que y est divisé par deux.
• A vous d'écrire l'algorithme

44
Algorithme puissance
Variables x,y,p type entier
lire(x,y)

écrire( p )

45
L'énoncé Répéter
• Sa syntaxe est généralement
répéter E tant que B
• L'énoncé E est exécuté jusqu'à ce que l'évaluation de
l'expression B retourne la valeur vrai. Tant que la valeur est
faux, l'énoncé E est exécuté.
• A la différence du tant que, l'énoncé E est exécuté au moins
une fois
• C/C++ :
do {
i++ ;
} while ( i<0 ) ;
46
L’énoncé pour
• La plupart des langages définissent une construction qui
réalise la même opération en fixant un ordre de parcours sur
un intervalle [min,max]
pour x de min à max faire
E
finpour
• C/C++ :
for ( i=0 ; i <= 5 ; i++ ){
printf(''dans la boucle...\n'') ;
}

47
Exemple
Calcul des éléments de la suite {
U n=U n−1+2 n>0
U 0=1

48
Algorithmique élémentaire

Les tableaux

49
Les tableaux
• Un tableau est un ensemble de variables de type élémentaire
ou non, de même type et dont l'accès à ses éléments se fait
par un indice calculé
• En algorithmique, la déclaration d'un tableau t aura la syntaxe
suivante :
t type tableau [T1] de T2
où T1 et T2 sont respectivement le type des indices et le type
des composants. En général, il n'y a aucune restriction sur le
type des composants alors que le type des indices est un type
discret.

50
Exemple de déclaration
t1 type tableau [[1,6]] de entier

1 entier
2 entier
entier
entier
entier
6 entier

51
Opérations sur les tableaux
• En général, les langages de programmation n'offrent que peu
d'opérations sur les tableaux, il est en général simplement
possible de modifier un composant particulier du tableau
• t[i] désigné la cellule d'indice i dans le tableau t
• En C et en C++, les indices de tableaux commencent à 0.

52
Exemple
Initialisation des éléments d’un tableau de n valeurs aléatoires
constante entier n = 10 /* nb d’éléments du tableau */
variable tab type tableau [ [0,n-1] ] de entier
variable i type entier
pour i de 0 à n-1 faire
tab[i] ← random() /* random retourne un nombre aléatoire */
finpour

53
En C / C++
• Déclaration :
type nomTableau [ nbElements ] ;
• Accès à un élément :
nomTableau [ indice ] ;
• Exemples :
int tab[10]; int taille=4;
for (int i = 0; i < 10; i++) { int tab2[taille]={0,5,8,12};
tab[i] = i;
}

54
Algorithmique élémentaire

Les fonctions

55
Les fonctions/méthodes
• Il arrive fréquemment qu’une même suite d’actions doive être
exécutée plusieurs fois au sein du programme (exemple :
fonction factorielle pour le calcul du sinus) ;
• Une fonction permet d’associer à un nom une suite d’actions,
cette fonction retournera un résultat ;
• L’association d’un nom à une suite d’actions s’appelle la
déclaration ;
• L’utilisation du nom à la place de la suite d’actions s’appelle
un appel de fonction ;
• Les fonctions peuvent avoir besoin de définir des variables
qui sont sans intérêt pour le reste du programme. On parle
alors de variables locales ;
• Point fondamental de la programmation : décomposition par
fonctions. 56
Déclaration de fonctions
• Le rôle de la déclaration de fonctions est de lier un nom à une
suite d’actions sur des objets formels ne prenant des valeurs
effectives qu’au moment de l’appel
• La déclaration est toujours formée de deux composants :
– l’en-tête
• nom de la fonction
• les paramètres formels et leur type
• le type du résultat
• syntaxe : fonction NomFonc( <liste des paramètres formels et leur type>) : type
résultat
• Ex : fonction discriminant(a, b, c : réel) : réel
– Le corps
• suite d’actions
• Syntaxe :
… suite d’actions
finfonc /* NomFonc */ 57
Déclaration de fonctions
– Le corps
Si la fonction retourne une valeur, la fonction doit contenir (en
général à la fin) l’instruction retour valeur (mot clé return en C
comme en C++)

• Il est d’usage de mettre l’ensemble des fonctions avant le


programme principal ;
• Il est possible d’utiliser une fonction dans une autre fonction, il
suffit que la fonction appelée soit écrite dans le code source
avant la fonction appelante

58
Appel d’une fonction
• L’appel d’une fonction est une action élémentaire qui permet
l’exécution de la suite d’actions associée à son nom ;
• Il consiste simplement à indiquer le nom de la fonction avec
ses paramètres effectifs ;

/* appel de la fonction discriminant */


delta ← discriminant(-2.0, 1.0, 3.0) ;

59
Exemple
• Écrire une fonction max à deux paramètres qui calcule la plus
grande valeur entre deux entiers passés en paramètre ;
• En utilisant la fonction précédente, en déduire une fonction
max3 calculant la plus grande valeur entre 3 entiers ;
• En utilisant la fonction max, écrire une fonction max20
permettant de calculer la plus grande valeur contenue dans
un tableau de 20 valeurs entières aléatoires

60
Fonction : maximum de 2
entiers

61
Fonction : maximum de 3
entiers

62
Fonction : maximum de 20
entiers

63
printf
• En C et en C++, printf est la fonction permettant d'écrire vers
la sortie standard (par défaut l'écran)
• On peut écrire des chaînes de caractères (tableaux de
caractères) et les valeurs de variables ou d'expressions.
• Utilisation :
printf(''chaîne'',var1,var2,...) ;
• La chaîne indique où afficher les variables qui suivent à l'aide
de spécificateurs :
int e=3 ; float r=3,2 ;
printf( ''On affiche ici un entier : %d et un réel : %f'' , e , r ) ;

64
Spécificateurs usuels
• %c : caractère
• %d : entier en base 10
• %e : réel avec exposant (ex : 2.99e8)
• %f : réel sans exposant (float)
• %lf : réel double sans exposant (double)
• %s : chaîne de caractères
• %u : entier naturel en base 10 (unsigned)

Type court/long :
• Ajouter h indique un type court : %hd par exemple
• Ajouter l indique un type long : %ld par exemple
65
scanf
• En C et en C++, scanf permet de lire depuis l'entrée standard
(par défaut le clavier). Le principe est similaire à printf.
• Les variables lues doivent avoir été déclarées au préalable.
• Utilisation :
scanf(''chaîne'',&var1,&var2,...) ;
• La chaîne est souvent uniquement composée de
spécificateurs :
int a,b ;
printf(''Entrez deux entiers séparés d'une espace'') ;
scanf(''%d %d'',&a,&b) ;
• Attention à respecter le format à l'exécution !

66
Fonctions particulières
• Le mot-clé void est utilisé pour indiquer qu'une fonction ne
retourne aucune valeur (ex : fonction d'affichage) ou ne prend
aucun paramètre en entrée.
• Ex : fonction helloworld(void) : void

• Le mot-clé static est utilisé lorsqu'une fonction ne doit être


utilisable qu'à l'intérieur du fichier où elle est définie. Cela
peut devenir utile lors de la création de projets de taille
importante.
• Le mot-clé static peut aussi s'appliquer à une variable locale à
une fonction. Une variable locale statique ne sera créée
qu'une fois et gardera sa valeur à chaque appel à la fonction.
• Ex : fonction compteurdappel(void) : void
entier static m=0
m++
finfonc
67
Programmation modulaire
• Les langages C et C++ utilisent les prototypes de fonctions.
• Un prototype indique que la fonction à laquelle il se rapporte
sera définie par ailleurs dans le code (il n'est donc plus
nécessaire de gérer l'ordre dans lequel les fonctions sont
écrites), ainsi que ses types d'entrée/sortie.
• On place généralement les prototypes en début de
programme.
• Le prototype reprend uniquement l'en-tête de la fonction, sans
identificateur, suivie d'un point-virgule.
• Ex :
double puissance2(double) ; /*prototype*/
double puissance2(double x)
{
return x*x ;
} 68
Programmation modulaire
• En langages C et C++, lorsque la taille d'un projet augmente,
on place les prototypes de fonctions dans des headers.
• Les headers portant le même nom que les fichiers contenant
le programme, avec .h comme extension.
• Ex : les fonctions de déplacements dans un jeu, contenues
dans un fichier fctdeplace.c, auront pour header fctdeplace.h
• Les headers sont ensuite inclus en début des programmes
utilisant ces fonctions.

69
Inclusion
• Il est possible de réutiliser dans un programme des éléments
(fonctions, variables...) créées dans d'autres programmes
(par exemple des bibliothèques de fonctions).
• Pour cela on pourra procéder à l'inclusion (mot-clé include)
des éléments désirés, c'est à dire à leur copie textuelle dans
le programme avant compilation par un pré-processeur =>
utilisé en langage C
• Ex : #include <stdio.h> (chevrons : pour des fichiers dans le
répertoire d'installation du langage (répertoire include))
• Ex : #include ''fctdeplace.h'' (guillemets : pour des fichiers se
trouvant dans le répertoire du projet (ou à un chemin à indiquer))

70
Programmation

Compilation et exécution

71
Compilation
• Une fois son programme terminé dans le langage de son
choix (langage source), le programmeur utilise un compilateur
qui traduit son programme dans un langage lisible par la
machine (langage cible).
• Le compilateur vérifie d'abord que le programme est
correctement écrit (mots reconnus, phrases bien écrites et
sens correct des phrases dans le langage source) puis
génère un « programme objet » dans le langage cible après
optimisation.
• Le programmeur ne modifiera pas le programme objet pour le
corriger/l'améliorer, il recompilera le code source après l'avoir
corrigé.

72
Compilation
• Le programme objet créé à la compilation dépend du code
source, du compilateur utilisé, de la machine sur laquelle la
compilation a été faite
• Le programme objet ne pourra être utilisé que sur une
machine compatible
• Il est possible de compiler un fichier exécutable, visant à
effectuer une chaîne d'action, mais aussi de compiler un
fichier non exécutable, par exemple contenant une
bibliothèque de fonctions

73
Exécution
• Un programme objet pourra être généré sous forme
d'exécutable.
• A l'exécution, c'est la fonction principale du programme
(fonction main dans le code source) qui sera appelée.
• Cette fonction ne retournera généralement aucune variable,
mais elle peut prendre des paramètres en entrée (par
exemple un nom de fichier).

74
Programmation

Les pointeurs

75
Utilisation des pointeurs
• Au lancement d'un programme, le système d'exploitation
alloue un emplacement mémoire aux variables du
programme.
• Un pointeur est une variable contenant l'adresse mémoire
d'une autre variable.
• L'utilisation des pointeurs en C et C++ se base sur deux
symboles :
– Le symbole &, qui permet d'accéder à l'adresse d'une variable
– Le symbole *, qui permet d'accéder au contenu d'une adresse
Ex : (on suppose que x est une variable et que P est un pointeur)
P=&x ;
printf("%d ",*P); /* affiche la valeur de x */
*P=10 ; /* x passe à 10 */
x=5 ;
printf("%p ",P); /* ne change pas par rapport à la première ligne (même adresse) */
printf("%d ",*P); /* affiche la valeur de x : 5 */
76
Déclaration de pointeur
• Les variables ont des emplacements mémoires plus ou moins
importants suivant leur type (un entier long prend plus de
mémoire qu'un entier court).
• Un pointeur doit connaître la taille de la variable vers laquelle
il pointe pour pouvoir la décrire correctement. Il faut donc
préciser le type de la variable associée à un pointeur lors de
sa déclaration.
Ex :
int x=12 ;
int *P ; /*déclaration d'un pointeur sur une variable int*/
P=&x ;
• Il est important de toujours initialiser un pointeur (pour ne pas
pointer vers une adresse déjà utilisée)
int *P=NULL ; /*adresse vide*/
77
Pointeur et tableau
• On peut établir une correspondance entre pointeurs et
tableaux : tous deux associent à un identificateur une liste de
'cases' (bits en mémoire / éléments d'un tableau)
• Les adresses des éléments d'un tableau se suivent : l'adresse
du deuxième élément est l'adresse du premier +1
• L'identificateur d'un tableau, utilisé seul, est un pointeur.

int tab[4] = {12, 5, 2, 4};


printf(''%d'',tab) ; /*affiche l'adresse de tab[0]*/
printf(''%d'',*tab) ; /*affiche 12 */
printf(''%d'',*(tab+1)) ; /*affiche 5 */

78
Exercice
int A[9] = {12, 23, 34, 45, 56, 67, 78, 89, 90};
int *P=NULL;
P = A;

Quelles valeurs ou adresses fournissent ces expressions:


• *P+2
• *(P+2)
• &A[4]-3
• A+3
• *(&A[2]+2)+A[1]
• &A[7]-P
• P+(*P-10)
• *(P+*(P+8)-A[7]) 79
Pointeur et tableau 2D
int tab[3][5] = {{ 1, 1, 1, 1, 1}, {10, 10, 10, 10, 10}, {100, 100, 100, 100, 100}};
int *P = tab;
int i, s = 0;
for ( i = 0; i < 15; i++) {
s += *(P + i);
}
printf("%d", s);

80
Allocation dynamique de
mémoire
• Il est possible de demander manuellement à réserver un espace
mémoire (ce qui est généralement fait automatiquement en
déclarant les variables)
• Intérêt : allocation mémoire pour un tableau de taille inconnue à
l'écriture du programme (ex : taille dépendant d'une variable du
programme)
• Méthode : utilisation de malloc et de free
int* P = malloc( nbElem * sizeof(int) ); /* P pointe sur l'adresse d'un bloc mémoire alloué à
un tableau de nbElem éléments de type int */
… /* expressions utilisant P pour travailler sur le tableau */
free(P) ; /* libère la mémoire réservée une fois qu'elle n'est plus utile */
• Remarque : malloc est une fonction qui peut retourner n'importe
quel type de pointeur (suivant les besoins du programmeur). Son
type de retour est void*
81
Pointeurs en entrée de fonction
• En l'absence de pointeur (et de variables statiques) seule la valeur
dans le return peut être modifiée à l'intérieur d'une fonction pour le
reste du programme.
void puissance2(int x) ;
main()
{
int nombre=5 ;
puissance2(nombre) ;
printf(''%d'', nombre) ; /*Résultat : 5 */
}
void puissance2(int x)
{
x *= x ;
}
• Modifier le programme pour modifier la variable nombre à travers
l'appel à la fonction. 82
Pointeurs en entrée de fonction
• Un pointeur permet de modifier une variable en mémoire n'importe où, y
compris à l'intérieur d'une fonction.

• Remarque : lorsqu'un tableau est passé en paramètre d'une fonction, il suit


les mêmes règles et pourra aussi être modifié pour le reste du programme.
Exemple : void unefonction(int tab[])
83
Chaînes de caractères en C/C++
• En C, une chaîne de caractères (ex : ''Hello World'') est un tableau
de caractères.
• char chaine[]=''Hello World !''
• La taille du tableau chaine est 14 : les 13 caractères de la chaîne
plus le caractère \0, qui marque la fin d'une chaîne

• char chaineAuto[10] ;
char* chaineDyn=malloc(10*sizeof(char)) ;
// chaineAuto=''Test'' ; /* ne fonctionne pas. chaineAuto est une adresse. Un tableau doit
être fixé à la déclaration ou être rempli élément par élément */
chaineDyn=''Test'' ; /* fonctionne */
printf("%s\n",chaineDyn);
free(chaineDyn);

84
Tableau de pointeurs
• Un pointeur est une variable. Il est donc possible de définir un
tableau de pointeurs.
• int *tab[10] définit un tableau de 10 pointeurs sur des entiers
tab[4] est un pointeur sur un entier
*tab[4] est un entier

• Particulièrement utile pour les tableaux de chaînes de


caractères de longueurs différentes :
char *jours[7] = {''lundi'', ''mardi'', ''mercredi'', ''jeudi'', ''vendredi'', ''samedi'', ''dimanche''} ;
int i ;
for (i=0; i<7; i++) printf("%s\n", jours[i]); /* affiche tous les jours */
printf("%s\n", *(jours[3]+2)); /* affiche le u de jeudi */

85
Pointeur sur fonction
• On peut pointer sur une fonction : là aussi on pointe sur son
emplacement mémoire (l'emplacement de sa première
instruction).
• int (*unefonction)(double) ; /* déclare un pointeur sur une
fonction prenant un double en entrée et retournant un entier */
• (*unefonction)(5) permet d'évaluer la fonction pointée en 5.
• On peut alors par exemple passer un pointeur sur fonction en
paramètre d'une autre fonction.
double (*fct)(double);
fct=sin;
printf("%f\n",fct(0)); /* affiche 0 */
fct=cos;
printf("%f\n",fct(0)); /* affiche 1 */

86
Programmation en C

Structures

87
Déclaration d'une structure
• Une structure peut contenir n'importe quels éléments de types
différents (ou non, mais on a déjà les tableaux pour ça) : int, double,
double[], *short...
• Mot-clé : struct
• Exemple :
struct personne {
char[10] nom;
char[10] prenom;
int age;
}; /* ne pas oublier le ; de fin de définition de structure */

88
Utilisation d'une structure
• Pour accéder aux différents éléments d'une structure, on utilise
l'opérateur '' . ''
• Exemple :
struct personne Pers ;
Pers.nom ;
• On ne peut qu'accéder et modifier les éléments d'une structure, la
copier en totalité ou récupérer son adresse : il n'existe pas
d'opérations sur les structures.
• On peut définir des fonctions ayant une structure en entrée ou en
sortie.

• On peut faire un parallèle entre les structures en C et la


programmation orientée objet (ex : C++)

89
Exercice
Compléter le code. La fonction creerpersonne doit initialiser l'ensemble
des éléments d'une structure personne
struct personne {
char* nom;
char* prenom;
int age;
};
struct personne creerpersonne(#####################){
#####################
}
void main(){
struct personne pers1;
pers1=creerpersonne("Jean","Dupond",36);
printf("%s %s a %d ans",#####################);
}
90
Exercice

91
Définition d'un ''type'' par une
structure
• typedef permet de définir ses propres mots-clés de type.
• Il est donc possible d'associer un nom de type à une structure que
l'on aura créé soi-même.
Ex :
typedef struct personne Personne;
struct personne
{
char[10] nom;
char[10] prenom;
int age;
};
• Désormais, écrire « Personne » revient à écrire « struct personne »
92
Programmation en C

Ecriture séquentielle de fichier

93
Interactions avec un fichier en C
• Les différentes variables d'un programme ne sont
enregistrées que temporairement (le temps de l'exécution)
dans la mémoire vide.
• Pour conserver des variables, il faut les enregistrer sur le
disque dur (ou sur un support externe).
• La bibliothèque stdio propose des fonctions pour lire et écrire
des fichiers.
• fopen() : ouverture de fichier
fprintf() : écriture dans un fichier
fgetc() : lecture dans un fichier (caractère par caractère)
fclose() : fermeture de fichier
fseek() : positionne dans le fichier
ftell() : indique la position dans le fichier
94
fopen et la structure FILE
• fopen retourne un pointeur sur un ''type'' FILE :
FILE* fopen(const char* nomfichier, const char* mode); /*header de fopen*/
• FILE est en fait un type qui a été défini à partir d'une structure par
utilisation de typedef. On n'accédera jamais aux éléments d'un FILE
(on ne fera jamais file.element)
• Quelques modes d'ouverture de fichier :
• "r" : lecture seule.
• "w" : écriture seule.
• "a" : ajout à la fin du fichier.
• "r+" : lecture et écriture.
• "w+" : lecture et écriture, avec suppression préalable du contenu.

95
fclose, fprintf, fgetc, fseek, ftell
• fclose ferme le fichier FILE passé en paramètre. Renvoie 0 si la
fermeture a réussi.
• fprintf fonctionne à la manière de printf, mais prend le fichier FILE
en premier paramètre
• fgetc retourne le prochain caractère du fichier FILE passé en
paramètre. Une structure conserve la position du dernier caractère
lu en mémoire.
• fseek prend trois paramètres en entrée : le nom du fichier FILE, un
nombre de déplacements de caractères et une position de départ
qui peut être SEEK_SET (début du fichier), SEEK_CUR (position
actuelle) ou SEEK_END (fin du fichier).
• ftell retourne la position actuelle (type long) dans le fichier passé en
paramètre.

96
Exemple
FILE* fichier = NULL;
int nombre = 3, caractere = 0;
fichier = fopen("test.txt", "w"); /* crée le fichier si inexistant */
fprintf(fichier, "Test d'écriture avec une variable int : %d\nsuivi d'un passage à la
ligne\n", nombre);
fclose(fichier);
fichier = fopen("test.txt", "r");
while (caractere != EOF) {
caractere = fgetc(fichier);
printf("%c", caractere);
}
fseek(fichier,5,SEEK_SET) ;
caractere = fgetc(fichier);
printf("%c", caractere);
fclose(fichier);
97

Vous aimerez peut-être aussi