Académique Documents
Professionnel Documents
Culture Documents
Cours PDF
Cours PDF
Version 1.2
c
2002
Florence HENRY
Observatoire de Paris Universit de Versailles
florence.henry@obspm.fr
Les bases
Variables et constantes
11
Les fonctions
15
Les tableaux
18
Les structures
20
Les pointeurs
22
Pointeurs et fonctions
25
10 Pointeurs et tableaux
26
31
Chapitre 1
Les bases
1.1
1.1.1
signification
permet dutiliser les fonctions printf() et scanf()
permet dutiliser les fonctions mathmatiques
dfinit la constante PI
partir de cet endroit, la constante PI nest plus dfinie
si la constante PI est dfinie, on compile les instructions 1,
sinon, les instructions 2
Parmi ces directives, une seule est obligatoire pour le bon fonctionnement dun programme :
#include <stdio.h> . En effet, sans elle, on ne peut pas utiliser les fonctions utiles pour laffichage
lcran : printf() et la lecture des donnes au clavier : scanf(). Nous verrons le fonctionnement
de ces fonctions plus tard.
main(){
int i ; /* declaration des variables */
instruction_2 ;
...
}
instruction_1 ;
1.2
Une fois le programme crit, on ne peut pas lexcuter directement. Pour que lordinateur comprenne ce que lon veut lui faire faire, il faut traduire le programme en langage machine. Cette
traduction sappelle la compilation.
On compile le programme par la commande cc prog.c, o prog.c est le nom du programme. La
compilation cre un fichier excutable : a.out. On peut vouloir lui donner un nom plus explicite, et
pour cela, la compilation, on compile avec la commande cc -o prog prog.c qui va appeler le
programme excutable prog au lieu de a.out.
On dmarre alors le programme avec la commande ./prog.
Chapitre 2
Variables et constantes
2.1
Les constantes
2.2
2.2.1
Les variables
Noms des variables
Le C fait la diffrence entres les MAJUSCULES et les minuscules. Donc pour viter les confusions, on crit les noms des variables en minuscule et on rserve les majuscules pour les constantes
symboliques dfinies par un #define. Les noms doivent commencer par une lettre et ne contenir
aucun blanc. Le seul caractre spcial admis est le soulignement (_). Il existe un certain nombre de
noms rservs (while, if, case, ...), dont on ne doit pas se servir pour nommer les variables. De plus,
on ne doit pas utiliser les noms des fonctions pour des variables.
2.2.2
Pour dclarer une variable, on fait prcder son nom par son type.
Il existe 6 types de variables :
type
char
short
int
long
float
double
signification
caractre cod sur 1 octet (8 bits)
entier cod sur 1 octet
entier cod sur 4 octets
entier cod sur 8 octets
rel cod sur 4 octets
rel cod sur 8 octets
val. min
27
27
231
263
1038
10308
val. max
27 1
27 1
231 1
263 1
1038
10308
On peut faire prcder chaque type par le prfixe unsigned, ce qui force les variables prendre
des valeurs uniquement positives.
Exemples de dclarations :
dclaration
int a ;
int z=4 ;
unsigned int x ;
float zx, zy ;
float zx=15.15 ;
double z ;
char zz ;
char zz=a ;
signification
a est entier
z est entier et vaut 4
x est un entier positif (non sign)
zx et zy sont de type rel
zx est de type rel et vaut 15.15
z est un rel en double prcision
zz est une variable caractre
zz vaut a
2.3
Les oprateurs
Le premier oprateur connatre est laffectation "=". Exemple : {a=b+" ;} Il sert mettre dans
la variable de gauche la valeur de ce qui est droite. Le membre de droite est dabord valu, et
ensuite, on affecte cette valeur la variable de gauche. Ainsi linstruction i=i+1 a un sens.
Pour les oprations dites naturelles, on utilise les oprateurs +, -, *, /, %.
% est lopration modulo : 5%2 est le reste de la division de 5 par 2. 5%2 est donc gal 1.
Le rsultat dune opration entre types diffrents se fait dans le type le plus haut. Les types sont classs
ainsi :
char < int < float < double
Par ailleurs, lopration a+1 a un sens, elle a pour rsultat le caractre suivant a dans le code
ASCII.
En C, il existe un certain nombre doprateurs spcifiques, quil faut utiliser prudemment sous
peine derreurs.
++ incrmente la variable dune unit.
- - dcrmente la variable dune unit.
Ces 2 oprateurs ne sutilisent pas avec des rels. Exemples dutilisation :
i++ ; /* effectue i=i+1 */
i- - ; /* effectue i=i-1 */
Leur utilisation devient dlicate quand on les utilise avec dautres oprateurs. Exemple :
int i=1 , j ;
j=i++ ;
j=++i ;
/*
/*
/*
/*
Quand loprateur ++ est plac avant une variable, lincrmentation est effectue en premier. Lincrmentation est faite en dernier quand ++ est plac aprs la variable. Le comportement est similaire pour
- -.
/*
/*
/*
/*
/*
i=i+5
i=i-3
i=i*4
i=i/2
i=i%3
*/
*/
*/
*/
*/
Pour finir, ajoutons que les oprateurs qui servent comparer 2 variables sont :
==
<
>
&&
gal
infrieur
suprieur
et logique
!=
<=
>=
||
diffrent de
infrieur ou gal
suprieur ou gal
ou logique
ATTENTION !
Ne pas confondre loprateur daffectation = et loprateur de comparaison ==.
Chapitre 3
Quelques fonctions indispensables
3.1
La fonction printf()
Elle sert afficher lcran la chane de caractre donne en argument, cest--dire entre parenthses.
printf("Bonjour\n") ; affichera Bonjour lcran.
Certains caractres ont un comportement spcial :
\n
\b
\r
\t
\v
\"
\
\?
\!
\\
retour la ligne
nimprime pas la lettre prcdente
nimprime pas tout ce qui est avant
tabulation horizontale
tabulation verticale
"
?
!
\
Le caractre % indique le format dcriture lcran. Ds quun format est rencontr dans la chane
de caractre entre " ", le programme affiche la valeur de largument correspondant.
{
printf("n=%d, m=%d",n,m);
ATTENTION ! le compilateur nempche pas dcrire un char sous le format dun rel affichage de valeurs dlirantes. Et si on crit un char avec un format dcimal, on affiche la valeur du
code ASCII du caractre.
8
%d
%u
%hd
%d
%f
%e
%lf
%le
%c
%s
Remarque : une chane de caractres est un tableau de caractres. Elle se dclare de la faon
suivante : char p[10] ;. Mais nous reviendrons sur la notion de tableau plus tard.
3.2
La fonction scanf()
Dans un programme, on peut vouloir quune variable nait pas la mme valeur chaque excution.
La fonction scanf() est faite pour cela. Elle permet de lire la valeur que lutilisateur rentre au clavier
et de la stocker dans la variable donne en argument.
Elle sutilise ainsi :
main(){
int a ;
scanf("%d",&a) ;
}
On retrouve les formats de lecture prciss entre " " utiliss pour printf(). Pour viter tout
risque derreur, on lit et on crit une mme variable avec le mme format.
Le & est indispensable pour le bon fonctionnement de la fonction. Il indique ladresse de
la variable, mais nous reviendrons sur cette notion dadresse quand nous aborderons les
pointeurs.
3.3
La librairie string.h
La librairie string.h fournit un certain nombres de fonctions trs utiles pour manipuler des
chanes de caractres en C. En effet, le C ne sait faire que des affectations et des comparaisons pour 1
seul caractre.
char p,q ;
char chaine1[10], chaine[10] ;
p = A ;
/*
chaine1 = "Bonjour" ;
/*
chaine2 = "Hello" ;
/*
if (p == q) ;
/*
if (chaine1 == chaine2) /*
Pour faire les affectations (1) et (2), et la comparaison (3), il faudrait donc procder caractre
par caractre. Ces oprations tant longues et sans intrt, on utilise les fonctions dj faites dans
string.h. Pour les oprations daffectation (1) et (2), il faut utiliser la fonction strcpy (string
copy), et pour une comparaison (3), la fonction strcmp (string compare).
#include<stdio.h>
#include<string.h>
main(){
char chaine1[10], chaine2[10] ;
int a ;
strcpy(chaine1,"Bonjour") ; /* met "Bonjour" dans chaine1 */
strcpy(chaine2,"Hello") ;
/* met "Hello" dans chaine2 */
a=strcmp(chaine1,chaine2) ;
/* a reoit la diffrence chaine1 et chaine2 */
/* si chaine1 est class alphabtiquement avant chaine2, alors a<0 */
/* si chaine1 est class aprs chaine2, alors a>0 */
/* si chaine1 = chaine2, alors a = 0 */
/* Ici, "Bonjour" est alphabtiquement avant "Hello", */
/* donc chaine1 est plus petite que chaine2, et a < 0 */
}
10
Chapitre 4
Les instructions de contrle
Ce sont des instructions qui permettent de notamment faire des tests et des boucles dans un programme. Leur rle est donc essentiel. Pour chaque type dinstruction de contrle, on trouvera la fin
de la partie 4 les organigrammes correspondant aux exemples donns.
4.1
4.1.1
if (expression) {
instruction 1 ;
} else {
instruction 2 ;
}
/* Si expression est vraie alors linstruction 1 est executee */
/* Sinon, cest linstruction 2 qui est executee */
if (expression 1) {
instruction 1 ;
} else if (expression 2){
instruction 2 ;
} else if (expression 3){
instruction 3 ;
} else {
instruction 4 ; }
/* Souvent, on imbrique les tests les uns dans les autres */
Remarque : les instructions xcuter peuvent tre des instructions simples {a=b ;} ou un bloc
dinstructions {a=b ; c=d ; ...}.
11
Comme nous lavons dj vu, une expression est vraie si la valeur quelle renvoie est non nulle.
ATTENTION ! les expressions (a=b) et (a==b) sont diffrentes :
if (a==b) vrai si a et b sont gaux
int b=1 ;
if (a=b)
on met la valeur de b dans a. a vaut alors 1. lexpression est donc vraie
4.2
Les boucles
4.2.3
la diffrence dune boucle while, les instructions sont excutes au moins une fois : lexpression
est value en fin ditration.
do {
instructions ... ;
} while (expression)
Les risques des faire une boucle infinie sont les mmes que pour une boucle while.
13
entree dans le if
expression 1 ?
vrai
{
instruction 1;
}
sortie
du if
Les tests
entree dans le if
expression 1 ?
vrai
faux
{
instruction 1;
}
sortie
du if
entree du switch
{
instruction 2;
}
i=1 ? vrai
faux
{
instructions 1;
}
break ? vrai
faux
entree dans le if
expression 1 ?
vrai
faux
i=2 ? vrai
faux
{
instruction 1;
}
{
instructions 2;
}
break ? vrai
faux
expression 2 ?
vrai
faux
{
instruction 2;
}
i=10 ? vrai
faux
sortie
du if
expression 3 ?
vrai
faux
{
instruction 3;
}
break ? vrai
faux
{
instructions 4;
}
{
instruction 4;
}
entree dans
sortie
du
switch
{
instructions 3;
}
le for
Les boucles
i=0
entree du while
instructions ;
}
expression ?
faux
sortie
du
while
vrai
i++
vrai
i<N ?
faux
{
instructions;
}
{
instructions;
}
expression ?
faux
sortie
du
while
vrai
sortie de la boucle
Organigramme
dune boucle for
Organigramme
dune boucle while
Organigramme
dun do ... while
14
Chapitre 5
Les fonctions
Crer une fonction est utile quand vous avez faire le mme type de calcul plusieurs fois dans
le programme, mais avec des valeurs diffrentes. Typiquement, pour le calcul de lintgrale dune
fonction mathmatique f . Comme en mathmatique, une fonction prend un ou plusieurs arguments
entre parenthses et renvoie une valeur.
5.1
Dclaration
15
16
5.2
Appel de la fonction
Une fonction f() peut tre appele depuis le programme principal main() ou bien depuis une
autre fonction g() la condition de rappeler le prototype de f() aprs la dclaration des variables de
main() ou g() :
#include <stdio.h>
main(){
int x,y,r ;
int plus( int x, int y ) ;
x=5 ;
y=235 ;
r=plus(x,y) ; /* appel dune fonction avec arguments */
}
int plus( int x, int y ){
void mess( void ) ;
mess_err() ; /* appel dune fonction sans arguments */
return (x+y)) ;
}
void mess( void ) {
printf("Vous n\avez fait aucune erreur\n") ;
return ;
}
Quand le programme rencontre linstruction return, lappel de la fonction est termin. Toute
instruction situe aprs lui sera ignore.
17
Chapitre 6
Les tableaux
6.1
Dclaration
Comme une variable, on dclare son type, puis son nom. On rajoute le nombre dlments du
tableau entre crochets [ ] :
float tab[5] ; est un tableau de 5 flottants.
int tablo[8] ; est un tableau de 8 entiers.
ATTENTION !
? Les numros des lments dun tableau de n lments vont de 0 a n 1.
? La taille du tableau doit tre une constante (par opposition variable), donc int t1[n] ; o n serait
une variable dj dclare est une mauvaise dclaration. Par contre si on a dfini #define N 100 en
directive, on peut dclarer int t1[N] ; car N est alors une constante.
On peut initialiser un tableau lors de sa dclaration :
float tab[5] = { 1, 2, 3, 4, 5} ; /* init. de tous les lments de tab */
float toto[10] = {2, 4, 6} ; /* equ. toto[0]=2 ; toto[1]=4 ; toto[2]=6 ; */
/* les autres lments de toto sont mis 0. */
6.2
Utilisation
float tab[5];
tab[0]
tab[1]
tab[2]
tab[3]
tab[4]
6.3
Un tableau de caractres est en fait une chane de caractres. Son initialisation peut se faire de
plusieurs faons :
char p1[10]=B,o,n,j,o,u,r ;
char p2[10]="Bonjour" ; /* init. par une chane litterale */
char p3[ ]="Bonjour" ; /* p3 aura alors 8 lments */
18
ATTENTION ! Le compilateur rajoute toujours un caractre null la fin dune chane de caractres. Il faut donc que le tableau ait au moins un lment de plus que la chane litterale.
Tableau 2 dimensions
int tableau[2][3];
.
co 0
l.
co 1
l.
2
co
l
6.4
ligne 0
ligne 1
tableau[1][0]
19
Chapitre 7
Les structures
Les structures permettent de rassembler des valeurs de type diffrent. Par exemple, pour une
adresse, on a besoin du numro (int) et du nom de la rue (char).
7.1
Dclaration
7.2
Manipulation
On accde aux donnes contenues dans les champs dune structure et faisant suivre le nom de la
strucure par un point "." et le nom du champ voulu :
chez_julie.numero=19 ;
strcpy(chez_julie.rue,"avenue Pasteur") ;
Si 2 structures ont le mme type, on peut effectuer :
20
7.3
Tableau de structure
On dclare un tableau de structure de la mme faon quun tableau de variables simples : le nombre
dlments est prcis entre crochets.
struct adresse pers[100] ;
Cette dclaration ncessite que la structure adresse ait dj t dclare avant. pers est alors un
tableau dont chaque lment est une structure de type adresse. Et pers[i].rue fait refrence au
`
champ "rue" de la ieme
personne de la structure pers .
7.4
Structure de structure
On peut utiliser une structure comme champ dune autre structure. Dans la ligne des exemples
prcdents, on peut dfinir une structure adresse qui pourra tre utilise dans la structure repertoire.
Elle peut galement tre utilise dans une autre structure.
struct adresse {
int numero ;
char rue[50] ; } ;
struct repertoire {
char nom[20] ;
char prenom[20] ;
struct adresse maison ; } ; /* dclaration dun champ structure */
/* de type adresse appel maison */
struct repertoire monrepertoire[100] ;
strcpy(monrepertoire[0].nom,"Cordier") ;
strcpy(monrepertoire[0].prenom,"Julie") ;
monrepertoire[0].maison.numero = 19 ;
strcpy(monrepertoire[0].maison.rue,"avenue_Pasteur") ;
strcpy(monrepertoire[1].nom,"Durand") ;
strcpy(monrepertoire[1].prenom,"Pierre") ;
monrepertoire[1].maison.numero = 15 ;
strcpy(monrepertoire[1].maison.rue,"rue_Dugommier") ;
Lorsquun tableau fait partie des champs dune structure, on peut accder aux valeurs de ce tableau
par :
char initiale ;
initiale=monrepertoire[1].prenom[0] ; /* initiale de Pierre */
21
Chapitre 8
Les pointeurs
8.1
Lors de la compiltaion dun programme, lorinateur rserve dans sa mmoire une place pour
chaque variable dclare. Cest cet endroit que la valeur de la variable est stocke. Il associe alors
au nom de la variable ladresse de stockage. Ainsi, pendant le droulement du programme, quand il
rencontre un nom de variable, il va chercher ladresse correspondante la valeur en mmoire.
Pour les dclaractions de variables suivantes :
int a=0xa ; /* a est un entier cod sur 4 octets */
short b=0x0 ; /* b est un entier cod sur 2 octets */
int c=0x14 ; /* c est un entier cod sur 4 octets */
ceci est stock en mmoire :
'
nom
adresse en hexa
(bfbff000)
00
00
(bfbff004)
00
00
(bfbff006)
00
00
00
0a
00
14
&
Ici, on suppose que lespace mmoire servant stocker les donnes commence ladresse (bfbff000).
Chaque case reprsente 1 octet.
Explication du shma :
? a est cod sur 4 octets et son adresse est (bfbff000), donc ladresse de b sera
(bfbff000)+(4)=(bfbff004).
? b est cod sur 8 octets et son adresse est (20004), donc ladresse de c sera
(bfbff004)+(2)=(bfbff006).
8.2
Un pointeur est une variable qui a pour valeur ladresse dune autre variable : celle sur laquelle elle
pointe ! Un pointeur est toujours associ un type de variable et un seul. Au moment de la dclaration,
on dtermine le type de variable point par le pointeur, en crivant le type concern, puis le nom du
pointeur avec une * devant :
22
8.3
8.4
Oprateur dindirection : *
Cet oprateur, mis en prfixe dun nom de pointeur signifie valeur de la variable pointe ou, plus
simplement, valeur pointe.
int a=1 ;
int *ptint ; /* declaration dun pointeur sur un entier */
ptint=&a ; /* ptint pointe sur a */
*ptint=12 ; /* la variable pointe par ptint reoit 12*/
printf("a=%d \n",a) ; /* affiche "a=12" */
En fait, manipuler ptint revient manipuler a.
8.5
Mmoire et pointeurs
'
nom
adresse
(bfbff000)
00
00
(bfbff004)
00
00
(bfbff006)
00
ptint
(bfbff010)
bf
&
00
0a
00
00
14
bf
f0
00
%
23
Explication : Les cases mmoire des variables a, b et c contiennent leur valeur. Celles de la variable
ptint contiennent ladresse de la valeur pointe. En effet, la valeur stocke est (bfbff000), ce qui
est bien ladresse de a.
8.6
Exemple
adresse de x : 0xbfbffa3c
valeur de px : 0xbfbffa3c
valeur de x : 3.5
valeur pointee par px : 3.5
24
Chapitre 9
Pointeurs et fonctions
Un variable globale est une variable connue dans toutes les fonctions dun programme (main
comme les autres).
Une variable locale nest connue qu lintrieur dune fonction (main ou une autre).
Les variables locales dune fonction sont regroupes dans une partie de la mmoire, et celles dune
autre fonction, dans un autre endroit. Ainsi, il peut exister un float a ; dans une fonction et un int
a dans une autre sans quil y ait de conflit.
Une conscquence de cette proprit est que la fonction suivante ne marchera pas :
void permute (int a , int b){
int buf ;
buf = a ;
a = b;
b = buf ;
return ;
}
car lors de lappel de cette fonction depuis main, les valeurs des arguments vont tre copis dans
les variables de permute et ce sont ces variables locales qui vont tre modifies, pas celles de main.
Ainsi, dans main, un appel du type permute(i,j) laissera i et j inchangs. On dit que le C passe ses
arguments par valeur.
Pour que permute fonctionne, il faut que ses arguments soient les adresses des variables a et b et
utiliser des pointeurs.
void permute (int *a , int *b){
int buf ;
buf = *a ;
*a = *b ;
*b = buf ;
return ;
}
Lors de lappel de la fonction, les pointeurs locaux vont recevoir ladresse des variables a et b.
Donc travailler sur ces pointeurs revient travailler sur les variables a et b de la fonction main.
Lappel dune telle fonction se fait ainsi : permute (&a ,&b)
De faon gnrale, on utilise des pointeurs avec les fonctions quand on veut quune fonction
modifie des variables du programme principal.
25
Chapitre 10
Pointeurs et tableaux
10.1
Vous avez dja manipul des pointeurs quand vous avez manipul les tableaux. En fait, le nom seul
du tableau est une constante qui contient ladresse du premier lment du tableau comme le shmatise
la figure suivante :
tab
tab[0]
tab[1]
tab[2]
.
.
.
tab[9]
Ainsi, tab est gal &tab[0] et donc *tab est gal tab[0].
Llment tab[i] est quivalent *(tab+i). On a donc les correspondances suivantes :
tab
tab+1
tab+2
.
.
.
tab[0]
tab[1]
tab[2]
.
.
.
tab+9
tab[9]
26
nom
adresse
tab
(bfbff000)
(bfbff004)
(bfbff008)
00
00
00
00
00
00
00
00
00
0a
03
0d
pta
(bfbff010)
bf
bf
f0
00
ptb
(bfbff014)
bf
bf
f0
08
&
27
pt[0]
pt[1]
pt[i]
10.2
Un tableau plusieurs dimensions est un tableau dont les lments sont eux-mmes des tableaux.
Ainsi, le tableau dfini par int tab[4][5] ; contient 4 tableaux de 5 entiers chacuns. tab donne
`
ladresse du 1er sous-tableau, tab+1 celle du 2eme
sous-tableau et ainsi de suite :
tab
tab[0][0]
tab[0][1]
tab[0][2]
tab[0][3]
tab[0][4]
tab+1
tab[1][0]
tab[1][1]
tab[1][2]
tab[1][3]
tab[1][4]
tab+2
tab[2][0]
tab[2][1]
tab[2][2]
tab[2][3]
tab[2][4]
tab+3
tab[3][0]
tab[3][1]
tab[3][2]
tab[3][3]
tab[3][4]
Ici, lopration tab+2 najoute pas 2 la valeur de tab mais ajoute 2 fois le nombre doctets
correspondant un tableau de 5 entiers, savoir 5*4 = 20 octets.
10.3
Tableaux de pointeurs
La dclaration dun tableau de pointeurs se fait comme pour un tableau de variables quelconques :
le type puis le nom du tableau avec
le nombre dlments entre crochets derrire le nom
et une * devant.
int *pttab[4] ; /* pttab est un tableau de 4 pointeurs dentiers */
pointeur de
pointeur
pttab
pttab+1
pttab+i
pointeur
pttab[0]
*pttab
tab
*(pttab[0])
**pttab
*tab
tab[0]
pttab[1]
*(pttab+1)
tab+1
*(pttab[1])
**(pttab+1)
*(tab+1)
tab[1]
pttab[i]
*(pttab+i)
tab+2
*(pttab[i])
**(pttab+i)
*(tab+i)
tab[i]
Note : Les expressions se situant dans une mme case sont quivalentes.
Au niveau de la mmoire, les lments dune colonne contiennent les adresses des lments de la
colonne qui est juste sa droite.
Voici ltat de la mmoire pour un tel exemple :
'
nom
adresse
tab
(bfbff000)
(bfbff004)
(bfbff008)
(bfbff00c)
00
00
00
00
00
00
00
00
00
00
00
00
0a
03
0d
6c
pttab
(bfbff010)
(bfbff014)
(bfbff018)
(bfbff01c)
bf
bf
bf
bf
bf
bf
bf
bf
f0
f0
f0
f0
00
04
08
0c
&
29
`
2eme
exemple
int
int
int
int
l1[4] = { 1 , 2 , 3 , 4 } ;
l2[3] = { 5 , 6 , 7 } ;
l3[1] = { 8 } ;
*pt[3] = { l1 , l2 , l3 } ;
Les lments de tab sont les adresses de tableaux ne comportant pas le mme nombre dlments.
pt est en fait un tableau dont les 3 lignes nont pas la mme longueur.
pt
pt[0]
l1
l1[0]
l1[1]
l1[2]
l1[3]
pt[0][0]
pt[0][1]
pt[0][2]
pt[0][3]
pt+1
pt[1]
l2
l2[0]
l2[1]
l2[3]
pt[1][0]
pt[1][1]
pt[1][2]
pt+2
pt[2]
l3
l3[0]
pt[2][0]
tat de la mmoire :
'
nom
adresse
l1
(bfbff000)
(bfbff004)
(bfbff008)
(bfbff00c)
00
00
00
00
00
00
00
00
00
00
00
00
01
02
03
04
l2
(bfbff010)
(bfbff014)
(bfbff018)
00
00
00
00
00
00
00
00
00
05
06
07
l3
(bfbff01c)
00
00
00
08
pt
(bfbff020)
(bfbff024)
(bfbff028)
bf
bf
bf
bf
bf
bf
f0
f0
f0
00
10
1c
&
30
Chapitre 11
Allocation dynamique de mmoire
Jusqu maintenant, lors de la dclaration dun tableau, il fallait prciser les dimensions, soit de
faon explicite :
int tab[3][2] ;
soit de faon implicite :
int tab[][] = { {0 , 1 } , {2 , 3 } , {4 , 5 } } ;
Dans les 2 cas, on a dclar un tableau de 3 fois 2 entiers.
Mais si lon veut que le tableau change de taille dune excution une autre, cela nous oblige
modifier le programme et le recompiler chaque fois, ou bien dclarer un tableau de 1000 fois
1000 entiers et nutiliser que les n premires cases mais ce serait du gchis.
Pour viter cela, on fait appel lallocation dynamique de mmoire : au lieu de rserver de la place
lors de la compilation, on la rserve pendant lexcution du programme, de faon interative.
11.1
La fonction malloc()
11.2
Loprateur sizeof()
Dune machine une autre, la taille rserve pour un int, un float,... change. Si nous voulons
rserver de la mmoire pour des donnes dun type dont la grandeur varie dune machine lautre,
nous avons besoin de la taille effective dune donne de ce type.
Loprateur sizeof nous fournit ce renseignement.
sizeof nom_variable fournit la taille de la variable nom_variable
31
de a : %d\n",sizeof a) ;
de b : %d\n",sizeof b) ;
de 4.25 : %d\n",sizeof 4.25) ;
de Bonjour ! : %d\n",sizeof "Bonjour !") ;
dun float : %d\n",sizeof(float)) ;
dun double : %d\n",sizeof(double)) ;
11.3
de a : 40
de b : 40
de 4.25 : 8
de Bonjour ! : 9
dun float : 4
dun double : 8
`
tab contient alors ladresse de dbut dun bloc de n entiers et on accde la ieme
valeur du tableau
par tab[i].
Jusqu maintenant, on a vu des pointeurs qui contenaient ladresse dune variable en mmoire.
Ici, on a lexemple dun pointeur qui contient ladresse dun bloc contenant des donnes. Celles-ci ne
sont accessibles que via un pointeur.
tat de la mmoire avant lallocation :
'
nom
adresse
(bfbff000)
00
00
00
04
tab
(bfbff004)
00
00
00
00
&
nom
adresse
(bfbff000)
00
00
00
04
tab
(bfbff004)
80
00
00
00
(80000000)
(80000004)
(80000008)
(8000000c)
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
00
&
(tab[0])
(tab[1])
(tab[2])
(tab[3])
%
33
11.4
On veut rserver de la place pour un tableau de n fois m entiers, o n et m sont lus au clavier : On a
vu que pour manipuler des tableaux plusieurs dimensions, il fallait utiliser des tableaux de pointeurs
(i.e. des pointeurs de pointeurs).
int i,j,n,m ;
float **tab ; /* (1) */
scanf("%d%d",n,m) ;
tab = (float **)malloc(n*sizeof(float *)) ; /* (2) */
for (i=0 ; i<n ; i++){
tab[i] = (float *)malloc(m*sizeof(float)) ; /* (3) */
}
for (i=0 ; i<n ; i++){
for (j=0 ; j<m ; j++){
tab[i][j] = 10*i+j ; /* (4) */
}
}
Explications :
(1) Un tableau de pointeurs tant un pointeur de pointeurs, on peut dclarer au choix un tableau
de pointeurs : int *tab[3] ou un pointeur de pointeur : **tab. Dans le cas de lallocation
dynamique de mmoire, comme on ne connait pas la taille du tableau dont on aura besoin, on
dclare donc un pointeur de pointeur.
(2) tab tant en fait un tableau de pointeurs de flottants, on rserve un bloc pouvant contenir n
pointeurs de float. tab contient alors ladresse de ce bloc.
(3) Les tab[i] sont des sous-tableaux de tab. On rserve alors pour chacun deux de la place pour
m flottants. Au total, on a bien rserv de la place pour n fois m flottants.
(4) On manipule les lments de tab comme ceux dun tableau "normal".
tat de la mmoire aprs ltape (2) :
'
nom
adresse
(bfbff000)
00
00
00
03
(bfbff000)
00
00
00
02
tab
(bfbff004)
80
00
00
00
(80000000)
(80000004)
(80000008)
00
00
00
00
00
00
00
00
00
00
00
00
&
34
'
nom
adresse
(bfbff000)
00
00
00
03
(bfbff000)
00
00
00
02
tab
(bfbff004)
80
00
00
00
(80000000)
(80000004)
(80000008)
80
80
80
00
00
00
01
0a
0d
00
00
00
(80000100)
(80000104)
00
00
00
00
00
00
00
01
(valeur de tab[0][0])
(valeur de tab[0][1])
(80000a00)
(80000a04)
00
00
00
00
00
00
0a
0b
(valeur de tab[1][0])
(valeur de tab[1][1])
(80000d00)
(80000d04)
00
00
00
00
00
00
14
15
(valeur de tab[2][0])
(valeur de tab[2][1])
&
Note : Les diffrentes allocations de mmoire ne se font pas en mme temps. Cest pour cela que
les diffrents blocs mmoire ne sont pas contigs.
35