Algorithme et programmation C
Dr Yannogo Hermann
Plan du cours
1. Généralités sur l’algorithmique et la programmation
2. Rappel sur les notions de basesStructures de données
3. Procédures et fonctions
4. Notions de pointeurs et allocation dynamique
Sommaire
▪ Objectifs de ce cours
Comprendre les notions de bases en algorithmique et programmation
Savoir écrire et écrire un algorithme et le traduire en langage C
Maîtriser l’utilisation du langage C pour réaliser la mise en œuvre d’algorithmes et le
développement d’applications de petite taille
Présentation du langage C
▪ Historique
Date Description
1978 Création du langage C dans les laboratoires Bell par les chercheurs B. Kernighan et D.
Ritchie
1980 Invention du langage C++ par Bjarne Stroustrup (informaticien danois)
➢ Extension du langage C par la programmation Objet
1983 Création du langage Objective - C par Brad Crox
➢ Extension du langage C, pour la programmation objet
➢ Très utilisé par Apple pour la conception des interfaces graphiques de MacOS
1990 Normalisation du Langage C par la norme ANSI/ISO
➢ Normalisé par la norme ANSI/ISO (C99 ou Ansi C)
1998 Normalisation du Langage C++ par l’ANSI/ISO
Présentation du langage C
▪ Pourquoi choisir le langage C ?
Sa popularité
➢ Un des langages de programmation les plus utilisés
➢ Il possède une communauté très importante et de nombreux tutoriels et documentations
➢ Il existe beaucoup de programmes et de bibliothèques développés en/et pour le C
20
Présentation du language C
▪ Pourquoi choisir le langage C ?
Sa rapidité
➢ Connu pour être le langage très rapide
➢ Langage de choix pour tout programme où la vitesse d’exécution est cruciale
➢ Langage à cheval entre les langages haut niveau et bas niveau
Sa légèreté
➢ Très utile pour les programmes embarqués où la mémoire disponible est faible
Sa portabilité
➢ Un programme développé en C marche théoriquement sur n’importe quelle plate-
entation du langage C
forme
➢ Le C a été conçu pour la programmation système (pilotes, systèmes d'exploitation,
matériel embarqué, etc)
▪ Quels sont les outils nécessaires au programmeur ?
3 éléments minimums sont nécessaires :
Un éditeur de texte :
➢ Utile pour écrire le code source du programme
➢ Exemple : bloc-notes, notepad++, …
Un compilateur:
➢ Transforme (ou compile) le code source en langage binaire
Un debogueur:
➢ Très utile pour traquer les erreurs dans votre programme
Il existe des environnements intégrant les trois éléments à la fois. On les appelle des IDE
(Environnement de Développement Intégré)
▪ Les environnements de développement intégré (EDI ou IDE)
Visual C++
➢ IDE propriétaire de Microsoft
➢ Fonctionne uniquement sous Windows
➢ Version payante
➢ Il existe des versions gratuites : Visual C++ express (très complet)
Eclispe CDT (C++ Development Tools)
IDE gratuit et complet offrant des fonctionnalités facilitant la programmation
Multiplateforme (Windows, Linux et Mac)
Présentation du langage C
▪ Les environnements de développement intégré (EDI ou IDE)
Dev – C++
➢ IDE gratuit
Code::Blocks
➢ IDE gratuit et disponible pour la plupart des systèmes d’exploitation
➢ Très simple d’utilisation et possède une complétion très riche
▪ Les compilateurs du C++
Visual C++ build (Microsoft)
Borland C++ builder
Gratuit
Utilisable sous Windows et linux
GCC (GNU Compilation Collection)
➢ Excellent compilateur, gratuit et le plus utilisé
➢ Multiplateforme
➢ Compilateur multi-langage (C, C++, Java, …)
Nous allons utiliser plutôt le GCC
Code::blocks intègre tous les compilateurs
Les variables
▪ Type de variable
Lorsqu’on déclare une variable, il faut préciser ce que l’on voudra mettre dedans c’est le
type
Types numériques : entier (int en C), réel (double ou float en C)
Type alphanumérique : caractère, chaine de caractères (char en C)
Type booléen (valeurs logiques VRAI, FAUX)
Les variables
▪ Les variables en Langage C
La déclaration d’une variable s’écrit
Type nomVariable;
Type nombreVariable = valeur;
Attention
Le langage C n’initialise pas les variables avec des valeurs par défaut
Une variable non initialisée possède une valeur indéterminée
Source de nombreux « bugs »
Règle : toujours initialiser les variables
118
▪ Les variables en Langage C
Le langage C est sensible à la casse (majuscule/minuscule)
Exemple : somme # Somme
Les espaces sont interdits dans les noms de variables
A la place, on peut utiliser le caractère underscore « _ »
Exemple : variable indiquant le nombre de vie d’un joueur : nombre_de_vie ou
nombreDeVie
Vous n’avez pas le droit d’utiliser des accents (é, à,ê, etc.).
Exemple : on ne peut pas ecrire « précaution » mais « precaution »
119
Les variables
▪ Les variables en Langage C
Pour afficher le contenu d’une variable, on utilise la fonction « printf » et une commande
spécifique
Exemple : code permettant d’afficher le nombre de vie d’un joueur :
printf("Il vous reste %d vies" , nombreDeVies);
Ce « symbole spécial » est un '% suivi d'une lettre (dans mon exemple, la lettre 'd').
Cette lettre permet d'indiquer ce que l'on doit afficher. 'd' signifie que l'on souhaite
afficher un entier « int »
120
▪ Les variables en Langage C
Il existe plusieurs autres possibilités, mais pour des raisons de simplicité on va se contenter
de retenir celles-ci
Format Type attendu
« %d » int
« %ld » long
« %f » Float, double
Pour récupérer les informations saisies par l’utilisateur sur le clavier, on utilise la fonction
« scanf ». Pour ce faire, une fois l’information saisie, on va le récupérer et le stocker dans
une variable
double poids = 0;
scanf("%lf", &poids);
121
▪ Les variables en Langage C
Exemple : Traduction en C de l’algorithme convertissant un nombre de secondes sous
forme d’heure, minutes et seconde
122
Les opérations de bases
▪ Les opérateurs mathématiques
Il s’agit des opérations usuelles
L’addition : +
La soustraction : -
La multiplication : *
La division : /
Le modulo : mod ( « % » en C)
▪ Les opérateurs relationnels (ou booléens)
< (inférieur) , > (supérieur) , <= (inférieur ou égal) , >= (supérieur ou égal) , =(égal, en C,
on utilise ==) , <>(différent de – en C, on utilise !=)
123
Les opérations de bases
▪ Les opérateurs logiques
Types En C
Négation !
Et logique &&
Ou logique ||
▪ Autres opérations
Incrémentation (++) et décrementation (--)
➢ Elle consiste respectivement à incrémenter (et décrementer) la valeur d’une variable de 1
Affectation avec opération
➢ Addition: +=, ex : a += b a = a + b
➢ Soustraction: -=, ex : a -= b a = a – b
➢ Multiplication: *=, ex : a *= b a = a * b
➢ Division: /=, ex : a /= b a = a / b
124
Structures de contrôle et boucles
▪ Structure de contrôles
Les structures conditionnelles ou alternatives permettent de réaliser des opérations en
fonction d'une condition. On distingue :
Les conditions simples
Conditions à choix multiple
Conditions simples : si … sinon … finsi
125
Structures de contrôle et boucles
▪ Structure de contrôles
Conditions à choix multiple : selon que .. Autrement … finselonque
43
En langage C :
126
Structures de contrôle et boucles
▪ Les boucles
Elles permettent de répéter une opération autant de fois que nécessaire;
On distingue 3 types de boucles :
La boucle « pour »
Elle est employée quand on connait a priori le nombre d’itération à effectuer
Notation LDA En langage C
127
Structures de contrôle et boucles
▪ Les boucles
Elles permettent de répéter une opération autant de fois que nécessaire;
On distingue 3 types de boucles :
La boucle « tant … que »
Utilisée quand on connait pas le nombre d’opération à effectuer
Notation LDA En langage C
128
▪ Jusqu’ici, nous avons travaillé les variables
➢ Rappel : une variable ne permet de stocker qu’une seule et unique valeur
▪ Que se passe t-il si on devait stocker plusieurs valeurs du même type? Et de types différents ?
▪ Dans ce chapitre, nous verrons particulièrement deux types de variables permettant de
stocker plusieurs valeurs :
Les tableaux
Les types structurés
➢ La définition de ces types est dépendante du langage
➢ En particulier, en C, nous verrons principalement:
➢ Les structures
129
▪ Définition
Un tableau (encore appelé table ou variable indicée) est un ensemble de données, qui sont
toutes de même type, désigné par un identificateur unique (le nom du tableau), et qui se
distinguent les une des autres par leur numéro d’indice
L’accès à un élément du tableau se fait grâce son indice
Attention : l’écriture de Température[-2] ou Température[12] n’ont pas de sens car elles
130
Tableaux
▪ Déclaration de tableau
Trois éléments définissent un tableau:
➢ Son nom : identificateur respectant les règles classiques des identificateurs d’un
programme
➢ Le nombre de ses éléments
➢ Le type de données qu’il contient
Un tableau à plusieurs dimensions est un tableau pour lequel l’accès à un élément se fait en
utilisant plusieurs indices
131
Tableaux en C
▪ Déclaration
Type nomTableau [taille1]…[taillek] ;
Attention : La taille du tableau (ou nombre de cases) est forcément fournie à la déclaration
Exemple :
int tab[1000] ; // Déclaration d’un tableau d’entiers de 1000 éléments
float notes[40][10];
Déclaration d’un tableau initialisé
Type nomTableau[] = {valeur1, valeur2,…,valeurN} ;
La taille est déduite du nombre de valeurs fournies
132
Exemple :
// Déclaration d’un tableau de 4 éléments initialisés
int tab[] = {10, 11, -1, 5} ; // tableau variable 54
▪ Parcours d’un tableau
Le parcours d’un tableau se fait grâce aux indices variant entre 0 et la taille (du tableau) - 1
Exemple : cas de la température
133
Les structures
▪ Généralités
Le type tableau est une structure composée de plusieurs éléments de même type
Supposons que l’on souhaiter travailler sur un fichier de personnes et on voudrait
regrouper une variable de type « chaine de caractères » pour le nom, une variable de type
« entier » pour le numéro d’employé, …
Impossible d’utiliser un tableau car ne contenant qu’un seul type de données
Pour regrouper les informations de différents types, un autre structure composée appelée
type structuré(ou enregistrement ou struture) est recommandé
134
▪ Déclaration d’une structure en C
La déclaration se fait comme suit :
struct nomStructure
type1 nomChamp1;
type2 nomChamp2;
typen nomChampn;
};
Chaque élément déclaré à l’intérieur de la structure est appelé un champ
Attention : on a fait que déclarer un type de structure, pas une variable. Pour
déclarer une variable du type « nomStructure », on procède comme suit :
struct nomStructure A, B ;
135
Les structures
▪ Déclaration d’une structure en C
Exemple : Nous souhaitons écrire une structure « Adresse » permet de gérer des adresses
postales. Les champs d’une adresse sont :
Un numéro de porte (int)
Le nom de la rue (char)
Le numéro du secteur (char)
struct Adresse
int numero ;
char rue[50] ;
int secteur ;
};
Pour déclarer des variables de type « Adresse », on procède ainsi :
struct adresse chezFati, chezSogotele
136
Les structures
▪ Déclaration d’une structure en C
Remarque : Il est possible de combiner la déclaration de la structure et celle des variables
associées comme suit
struct Adresse
int numero ;
char rue[50] ;
int secteur ;
} chezFati, chezSogotele ;
137
▪ Accès au champs d’une structure en C
Pour accéder aux données contenues dans les champs d’une structure, on fait suivre le
nom de la structure par un point "." et le nom du champ voulu :
[Link]=19 ;
printf(“%s”,[Link]);
On peut initialiser une structure lors de sa déclaration :
struct Adresse chezFati= { 15 , "rue M. Yaméogo", 8 } ;
▪ Affectation
Si deux variables sont de même structure alors on peut effectuer une affectation:
➢ chezJean = chezFati ; /* Jean a emménagé chez Fati ! */
Attention : on ne peut pas comparer 2 variables de même structure (avec == ou !=).
138
Les structures
▪ Structure de structure en C
On peut utiliser une structure comme champ d’une autre structure.
Dans la lignée des exemples précédents, on peut définir une structure adresse qui pourrait
être utilisée dans la structure repertoire ou toute autre structure.
struct adresse {
int numero ;
char rue[50] ;
int secteur;
};
struct repertoire {
char nom[20] ;
char prenom[20] ;
struct adresse maison ;
};
139
▪ Tableau de structure en C
La déclaration et l’utilisation d’un tableau de structure en C se fait de la même façon qu’un
tableau de variables simples. Le nombre d’éléments est précisé entre crochets.
struct adresse pers[100] ;
Cette déclaration nécessite que la structure adresse ait déjà été déclarée avant.
« pers » est alors un tableau dont chaque élément est de structure de type adresse.
« pers[i].rue » fait référence au champ « rue » du ième élément du tableau « pers ».
140
Les énumérations
▪ Déclaration
Un type énuméré est un type simple correspondant à une liste de valeurs symboliques (i.e.
des noms). Une variable de ce type ne peut prendre sa valeur que parmi ces symboles.
Pour déclarer un type énuméré, on utilise le mot-clé « enum », suivi de la liste de symboles
séparés par des virgules :
Chaque valeur est en réalité associée à une valeur entière dont le premier champ prend la
valeur 0 et les autres champs s’incrementent de 1
Pour déclarer une variable de ce type
64
enum nom_du_type
valeur_1,
valeur_2,
};
enum nom_du_type nomVariable = valeur_i ;
141
Exemple : on souhaiterait gérer les mois de l’année
enum Jour
};
Pour déclarer une variable enum Mois x = JANVIER
Remarque : Il est possible de spécifier une valeur (entière) à l’un des champs
enum Mois
};
142
▪ Utilités
Nous avons vu que pour déclarer une structure (car de l’« Adresse »), on utilise la syntaxe :
struct adresse
int numero ;
char rue[50] ;
int secteur;
};
La déclaration des variables se fait : struct Adresse ChezFati
Si l’on déclare cette structure en utilisant le mot clé « typedef » comme suit :
typedef struct adresse
int numero ;
char rue[50] ;
int secteur;
};
Alors la déclaration d’une variable de type « Adresse » se fera sans l’utilisation de « struct »
Le mot clé « typedef » permet d’éviter la répétition « struct » lors de la déclaration d’une
variable. Cela est valable pour tous les types structurés
143
Les Procédures et les fonctions
▪ Définition et utilité
Les procédures et fonctions permettent de décomposer un programme complexe en
plusieurs parties plus simple et relativement indépendantes (aussi appelées sous-
programmes)
Les avantages:
☺ Elles peuvent implémentées et testées séparément
☺ Si le même traitement est nécessaire en plusieurs point du programme, on se contente
d’appeler la fonction (ou procédure) correspondante plusieurs fois au lieu de
dupliquer le code source ;
☺ Une même fonction (ou procédure) peut être utilisée dans plusieurs programmes
différents, grâce au concept de bibliothèque
Les aspects les plus importantes des fonctions et procédures sont leur création et leur
144
Les Procédures et les fonctions
▪ Fonctionnement d’un programme
Un programme (ou algorithme) peut être composé d’un ou plusieurs sous-programmes
(exécutant des taches bien définies)
Un sous-programme est obligatoirement caractérisé par un nom (un identifiant) unique
145
▪ Environnement d’un sous-programme
Un sous-programme est caractérisé par 3 types de variables :
Les variables globales : elles sont définies dans le programme appelant et ont donc
une portée globale
Les variables locales : Elles sont définies à l’intérieur du sous-programme et ne sont
pas accessible en dehors du sous-programme. Leur portée est locale
Les variables formels : Il s’agit des variables d’entrées servant d’échanges entre les
programmes appelant et appelé
146
Les procédures
▪ Définition
Une procédure est un sous-programme représentant une ou plusieurs actions, et ne
retournant aucune valeur, sauf en paramètre.
Déclaration
72
147
3.3 Les fonctions
▪ Définition
Une fonction est un sous-programme à l’image d’une procédure mais qui retourne des
valeurs
Déclaration
74
148
Appel de fonction (ou procédure)
▪ Méthodologie
Pour utiliser une fonction (ou procédure), on fait un appel en lui passant des expressions
correspondant aux paramètres dont elle a besoin
La syntaxe est la suivante :
nomFonction( param1, param2, …, paramk) ;
Exemple : Appel des procédure et fonction défini précédemment
Age( 1901)
X Maximum(45, 1)
Remarque : lors de l’appel d’une fonction (ou procédure), un paramètre formel (ou
argument) d’une fonction (ou procédure) peut être une variable ou une valeur mais doit
149
Appel de fonction (ou procédure)
▪ Remarque
Une fonction (ou procédure) avant d’être appelée doit être préalablement définie (et
implémentée)
Etant donnée qu’une fonction retourne une valeur, il est possible d’affecter cette valeur à
une variable ou peut être utilisée dans une autre fonction ou expression
77
Passage des paramètres
▪ Il existe principalement 3 modes de passages des paramètres
Le passage par valeur
Le passage par adresse
Le passage par référence
On s’interessera uniquement aux 2 modes (les seuls modes utilisés en C)
150
Passage des paramètres
▪ Passage par valeur
Lorsque les paramètres formels sont transmis à une procédure (ou fonction) en mode
passage par valeur alors toute modification de ces paramètres dans la procédure ne sont
sans effet dans le programme appelant.
Le programme appelant garde les mêmes valeurs des paramètres avant et après appel de la
procédure. Pour déclarer ces paramètres, on parle de « Données »
Exemple
151
Passage des paramètres
▪ Passage par adresse
Pour ce mode de passage, toute modification de ces paramètres dans la procédure (ou
fonction) aura un effet dans le programme appelant.
En LDA, les paramètres en mode passage par adresse sont appelés « Données
Modifiées ». En langage C, ces paramètres sont des pointeurs
152
Fonction
ions et procédures en C
▪ Syntaxe de déclaration
Type nomFonction( Type idParam1, Type idParam2, …, Type idParamN )
{
Le type de retour d’une procédure est un « void »
Pour une fonction, le type de retour peut être un entier (int), un réel (float), …
Dans le corps d’une fonction, on doit avoir obligatoirement l’instruction « return »
permettant de renvoyer le résultat attendu de la fonction
153
Fonctions et procédures en C
▪ Exemple
Reprenons les exemples précédent
void Age (int annee_naissance)
int age; int main ()
age = 2020 – annee_naissance
printf(‘vous avez %d ans’, age) int maxi;
if( a >
maxi = a;
int Maximum (int a, int b)
else{
int maxi; maxi = b;
if( a > b){
maxi = a; return maxi;
else{
maxi = b;
return maxi;
154
82
Fonctions récursives
▪ Définition
On appelle fonction récursive toute fonction qui s’appelle elle-même
Elle permet de coder des fonctions (mathématiques) définie à partir de relation de
récurrence
Exemple : calcul du factoriel d’un nombre entier
o 1ère définition
• n! = 1 * 2 * 3 * 4 * … * n
• Traduction par une boucle :
o 2ème définition:
155
Fonctions récursives
▪ Définition
Exemple : calcul du factoriel d’un nombre entier
156
Fonctions récursives
▪ Définition
Dérouler cet algorithme pour factoriel(5)
3.7 Exercices
157
Notions de pointeurs et allocation dynamique
158
Généralités
▪ Un des chapitres les plus importants du langage C/C++
Le cœur du langage C/C++
▪ Les pointeurs sont totalement indispensables car on s'en sert tout le temps
▪ Nous verrons des cas de problèmes qu’on ne pourra pas résoudre sans utiliser de pointeurs
▪ La notion de pointeurs est intrinsèquement liée à la notion de mémoire
159
Notion d’adressage mémoire
▪ Mémoire vive d’un ordinateur (Rappel)
➢ Schéma
▪ La mémoire vive contient 2 éléments (en colonne)
▪ les adresses : une adresse est un nombre qui permet à
l'ordinateur de se repérer dans la mémoire vive
➢ Commence à l'adresse 0 (au tout début de la mémoire)
➢ Plus vous avez de mémoire vive, plus il y a d'adresses,
▪ Les valeurs : à chaque adresse, on peut stocker une valeur (un
nombre) : votre ordinateur stocke dans la mémoire vive des
nombres pour pouvoir s'en souvenir par la suite.
▪ On ne peut stocker qu'un nombre par adresse !
160
Notion d’adressage mémoire
▪ Exemple
Exemple
int main() /* Plus petit programme C/C++. */
{
int ageUtilisateur = 16;
return 0;
}
1 2 3 4 5 …
14562 14563 14564 14564 14565 … ageUtilisateur
16
53567 53568 53569 53570 53571 …
… … … … … …
… … … … … …
… … … … … …
Notre programme utilise une seule de ces cases, la 14562, pour y stocker sa variable.
Jusqu’à présent, la manipulation de la « 16 » était possible grâce à la variable « ageUtilisateur »
161
Notion d’adressage mémoire
▪ Chaque variable possède une seule adresse et que chaque adresse correspond à une seule
variable.
L'adresse est donc un deuxième moyen d'accéder à une variable.
▪ On peut atteindre la case rose (la valeur 16) du schéma par deux chemins différents :
Le nom de la variable
Dans l’exemple, il s’agit de ageUtilisateur
L’adresse de la variable i.e son numéro de case
➢ l’adresse 14562
D’où la notion de pointeur
162
Notion de pointeurs
▪ Définition
Un pointeur est une variable qui contient l'adresse d'une autre variable.
➢ L'adresse contenue dans un pointeur est celle d'une variable qu'on appelle variable
pointée.
➢ On dit que le pointeur pointe sur la variable dont il contient l'adresse.
➢ Un pointeur est associé à un type de variable sur lequel il pointe. Par exemple, un
pointeur sur entier ne peut pointer que sur des variables entières.
163
Notion de pointeurs
▪ Déclaration
Il faut déclarer le type de la variable pointée.
Par convention, les variables pointeurs commencent par la lettre p.
Syntaxe (langage C) :
Type * nom_pointeur
Exemple :
int * p_toto
Note : * est appelé opérateur de déréférencement
164
Notion de pointeurs
▪ Exemple
{
// Pointeur sur un entier
int * ptr_int ;
// Deux pointeurs sur des réels
float * ptr_int1, * ptr_int2 ;
// Pointeur vers une instance de vecteur
}
Attention : un pointeur est une variable de type élémentaire. Sa valeur n’est donc pas
initialisée par défaut (source de très nombreux bugs).
Il faut toujours initialiser un pointeur
165
Notion de pointeurs
▪ Initialisation
▪ Pointeur ne pointant sur rien : NULL
{
// Un pointeur ne pointant sur
rien
Type * ptr_variable = NULL ;
}
▪ Initialisation à partir de l’adresse d’une variable
➢ Utilisation de l’opérateur & : renvoi l’adresse d’une variable
{
// Déclaration d’une variable
Type var ;
// Initialisation d’un pointeur par l’adresse d’une variable
Type * ptr_identifiant = & var ;
}
166
Notion de pointeurs
▪ Exemple
{ int i = 15
// Déclaration d’une variable de type entier (int)
int i = 15 ;
// Déclaration et initialisation de deux pointeurs
int * int *
// sur cette variable de type entier (int) ptr1_i ptr2_i
int * ptr1_i(&i) ;
int * ptr2_i = &i ;
}
167
Notion de pointeurs
▪ Déréférencement ou indirection
Déréférencer un pointeur consiste à extraire la valeur de la variable sur laquelle il pointe.
Utilisation de l’opérateur * : récupération de la valeur pointée
Soit ptr un pointeur
La valeur pointée est accessible (lecture/écriture) via l’expression *ptr
▪ Exemple
{
// Variable de type entier
int a = 10 ;
// Pointeur sur cette variable
int * ptr_a(&a) ;
// Déclaration d’une seconde variable
int b = *ptr_a ; // b vaut 10 (initialisé à partir de la valeur de a, pointée par ptr_a)
// Changement de la valeur de a, pointée par ptr_a
(*ptr_a) = 5 ; // a vaut 5
// Incrementation de la valeur de a, pointée par ptr_a
(*ptr_a)++ ; // a vaut 6
}
98
168
Notion de pointeurs
▪ Syntaxe algorithmique
Syntaxe C/C++
syntaxe algorithmique
int n = 33;
Variables
int *p; //déclaration du pointeur p
n: entier
p = &n; // p pointe sur n
p: pointeur sur entier
Début
cout << *p //affiche 33 à l'écran, la valeur
p ← @n // adresse de n p pointe sur n
de n
afficher *p // affichée
*p ← 34 // n vaut maintenant 34
*p = 34 // n vaut maintenant 34
169
Pointeurs et structures de données
▪ Pointeur et tableau
Déclaration d’un tableau à une dimension
Type tab[NB] ;
➢ Le nom d'un tableau représente l'adresse de son premier élément.
➢ En d'autre termes: &tab[0] et tab sont une seule et même adresse.
Déclaration d’un pointeur vers le premier élément
Type * p_tab =&tab[0] ;
➢ ou
Type * p_tab = tab ;
Il existe une arithmétique sur les pointeurs
100
170
Pointeurs et structures de données
▪ Pointeur et tableau
▪ Arithmétique sur les pointeurs
Relation 1 : *(p_tab + i) tab[i]
0 1 2 i … NB -1
p_tab …
p_tab+1
p_tab+i tab
Relation 2 : tab &tab[0]
Relation 3 : tab[i] *(tab+i) *(p_tab+i) p_tab[i]
171
Pointeurs et structures de données
▪ Pointeur et tableau
Cas d’un tableau à deux dimensions
➢ Un tableau à 2 dimensions est un tableau dont les éléments sont eux-mêmes des
tableaux
➢ Ainsi, le tableau défini par int tab[4][5] ; contient 4 tableaux de 5 entiers chacun.
➢ tab donne l’adresse du 1er sous-tableau,
➢ tab+1 celle du 2ème sous-tableau et ainsi de suite :
172
Pointeurs et structures de données
▪ Pointeur et chaines de caractères
De la même façon qu'un pointeur sur « int » peut contenir l'adresse d'un nombre isolé ou
d'un élément d'un tableau, un pointeur sur un « char » peut pointer sur un caractère isolé
ou sur les éléments d'un tableau de caractères.
Un chaîne de caractères est représentée en langage C par un tableau de caractères.
Exemple d’initialisation
char *c;
c = "Salut !";
173
Pointeurs et structures de données
▪ Pointeur et chaines de caractères
Attention : Il existe une différence importante entre les deux déclarations:
char T[] = "Salut !"; un tableau
char *C = "Salut !"; /* un pointeur */
➢ T est un tableau qui a exactement la grandeur pour contenir la chaîne de caractères et la
terminaison '\0'. Les caractères de la chaîne peuvent être changés, mais le nom T va toujours
pointer sur la même adresse en mémoire.
➢ C est un pointeur qui est initialisé de façon à ce qu'il pointe sur une chaîne de caractères
constante stockée quelque part en mémoire. Le pointeur peut être modifié et pointer sur autre
chose. La chaîne constante peut être lue, copiée ou affichée, mais pas modifiée.
174
Pointeurs et structures de données
▪ Pointeur et structure
▪ Supposons que l’on ait défini la structure « struct personne » à l’aide de la déclaration :
struct personne {
char nom[60] ;
char prenom[60]
int age ;
int secteur;
};
On déclarera une variable de type pointeur vers la structure « personne » de la manière
On pourra alors affecter à « p » des adresses de « struct personn
e»
struct personne pers = {"sanou", "sogotèlè", 15, 27}; 105
175
Pointeurs et structures de données
▪ Accès aux éléments d’une structure pointée
Pour accéder aux éléments d’un pointeur de structure, on peut utiliser 2 méthodes:
Méthode du déréférencement
(* p).champ1;
Utilisation de l’opérateur « → »
p →champ1
Exemple
struct personne {
};
struct personne pers = {"sanou", "sogotèlè", 15, 27};
106
printf("nom : %s\nprésom : %s", (*p).nom, p->prenom)
176
Allocation dynamique
▪ Définition
L'allocation dynamique de mémoire permet à un programme en cours d‘exécution de
réserver un espace mémoire dont la taille n'est pas nécessairement connue lors de la
compilation.
Cette allocation de la mémoire gérée manuellement
La libération de la mémoire gérée manuellement
Attention : Responsabilité du programmeur
Règle : tout objet créé dynamiquement doit être désalloué
L'allocation dynamique est réalisée par les fonctions « malloc() » et « calloc () ».
Quant à la libération de la mémoire, on utilise la fonction « free() »
177
Allocation dynamique
▪ Fonction « Malloc(…) »
Cette fonction permet de réserver un bloc de taille t (en octets) et renvoie un pointeur vers
l'adresse du bloc alloué s'il y a suffisamment de mémoire disponible;
Son prototype est :
void* malloc( size_t t)
En cas d’erreur, cette fonction renvoie « NULL »
Pour l’utiliser il faut inclure la bibliothèque <stdlib.h> en début de programme.
Exemple :
i n t *a ;
a= ( i n t ∗) m a l l o c ( s i z e o f ( i n t ) ) ;
*a=25;
La fonction « malloc » alloue (si possible) un bloc mémoire pour 1 « int » et retourne
l'adresse (non typée, void ∗) du bloc. On effectue alors une conversion de type : void ∗
vers int ∗. 108
178
Allocation dynamique
▪ L’opérateur « sizeof(type) »
D’une machine à une autre, la taille réservée pour un « int » ou un « float », peut varier.
L’opérateur « sizeof » permet de réserver la mémoire en tenant compte des spécificités de
la machine
Exemple :
printf("char : %d octets\n", sizeof(char));
printf("int : %d octets\n", sizeof(int));
179
Allocation dynamique
▪ Fonction « free() »
La fonction « free() » permet de libérer de la mémoire préalablement allouée par les
fonctions « malloc() ».
En paramètre, on passe l'adresse du bloc mémoire à libérer.
Son prototype :
void free(void* p)
Exemple :
#include<stdio.h>
#include<stdlib.h>
int main() {
int* memoireAllouee ;
memoireAllouee =(int*) malloc(sizeof(int)); // Allocation de la mémoire
if (memoireAllouee == NULL) {
exit(0); Erreur : on arrête tout !
}
Utilisation de la mémoire
printf("Quel age avez-vous ? ");
scanf("%d", memoireAllouee);
printf("Vous avez %d ans\n", *memoireAllouee);
free(memoireAllouee); // Libération de mémoire
110
}
180
Allocation dynamique
▪ Tableau dynamique
Un des principaux intérêts de l'allocation dynamique est de permettre à un programme de
réserver la place nécessaire au stockage d'un tableau en mémoire dont il ne connaissait pas
la taille avant
En effet, jusqu'ici, la taille de nos tableaux était fixée dans le code source. Lors de la
déclaration d’un tableau en langage C, il fallait préciser les dimensions, soit de:
➢ façon explicite :
➢ int tab[5] ;
➢ float tam[3][2];
➢ façon implicite (par initialisation) :
➢ int tab[ ] = {4, 6, 2, 8, 1};
➢ float tam[ ][ ] = { {0 , 1 } , {2 , 3 } , {4 , 5 } };
Dans les 2 cas, on a déclaré des tableaux de tailles fixes et donc impossible de changer la
taille
Mais si l’on veut que le tableau change de taille d’une exécution à une autre, cela nous
oblige à modifier le programme et à le recompiler à chaque fois, ou bien à déclarer un
tableau de taille nettement plus grand mais ce serait du gâchis.D’où l’intérêt de
l’allocation dynamique
181
Allocation dynamique
▪ Tableau dynamique
Syntaxe :
type * tab =(type*)malloc(taille_tab×sizeof(type))
Exemple 1
182
▪ Tableau dynamique
Exemple 2
#include<stdio.h>
#include<stdlib.h>
int main() {
int nombreDAmis = 0, i = 0 ;
int* ageAmis = NULL; // Ce pointeur va servir de tableau après l'appel du malloc
// On demande le nombre d'amis à l'utilisateur
printf("Combien d'amis avez-vous ? ");
scanf("%d", &nombreDAmis);
if (nombreDAmis > 0) { // Il faut qu'il ait au moins un ami
ageAmis = (int *)malloc(nombreDAmis * sizeof(int)); // On alloue de la mémoire pour le tableau
if (ageAmis == NULL) { // On vérifie si l'allocation a marché ou non
exit(0); // et on quitte le programme si l’allocation a échoué
}
// On demande l'âge des amis un à un
for (i = 0 ; i < nombreDAmis ; i++){
printf("Quel age a l'ami numero %d ? ", i + 1);
scanf("%d", &ageAmis[i]); // on pouvait aussi ecrire scanf("%d", (ageAmis+i));
}
// On affiche les âges stockés un à un
printf("\n\nVos amis ont les ages suivants :\n");
for (i = 0 ; i < nombreDAmis ; i++) {
printf("%d ans\n", ageAmis[i]);
}
// A la fin, on libère la mémoire allouée avec malloc, on n'en a plus besoin
free(ageAmis);
}return 0
113
183
5.3 Plusieurs fichiers par projet