UNIVERSITÉ CHOUAIB DOUKKALI
FACULTÉDES SCIENCES
El Jadida
Pr. I. EL GUABASSI
PROGRAMMATION C 2
elguabassi@gmail.com
Tronc Commun National
Informatique Appliquée
2023/2024
FS - EL JADIDA
2.
Plan
❑ Chapitre 1: Rappels
❑ Chapitre 2 : Pointeurs et allocation dynamique de la mémoire
❑ Chapitre 3 : Les structures
❑ Chapitre 4 : Récursivité
❑ Chapitre 5 : Evaluation de la complexité de l’algorithme
❑ Chapitre 6 : Tri et recherche
❑ Chapitre 7 : Les fichiers
2
3.
❑ Pointeurs etallocation dynamique de la mémoire
CHAPITRE 2
o Introduction
o Intérêts des pointeurs
o Déclaration d’un pointeur
o Les opérateurs de base
o Les opérateurs élémentaires
o Pointeurs et tableaux
o Allocation mémoire
4.
Pointeurs et allocationdynamique de la mémoire
Introduction
4
Adresse et valeur d’une variable
❑ Une variable est caractérisée par:
✓ son adresse: L’adresse mémoire à partir de laquelle l’objet est stocké.
✓ sa valeur : Ce qui est stocké à cette adresse.
❑ Deux modes d’adressage:
✓ Adressage direct
✓ Adressage indirect
5.
Pointeurs et allocationdynamique de la mémoire
Introduction
5
Adressage direct
La valeur d'une variable se trouve à un endroit spécifique dans la mémoire
interne de l'ordinateur. Le nom de la variable nous permet alors d'accéder
directement à cette valeur
Adressage direct: Accès au contenu
d'une variable par le nom de la variable.
▪ Exemple
int A;
A=10;
… … … … … 10 …
Adresse 1B05 1B06 1B07 1B08 1B09 1B010
A
6.
Pointeurs et allocationdynamique de la mémoire
Introduction
6
Adressage indirect
On peut copier l'adresse d’une variable dans une variable spéciale P,
appelée pointeur. Ensuite, on peut retrouver l'information de la variable A
en passant par le pointeur P.
Adressage indirect: Accès au contenu d'une variable, en
passant par un pointeur qui contient l'adresse de la variable
▪ Exemple
… 1B09 … … … 10 …
A
P
Pointeur
Soit A une variable contenant la
valeur 10 et P un pointeur qui
contient l'adresse de A
(on dit que P pointe sur A)
Adresse 1B05 1B06 1B07 1B08 1B09 1B010
7.
Pointeurs et allocationdynamique de la mémoire
Définition
7
Un pointeur est une variable qui contient l’adresse en mémoire d’une autre
variable
Chaque pointeur est limité à un type de données. Il peut contenir
l'adresse d'une variable simple de ce type ou l'adresse d’une
composante d’un tableau de ce type.
Si un pointeur P contient l'adresse d'une
variable A, on dit que P pointe sur A.
✓ Un pointeur est une variable qui peut 'pointer' sur différentes adresses.
✓ Le nom d'une variable reste toujours lié à la même adresse.
8.
Pointeurs et allocationdynamique de la mémoire
Intérêts des pointeurs
8
Les pointeurs présentent de nombreux avantages :
✓ Ils sont indispensables pour permettre le passage par référence pour
les paramètres des fonctions
✓ Ils permettent de créer des structures de données (listes et arbres)
dont le nombre d’éléments peut évoluer dynamiquement. Ces
structures sont très utilisées en programmation.
✓ Ils permettent d'écrire des programmes plus compacts et efficaces
9.
Pointeurs et allocationdynamique de la mémoire
Déclaration d’un pointeur
9
On déclare un pointeur par l’instruction :
type *nom-du-pointeur
type est le type de la variable pointée
* est l’opérateur qui indiquera au compilateur que c’est un pointeur
o Exemple
int *pi; /*pi est un pointeur vers une variable de type int*/
float *pf; /*pf est un pointeur vers une variable de type float*/
✓ Chaque pointeur est limité à un type de donnée (même si la valeur
d’un pointeur, qui est une adresse, est toujours un entier).
✓ Le type d’un pointeur dépend du type de la variable pointée. Ceci
est important pour connaître la taille de la valeur pointée.
10.
Pointeurs et allocationdynamique de la mémoire
Les opérateurs de base
10
Lors du travail avec des pointeurs, nous avons besoin
*
&
L’opérateur « adresse de »
L’opérateur « contenu de »
pour obtenir l'adresse d'une variable
pour accéder au contenu d'une adresse
Exemples
11.
Pointeurs et allocationdynamique de la mémoire
Les opérateurs de base
11
o Exemple 1
Soit :
✓ A une variable contenant la
valeur 10
✓ B une variable contenant la
valeur 50
✓ P un pointeur non initialisé
A 10
B 50
P
A 20
B 10
P
Après les instructions :
P = &A;
B = *P;
*P = 20;
✓ P pointe sur A
✓ Le contenu de A (référencé par *P) est affecté à B
✓ Le contenu de A (référencé par *P) est mis à 20.
1
1
2
3
2
3
12.
Pointeurs et allocationdynamique de la mémoire
Les opérateurs de base
12
o Exemple 2
int * p; //on déclare un pointeur vers une variable de type int
int i=10, j=30; // deux variables de type int
p=&i; // on met dans p, l’adresse de i (p pointe sur i)
printf("*p = %d n",*p); //affiche : *p = 10
*p=20; // met la valeur 20 dans la case mémoire pointée par p (i=20)
p=&j; // p pointe sur j
i=*p; // on affecte le contenu de p à i (i vaut 30 après cette instruction)
13.
Pointeurs et allocationdynamique de la mémoire
Les opérateurs élémentaires
13
Priorité de * et &
✓ Les opérateurs * et & ont la même priorité que les autres opérateurs
unaires (la négation !, l'incrémentation ++, la décrémentation --). Dans
une même expression, les opérateurs unaires *, &, !, ++, -- sont évalués
de droite à gauche.
✓ Si un pointeur P pointe sur une variable X, alors *P peut être utilisé
partout où on peut écrire X.
Exemple
14.
Pointeurs et allocationdynamique de la mémoire
Les opérateurs élémentaires
14
Priorité de * et &
▪ Exemple 1
Après l'instruction P = &X; les expressions suivantes, sont équivalentes:
Y = *P+1
*P = *P+10
*P += 2
++*P
(*P)++
Y = X+1
X = X+10
X += 2
++X
X++
15.
Pointeurs et allocationdynamique de la mémoire
Les opérateurs élémentaires
15
▪ Exemple 2
float a, *p;
p=&a;
printf("Entrez une valeur : n");
scanf("%f ",a); //supposons qu’on saisit la valeur 1.5
printf("Adresse de a= %x, contenu de a= %fn" , p,*p);
*p+=0.5;
printf ("a= %fn" , a); //affiche a=2.0
Si un pointeur P pointe sur une variable X, alors *P peut être utilisé partout où on peut écrire X
✓ X+=2 équivaut à *P+=2
✓ ++X équivaut à ++ *P
✓ X++ équivaut à (*P)++ // les parenthèses ici sont obligatoires car l’associativité des
opérateurs unaires * et ++ est de droite à gauche
Priorité de * et &
16.
Pointeurs et allocationdynamique de la mémoire
Initialisation d’un pointeur
16
A la déclaration d’un pointeur p, on ne sait pas sur quel zone mémoire il
pointe. Ceci peut générer des problèmes
int *p;
*p = 10; /*provoque un problème mémoire car le pointeur p n’a pas été initialisé*/
Conseil
Toute utilisation d’un pointeur doit
être précédée par une initialisation.
On peut initialiser un pointeur en lui affectant :
✓ L’adresse d’une variable (Ex: int a, int *p1; p1=&a; )
✓ Un autre pointeur déjà initialisé (Ex: int *p2; p2=p1;)
✓ La valeur 0 désignée par le symbole NULL, défini dans <stddef.h>.
Pointeurs et allocationdynamique de la mémoire
18
Pointeurs Exercice
Trouvez les erreurs dans les suites d’instruction suivantes :
1. int *p , x = 34; *p = x;
2. int x = 17 , *p = x; *p = 17;
3. double *q; int x = 17 , *p = &x; q = p;
4. int x, *p; &x = p;
5. char mot[10], car = ‘A’, *pc = &car ; mot = pc;
19.
Pointeurs et allocationdynamique de la mémoire
19
Pointeurs Solution
1. int *p , x = 34; *p = x;
int *p, x = 34; p = &x;
// *p = x est incorrect parce que le pointeur p n’est pas initialisé
// Correction : Assigne l'adresse de x à p
2. int x = 17 , *p = x; *p = 17;
int x = 17, *p = &x; *p = 17;
// La déclaration *p = x; est incorrecte, car x est une valeur entière, pas un pointeur
3. double *q; int x = 17 , *p = &x; q = p;
double *q; int x = 17, *p = &x; q = (double *)p;
// q = p incorrect. q et p deux pointeurs sur des types différents
// Correction : Caste le pointeur p en pointeur double et l'assigne à q
20.
Pointeurs et allocationdynamique de la mémoire
20
Pointeurs Solution
4. int x, *p; &x = p;
5. char mot[10], car = 'A', *pc = &car ; mot = pc;
char mot[10], car = 'A', *pc = &car; mot[0] = car;
//mot est un pointeur constant et on ne peut pas changer sa valeur.
// Correction : Affecte la valeur de car au premier élément de mot
int x, *p; p = &x; // Assigne l'adresse de x à p
21.
Pointeurs et allocationdynamique de la mémoire
21
Pointeurs
Exercice
#include<stdio.h>
main() {
int n=5,m=3,*p;
p=&n;
printf("n=%d m=%d n",n,m);
(*p)++;
printf("n=%d m=%d n",n,m);
n++;
printf("n=%d m=%d n",n,m);
p=&m;
printf("n=%d m=%d n",n,m);
m+=n;
printf("n=%d m=%d n",n,m);
*p=7;
printf("n=%d m=%d n",n,m);
}
Qu’affiche le programme suivant :
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
23
Le nom d'un tableau représente l'adresse de son premier élément T=&T[0].
Avec le formalisme pointeur, on peut dire que T est un pointeur constant sur
le premier élément du tableau
En déclarant un tableau T et un pointeur P du même type, l’instruction P=T fait
pointer P sur le premier élément de T (P=&T[0]) et crée une liaison entre P et
le tableau T.
o Exemple
int A[10];
int *P;
24.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
24
❑ Si P pointe sur une composante quelconque d'un tableau, alors P+1
pointe sur la composante suivante et:
✓ P+i pointe sur la i-ième composante derrière P et
✓ P-i pointe sur la i-ième composante devant P.
❑ Ainsi, après l'instruction, P = A; le pointeur P pointe sur A[0], et
✓ *(P+1) désigne le contenu de A[1]
✓ *(P+2) désigne le contenu de A[2]
✓ ...
✓ ...
✓ ...
✓ *(P+i) désigne le contenu de A[i]
Exemple
25.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
25
o Exemple
Soit A un tableau contenant des éléments de type float et P un pointeur sur
float:
float A[20], X;
float *P;
Après les instructions,
P = A;
X = *(P+9);
X contient la valeur du 10-ième élément de A, (c.-à-d. celle de A[9]). Une
donnée du type float ayant besoin de 4 octets, le compilateur obtient
l'adresse P+9 en ajoutant 9 *4 = 36 octets à l'adresse dans P.
26.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
26
Formalisme
Formalisme tableau Formalisme pointeur
int main() {
int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};
int POS[10];
int I,J;
for (J=0,I=0 ; I<10 ; I++)
if (T[I]>0) {
POS[J] = T[I];
J++;
}
return 0;
}
int main() {
int T[10] = {-3, 4, 0, -7, 3, 8, 0, -1, 4, -9};
int POS[10];
int I,J;
for (J=0,I=0 ; I<10 ; I++)
if (*(T+I)>0) {
*(POS+J) = *(T+I);
J++;
}
return 0;
}
27.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
27
Résumé (1)
int B[] déclare un tableau d'éléments de type int
B désigne l'adresse de la première composante de B.
B[i] désigne le contenu de la composante i du tableau
&B[i] désigne l'adresse de la composante i du tableau
en utilisant le formalisme pointeur:
B+i désigne l'adresse de la composante i du tableau
*(B+i) désigne le contenu de la composante i du tableau
28.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
28
Résumé (2)
int *P; déclare un pointeur sur des éléments du type int.
P peut pointer sur des variables simples du type int ou sur les composantes
d'un tableau du type int.
P désigne l'adresse contenue dans P (Cette adresse est variable)
*P désigne le contenu de l'adresse dans P
Si P pointe dans un tableau, alors
P désigne l'adresse de la première composante
P+i désigne l'adresse de la i-ième composante derrière P
*(P+i) désigne le contenu de la i-ième composante derrière P
29.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
29
Opérations arithmétiques
✓ Affectation par un pointeur sur le même type
Soient P1 et P2 deux pointeurs sur le même type de données, alors l'instruction
P1 = P2; fait pointer P1 sur le même objet que P2
✓ Addition et soustraction d'un nombre entier
Si P pointe sur l'élément A[i] d'un tableau, alors :
• P+n pointe sur A[i+n]
• P-n pointe sur A[i-n]
30.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
30
Opérations arithmétiques
✓ Incrémentation et décrémentation d'un pointeur
Si P pointe sur l'élément A[i] d'un tableau, alors après l'instruction
• P++; P pointe sur A[i+1]
• P+=n; P pointe sur A[i+n]
• P--; P pointe sur A[i-1]
• P-=n; P pointe sur A[i-n] Exemple
31.
Pointeurs et allocationdynamique de la mémoire
Pointeurs et tableaux
31
Opérations arithmétiques
▪ Exemple
float *p1, *p2;
float z =1.5;
p1=&z;
printf("Adresse p1 = %x n",p1);
p1++; p2=p1+1;
printf("Adresse p1 = %x t Adresse p2 = %xn",p1,p2);
printf("p2-p1 = %d n",p2-p1);
Résultat
Adresse p1 = 22ff44
Adresse p1 = 22ff48
Adresse p2 = 22ff4c
p2-p1=1
32.
Pointeurs et allocationdynamique de la mémoire
Allocation mémoire
32
✓ La déclaration d’un tableau définit un tableau « statique » (il
possède un nombre figé d’emplacements). Il y a donc un
gaspillage d’espace mémoire en réservant toujours l’espace
maximal prévisible.
✓ Il serait souhaitable que l’allocation de la mémoire dépend du
nombre d’éléments à saisir. Ce nombre ne sera connu qu’à
l’exécution : c’est l’allocation dynamique.
33.
Pointeurs et allocationdynamique de la mémoire
Allocation mémoire
33
Il existe 4 fonctions pour gérer l’allocation dynamiquement de la mémoire
Bibliothèque <stdlib.h>
char *malloc(taille) allocation d’un bloc
char *calloc(taille, sizeof(type)) allocation & initialisation d’un bloc
char *realloc(char *, taille) modification de la taille d’un bloc
void free(char *) libération d’un bloc
S'il n'y a pas assez de mémoire libre à allouer, la fonction renvoie
le pointeur NULL.
34.
Pointeurs et allocationdynamique de la mémoire
Allocation mémoire
34
La fonction « mallo »
<pointeur> = <type> malloc(<taille>);
• <type> est un type pointeur définissant la variable pointé par
<pointeur>
• <taille> est la taille, en octets, de la zone mémoire à allouer
dynamiquement. <taille> est du type unsigned int, donc on ne peut
pas réserver plus de 65536 octets à la fois
• La fonction malloc retourne l’adresse du premier octet de la zone
mémoire allouée. En cas d’échec, elle retourne NULL.
35.
Pointeurs et allocationdynamique de la mémoire
Allocation mémoire
35
La fonction « free »
✓ Si on n’a plus besoin d’un bloc de mémoire réservé
dynamiquement par malloc, alors on peut le libérer à l’aide de la
fonction free.
✓ free(<pointeur>);
✓ Libère le bloc de mémoire désigné par le pointeur <pointeur>
Exemple
36.
Pointeurs et allocationdynamique de la mémoire
Allocation mémoire
36
printf(" Saisie du tableau n " );
for(i=0;i<n;i++) {
printf ("Élément %d ? n ",i+1);
scanf(" %f" , pt+i);
}
printf(" Affichage du tableau n " );
for(i=0;i<n;i++)
printf (" %f t",*(pt+i));
free(pt);
return 0;
}
#include<stdio.h>
#include<stdlib.h>
int main() {
float *pt;
int i,n;
printf("Entrez la taille du tableau n"
);
scanf("%d" ,&n);
pt=(float*) malloc(n*sizeof(float));
if (pt==NULL) {
printf( " pas assez de mémoire
n" );
}
Pointeurs et allocationdynamique de la mémoire
38
Pointeurs
Exercice
#include<stdio.h>
int main() {
int A[]= {12,23,27,42,67,70, 73,76,89,90};
int *p ;
p=A ;
printf("A : %d, B : %d, C : %d ", *p+2 , *(p+2) ,*(p+(*p-9)) );
return 0;
}
Qu’affiche le programme suivant :
39.
Pointeurs et allocationdynamique de la mémoire
39
Pointeurs
Solution
#include<stdio.h>
int main() {
int A[]= {12,23,27,42,67,70, 73,76,89,90};
int *p ;
p=A ;
printf("A : %d, B : %d, C : %d ", *p+2 , *(p+2) ,*(p+(*p-9)) );
return 0;
}
A : 14, B : 27, C : 42
40.
Pointeurs et allocationdynamique de la mémoire
40
Pointeurs
Exercice
Ecrire un programme C qui remplit un tableau d’entiers et
calcule la somme et la moyenne de ses éléments en
utilisant un pointeur pour son parcours
41.
Pointeurs et allocationdynamique de la mémoire
41
Pointeurs
Solution
#include<stdio.h>
int main() {
int t[50];
int n,*p,som=0;
float moy;
printf("Donnez le nombre d'elements: ");
scanf("%d",&n);
for(p=t;p<t+n;p++)
scanf("%d",p);
for(p=t;p<t+n;p++)
som = som + *p; printf("la somme est %dn",som);
moy=som/n; printf("la moyenne est %.2fn",moy);
return 0;
}