6. 6
Un octet = 8 bits
ex : 1 0 1 1 0 1 1 0
Combien d'objets distincts peut-on représenter
avec un octet ?
Octet ?
7. 7
1 bit
1 octet
1 Kilo octet (Ko) = 1024 octets
1 Mega octet (Mo) = 1024 Ko
= 1024 * 1024 octets
1 giga octet (Go) = 1024 Mo
Volume mémoire
8. 8
1 octet
1 octet
1 octet
1 octet
1 octet
1 octet
Organisation de l’information en mémoire
Chaque octet de la mémoire est repéré par une adresse
Adresse
Le nombre d’octet
occupés par une
information dépend
du type de cette
information:
entier, réel,
Caractère, chaîne
de caractères
9. 9
32 espaces
33 !
34 "
35 #
36 $
37 %
38 &
39 `
40 (
41 )
42 *
43 +
44 ,
45 -
46 .
47 /
48 0
49 1
50 2
51 3
52 4
53 5
54 6
55 7
56 8
57 9
58 :
59 ;
60 <
61 =
62 >
63 ?
64 @
65 A
66 B
67 C
68 D
69 E
70 F
71 G
72 H
73 I
74 J
75 K
76 L
77 M
78 N
79 O
80 P
81 Q
82 R
83 S
84 T
85 U
86 V
87 W
88 X
89 Y
90 Z
91
92
93 ]
94 ^
95 —
96 -
97 a
98 b
99 c
100 d
101 e
102 f
103 g
104 h
105 i
106 j
107 k
108 l
109 m
110 n
111 o
112 p
113 q
114 r
115 s
116 t
117 u
118 v
119 w
120 x
121 y
122 z
123 {
124
125 }
126 ~
127
Représentation des caractères sur un octet
(ASCII)
11. 11
"Une suite finie de règles à appliquer dans
un ordre déterminé à un nombre fini de
données pour arriver, en un nombre fini
d'étapes, à un certain résultat, et cela
indépendamment des données".
Algorithme
12. 12
langage machine le seul compréhensible
par la machine
langage assembleur très proche du langage
machine, mais plus
explicite
langage évolué proche de la description
(3ème génération) des algorithmes
C, FORTRAN, PASCAL
langage facilite la recherche
4è génération d'information dans les
bases de données (SQL)
Langages de programmation ?
Bas niveau
Haut niveau
15. 15
Historique
Pour développer une version portable du système d'exploitation UNIX, en
1972 dans les 'Bell Laboratories' Dennis M. Ritchie a conçu un langage
de programmation structuré, mais très 'près' de la machine: c’est la
naissance du langage C.
K&R-C
En 1978, le duo Brian W. Kernighan / Dennis M. Ritchie a publié la
définition classique du langage C (connue sous le nom de standard K&R-
C ) dans un livre intitulé 'The C Programming Language'.
ANSI-C
En 1983, le 'American National Standards Institute' (ANSI) chargeait une
commission de mettre au point 'une définition explicite et indépendante de
la machine pour le langage C', qui devrait quand même conserver l'esprit
du langage. Le résultat était le standard ANSI-C
16. 16
Avantages
Le grand succès du langage C s'explique par les avantages suivants; C
est un langage:
(1) universel :
C n'est pas orienté vers un domaine d'applications spéciales, comme par
exemple FORTRAN (applications scientifiques et techniques) ou
COBOL (applications commerciales ou traitant de grandes quantités de
données).
(2) compact :
C est basé sur un noyau de fonctions et d'opérateurs limité, qui permet la
formulation d'expressions simples, mais efficaces.
(3) moderne :
C est un langage structuré, déclaratif et récursif; il offre des structures
de contrôle et de déclaration comparables à celles des autres grands
langages de ce temps (FORTRAN, ALGOL68, PASCAL).
17. 17
4) près de la machine :
comme C a été développé en premier lieu pour programmer le système
d'exploitation UNIX, il offre des opérateurs qui sont très proches de
ceux du langage machine et des fonctions qui permettent un accès
simple et direct aux fonctions internes de l'ordinateur (p.ex: la gestion
de la mémoire).
(5) rapide :
comme C permet d'utiliser des expressions et des opérateurs qui sont
très proches du langage machine, il est possible de développer des
programmes efficients et rapides.
(6) indépendant de la machine :
bien que C soit un langage près de la machine, il peut être utilisé sur
n'importe quel système en possession d'un compilateur C. Au début C
était surtout le langage des systèmes travaillant sous UNIX, aujourd'hui
C est devenu le langage de programmation standard dans le domaine des
micro-ordinateurs.
18. 18
(7) portable :
en respectant le standard ANSI-C, il est possible d'utiliser le même
programme sur tout autre système (autre hardware, autre système
d'exploitation), simplement en le recompilant.
(8) extensible :
C ne se compose pas seulement des fonctions standard; le langage est
animé par des bibliothèques de fonctions privées ou livrées par de
nombreuses maisons de développement.
19. 19
Présentation du langage
Premières notions
Les types de base
Les entiers, les réels (sous ensemble fini des rationnels), et les caractères.
Les entiers:
Définition Description Dom min Dom max Nbre
octets
short int Entier court -32768 +32767 2 octet
int Entier standard -32768 +32767 2 octet
long int Entier long -2147483648 +21474836487 4 octet
20. 20
Définition Description Dom min Dom max Nbre
octets
unsigned short int Entier court 0 65535 2 octet
unsigned int Entier standard 0 65535 2 octet
unsigned long int Entier long 0 4294967295 4 octet
Il est possible de travailler avec un entier non signé
Les caractères
Définition Description Dom min Dom max Nbre
octets
unsigned char Caractère non signé 0 255 1 octet
char caractère 0 255 1octet
signed char Caractère signé -128 127 1 octet
21. 21
Les nombres en virgule flottante
<+|-> <mantisse> * 10<exposant>
<+|-> est le signe positif ou négatif du nombre
<mantisse> est un décimal positif avec un seul chiffre devant la
virgule
<exposant> est un entier relatif
En C, nous avons le choix entre trois types de rationnels: float,
double et long double. Dans le tableau ci-dessous, vous trouverez
leurs caractéristiques:
Définition Description mantisse Dom min Dom max Nbre
octets
float simple 6 -3.4 * 10-38 3.4 * 1038 4 octet
double double 15 -1.7 * 10-308 1.7 * 10308 8 octet
long double Long double 19 -3.4 * 10-4932 1.1 * 104932 10 octet
22. 22
2. Les variables
Emplacement mémoire dans lequel est codé une information que l’on
peut modifier et utiliser grâce à un identificateur.
Toute variable doit être déclarée avant d’être utilisée
Syntaxe: <type> < identificateur>
Identificateur: composé de chiffres, de lettres et du caractère _ ; son
premier caractère ne doit pas être un chiffre.
Les majuscules et les minscules ne sont pas équivalentes. Ainsi :
le_langage_C et le_lAngae_C sont deux identificateurs distincts.
Exemple: unsigned long int le nombre; int I_entier;
double le_reel; unsigned char le_caractère;
23. 23
3. Les constantes
Contrairement à une variable, une constante ne peut être modifiée.
Les constantes entières
Elles peuvent être représentées selon trois systèmes de numération:
décimale, octale(précédée de 0) et héxadécimale (précédée de 0x ou 0X)
Base décimale Base octale Base
héxadécimale
Représentation
binaire
100 0144 0X64 1100100
255 0377 0xff 11111111
65536 0200000 0X10000 10000000000000000
24. 24
Selon sa valeur, une constante entière est codé soit comme: un
entier, un entier long. On peut même forcer le codage en entier
long en ajoutant la lettre l ou L. les constantes non signées
s’écrivent avec un u ou U à la fin.
Exemples: 0XAL, 5u, 6l, 10uL, 041lU, 25UL, 0x78ul
Les constantes en virgule flottante
•En notation décimale: <partie entière>.<partie fractionnaire>
Exemples: 3.14159, 1000.001, 2001.007, .125
•En notation scientifique:
<partie entière>.<partie fractionnaire>e[signe]<nombre entier>
<partie entière>.<partie fractionnaire>E[signe]<nombre entier>
Exemples: 3.14159e0, 0.314159E+1, 314.159e-2
25. 25
Les constantes caractères
Une constante caractère s’écrit en encadrant le caractère par deux
apostrophes. Exemple: 'A', '$', 'a', 'o', '0', '1', etc…
Il est possible de remplacer le caractère, par exemple A, par son code
ASCII (65) exprimé en octale précédé par ou héxadécimale précédé
par x. Les constantes 'A' , '101' et 'x41' sont identiques.
Code décimal caractère séquence signification
7 BEL a Sonnette
8 BS b Retour arrière
9 HT t Tab horizontale
10 NL n Changement de ligne
11 VT v Tab verticale
12 FF f Saut de page
13 RC r Retour chariot
26. 26
t o u l e
s m o n d e
Les constantes chaîne de caractères
Une constante chaîne de caractères est une suite finie de caractères,
délimitée par des guillemets.
Une chaîne se termine impérativement par le caractère non affichable
NULL (code ASCII: zéro) qui est ajouté automatiquement par le
compilateur.
Exemple: en mémoire la chaîne "tous le monde" est représentée par:
0
Attention ne confondons pas le caractère 'a' et la chaîne "a"
qui, elle comprend deux caractère 'a' et '0'.
27. 27
Utilisation des constantes:
•Soitdirectement:
I_entier = 20; (on affecte 20 à la variable I_entier),
•Soit en définissant un nom symbolique à la constante par:
# define MAX 20
Et I_entier = MAX;
La directive #define s'adresse au préprocesseur; celui-ci remplace
toutes les occurrences MAX par 20 et ceci avant la compilation.
Exemples: #define MESSAGE ”le langage C ”
#define PI 3.14159
•Soit en utilisant un identificateur déclaré avec le mot-clé const
Syntaxe: const <type> <identificateur> = <valeur>;
Exemples: const double pi =3.14159; const int max = 20;
28. 28
4. Les opérateurs
Les opérateurs, les variables et les constantes permettent de construire
des expressions. En C, une expression a toujours un type et une valeur.
Une instruction élémentaire est obtenue en ajoutant à une expression le
caractère ;
Les opérateurs arithmétiques
Ce sont les opérateurs + (addition), - (soustraction), * (multiplication),
/ (division) et % (reste de la division entière).
Syntaxe: <expression numérique> op <expression numérique>
Où op est l’un des opérateurs +, -, *.
< expression> / < expression> où l’une des deux expression est de
type flottant. Le résultat est de type flottant.
29. 29
<expression entière> / <expression entière> . Le résultat est entier
<expression entière> % <expression entière> . Le résultat est entier
Exemples: 7 * 5 et 7.0 * 5 sont respectivement de type entier et de type
réel. Les expressions 7.0 / 5, 7 / 5 et 7 % 5 valent respectivement
1.4, 1 et 2. Notez bien qu’il y a deux divisions et un seul symbole.
L’affectation
Syntaxe: <variable> = < expression>
Le résultat de l’expression est convertit, si cela a un sens, au type de la
variable.
Déclarons trois variables: int I_entier, le_nombre;
double le_reel;
Les instructions I_entier = 3 ; et le_reel = 3.14 sont des instructions
d’affectation. L’affectation en cascade le_nombre = I_entier = 3 ; est
correcte.
30. 30
L’incrémentation, la décrémentation
Syntaxe: <variable> op ou op <variable> où op est l’un des opérateurs
++ ou –
L’expression le_nombre = le nombre + 1 peut être remplacée par
le_nombre++ ou ++le_nombre.
Attention la valeur de l’expression le_nombre++ est égale à la valeur de
nombre avant l’incrémentation alors que ++le_nombre a pour valeur
le_nombre après l’incrémentation.
Ainsi la séquence d’instructions
Le_nombre = 3; I_entier = le_nombre++; le_reel = ++le_nombre
A pour résultat d’affecter 3 à I_entier et 5 à le_reel, le_nomre contenant
en définitive 5.
L’opérateur de décrémentation a le même comportement que le précédent.
Ainsi l’instruction le_reel--; diminue de 1 le contenu de le_reel.
31. 31
Les affectations généralisées: +=, -=, *=, /=, %=, etc
L’expression I_entier = I_entier + 2 est équivalente à I_entier += 2
L’instruction I_entier = I_entier + le_nombre; est équivalente à
I_entier += le_nombre;
La syntaxe générale est: <variable> op <expression> où op est l’un des
opérateurs +=, -=, *=, /=, %=
Exemple : le_nombre contenant 5. Après la séquence :
I_entier = 8; I_entier += le_nombre; I_entier contient 13.
Les opérateurs relationnels:
égal à (==), différent !=, strictement supérieur à (>), strictement inférieur à
(<), supérieur à (>=) et inférieur à (<=).
32. 32
La syntaxe est : <variable> op <expression> où op est l’un des opérateurs
==, !=,<, >, <=, >=.
Exemples: si I_entier contient 3 , le_nombre 2 et le_reel 3.
Les expressions I_entier==le_nombre, I_entier >4, le_reel<=le_nombre
sont fausses et valent donc 0. De même les expressions I_entier != 5,
le_reel == I_entier, le_nombre < 14 sont vraies et valent 1.
Les opérateurs logiques:
Ce sont les connecteurs ET et OU ainsi que la négation; ils sont représentés
respectivement pa && , ||, et !.
La syntaxe: <expression numérique> op <expression numérique>
où op est l’un des opérateurs && , ||.
!= <expression numérique>
33. 33
Les opérateurs de traitement de bits:
complémentation ~ dans la représentation binaire, tous les bits à 1
sont mis à 0 et réciproquement.
Syntaxe: ~ <expression entière>
Exemple: la représentation de 10 est : 0000000000001010
la représentation de ~10 est : 1111111111110101
les opérateurs de traitement de bits:
syntaxe : <expression entière> OP <expression entière>
OP est l ’un des opérateurs &, | ou ^
& 0 1
0 0 0
1 0 1
| 0 1
0 0 1
1 1 1
^ 0 1
0 0 1
1 1 0
34. 34
Exemple:
la représentation de binaire de 65 est : 0000000001000001
la représentation de binaire de 9 est : 0000000000001001
la représentation de binaire de 65 & 9 est : 0000000000000001
la représentation de binaire de 65 | 9 est : 0000000001001001
la représentation de binaire de 65 ^ 9 est : 0000000001001000
les opérateurs de décalage:
ils permettent de décaler vers la droite (>>) ou vers la gauche (<<)
tous les bits d ’un nombre entier.
Syntaxe: <expression entière> OP <expression entière>
OP est l ’un des opérateurs << ou >>
Exemple:
la représentation de binaire de 65 <<9 est : 1000001000000000
la représentation de binaire de 65 >>3 est : 0000000000001000
35. 35
Les opérateurs & et sizeof().
L ’opérateur & permet de connaître l ’adresse ( l ’emplacement
mémoire) d ’une variable.
Exemple : & I_entier désigne l ’endroit où est la variable I_entier.
Pour connaître la taille on utilise l ’opérateur sizeof().
Syntaxe : & <variable>
sizeof ( <variable>)
sizeof (<type>)
& I_entier I_entier
36. 36
L ’opérateur conditionnel
syntaxe : <expressionC> ? <expression1> : <expression2>
la valeur du résultat est la valeur de l ’expression1 si l ’expressionC est
différente de zéro et expression2 sinon.
Exemple : l ’expression (I_entier == 8 ? I_entier / 2 : 7) a pour
valeur 4 si I_entier vaut 8 et 7 dans le cas contraire.
L ’opérateur de coercition
syntaxe : (<type>) <expression>
il force la conversion du type de la valeur d ’une expression.
Exemple : 012 est de type entier et (double)012 est de type double
si le_reel est de type float, (unsigned long int)le_reel est de type
unsugned long int; la valeur étant correctement arrondie.
37. 37
La virgule est un opérateur
il permet de construire une expression composée.
Syntaxe : <expression1> , <expression2>
l ’expression1 puis l ’expression2 sont évaluées. Le résultat a pour
type et a pour valeur ceux de l ’expression 2.
Exemple : après l ’instruction :
le_nombre = (I_entier = 4 , I_entier ++, I_entier * 3);
le_nombre vaut 15.
L ’opérateur unaire - est l ’opposé
par symétrie, l ’opérateur + est défini.
Exemple : +5, -5, +I_entier, -I_entier.
38. 38
Opérateur Niveau Symbole Associativité
De structure
Unaire
Multiplicatif
Additif
De décalage
D’inégalité
D’égalité
De bit à bit
De bit à bit
De bit à bit
Conjonction
Disjonction
Conditionnel
Exp composée
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
( ) . -> [ ]
~ ! ++ -- - + (<type>)
(indirection), & sizeof
* / %
+ -
>> <<
< <= > >=
== !=
&
^
|
&&
||
? :
= += -= *= /= %=
&= ^= |= <<= >>=
,
De gauche vers droite
De droite vers gauche
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De gauche vers droite
De droite vers gauche
De droite vers gauche
De gauche vers droite
Tableau récapitulatif des opérateurs
39. 39
Les fonctions
Définition :
les fonctions sont les sous-programmes du C; elles permettent de
regrouper des instructions et de lancer leur exécution grâce à un
identificateur.
Syntaxe :
[type] <identificateur>(liste des paramètres formels])
{
. . .
< corps de la fonction>
. . .
} /* fin de la fonction
40. 40
Remarques :
le type d ’une fonction est déterminé par le type du résultat qu ’elle
retourne.
Une fonction qui ne renvoie pas de valeur au programme appelant est
de type void.
Le type par défaut d ’une fonction est int.
Dès qu’une instruction de retour est rencontrée, l ’exécution de la
fonction s ’interrompt.
Syntaxe : return;
return <expression>;
return (<expression>);
si la fonction ne contient pas d ’instruction « return », elle s ’achève
automatiquement à la fin de son bloc.
41. 41
Exemple :
définition :
int ce_double (int tel_nb)
{
int res;
res = tel_nb * 2;
return res;
} /* fin ce_double */
Appel :
ce_double(41.125); ou ce_double(le_nb);
remarque: l ’argument 41.125 est converti en entier à l ’appel.
42. 42
Déclaration de fonction
la déclaration d ’une fonction a pour but d ’avertir le compilateur que
cet objet va être utilisé et de lui préciser le type de son résultat et de
chacun de ses paramètres formels éventuels.
Syntaxe : <type> <identificateur de fonction> (liste des paramètres);
Exemple : déclaration du prototype de la fonction précédente:
int ce_double (int tel_nb); ou int ce_double (int);
Remarque : les prototypes des fonctions des bibliothèques sont
déclarés dans des fichiers « en-tête »; il est souhaitable d ’inclure le
fichier correspondant lorsque l ’une de ces fonctions est utilisée grâce
à la directive de compilation include :
# include <stdio.h>
43. 43
Deux fonctions d ’E/S : printf et scanf
le prototype de ces fonctions est dans le fichier en-tête stdio.h.
la fonction printf
pour afficher des résultats on utilise la fonction printf.
Syntaxe : printf(<format>, [expression1] [, expression2]. . .)
le format est une chaîne de caractères comprenant éventuellement les
spécifications de type des expression1, expression2 etc.. à afficher.
Exemple : le résultat de l ’instruction printf (" coucou le monde!n");
est coucou le monde!
De même printf("le double de %d est %d.n", 8, 16);
donne le double de 8 es 16 .
Printf("Nous étudions n %s sous n UNIX. n", "le langage C")
donne:
44. 44
Nous étudions
le langage C sous
Unix.
Il est possible de fixer la largeur du champ d'affichage pour
l'argument.
Exemple : printf("valeurs : %5d%10.3fn", 14, 3.1459);
donne : 14 3.142
la fonction scanf
permet de saisir des données au clavier et de les ranger dans une
variable.
Syntaxe : scanf (<format>, <adresse d'une variable>)
le format est une chaîne réduite à la spécification de données à saisir.
Exemple : saisir une données entière et la ranger dans la variable
"int" I_entier,
scanf("%d", &I_entier);
45. 45
Le type de l’expression Spécificateur d’affichage Spécificateur de saisie
Int (écriture décimale)
Int (écriture décimale ou
octale ou hexadécimale)
int (écriture octale)
int (écriture hexadécimale)
int unsigned
short int
long int
char
float (écriture décimale)
double (écriture décimale)
long double (décimale)
float (écriture scientifique)
double (scientifique)
long double (scientifique)
chaîne de caractères
%d ou %i
%o
%x
%u
%hd ou %ho ou %hx ou
%hu
%ld ou %lo ou %lx ou
%lu
%c
%f
%f
%Lf
%e ou % E
%e ou %E
%Le ou %LE
%s
%d
%i
%o
%x
%u (décimale)
%hd ou %ho ou %hx ou
%hu
%ld ou %lo ou %lx ou
%lu
%c
%f
%lf
%Lf
%e
%le
%Le
%s
Les spécificateurs de format
46. 46
Structure d'un programme
Organisation d'un programme C
un programme C se présente sous la forme d'un ou plusieurs fichiers
sources.
Chaque fichier contient des déclarations et des définitions de
variables et de fonctions.
La définition d'une fonction contient les déclarations de son type et
de la liste (éventuellement vide) de ses paramètres et un bloc. Le
programme doit contenir une et une seule fonction de nom main :
c'est le point d'entrée du programme.
Un bloc commence par le symbole { , contient des déclarations de
variables et une suite d'instructions et se termine par le symbole }.
Un bloc est appelé aussi "instruction composée".
47. 47
Une instruction est soit une instruction élémentaire (elle doit se
terminer par un point virgule), soit un bloc, soit une instruction de
contrôle. Notez que si un bloc peut contenir un autre bloc, une fonction
ne peut contenir la définition d'une autre fonction.
Des directives de compilation apparaissent aussi dans les fichiers
sources.
Exemples :
Le premier programme:
void main (void)
{
printf (" bonjour, tous le monde!n");
} /* main */
ce programme est écrit à l'aide d'un éditeur de texte et sauvegardé sous
le nom premier.c. Pour le compiler sous Unix (et aussi Linux) il faut
exécuter la commande cc premier.c. Le résultat de la compilation et
de l'édition de liens est alors le fichier exécutable a.out
48. 48
Deuxième programme : taille en octets des types de base
void main(void)
{
printf(" la taille d'un entier est : %d octets n",sizeof(int));
printf(" la taille d'un entier court est : %d octets n",sizeof(short int));
printf(" la taille d'un entier long est : %d octets n",sizeof(long int));
printf(" la taille d'un caractère est : %d octet n",sizeof(char));
printf(" la taille d'un "float" est : %d octets n",sizeof(float));
printf(" la taille d'un "double" est : %d octets n",sizeof(double));
printf("et celle d'un "long double" est:%d octetsn",sizeof(long double));
} /* main de taille.c */
compilons:
cour_C> cc taille.c
49. 49
Exécutons:
cours_C> a.out
la taille d'un entier est : 4 octets
la taille d'un entier court est : 2 octets
la taille d'un entier long est : 4 octets
la taille d'un caractère est : 1 octet
la taille d'un "float" est : 4 octets
la taille d'un "double" est : 8 octets
et celle d'un "long double est : 12 octets
50. 50
Troisième exemple: utilisation de scanf
void main (void)
{
float le_flottant; double le_reel; long double le_reel_double;
printf("entrez un nombre a virgule:");
scanf("%f",&le_flottant);
printf("vous avez tapé %f.n", le_flottant);
printf("Affichage du même nombre avec format : %8.3f.n,le_flottant);
printf("Entrez un nombre a virgule:");
scanf("%lf",&le_reel);
printf("vous avez tapé %f.n", le_reel);
printf("Affichage du même nombre avec format : %16.3f.n,le_reel);
printf("Entrez un nombre a virgule:");
scanf("%Lf",&le_reel_double);
printf("vous avez tapé %Lf.n", le_reel_double);
printf("Affichage du nombre avec format :%20.3Lf.n,le_reel_double);
} /* main de scanf.c */
51. 51
Cours_C> cc scanf.c
cours_C> a.out
Entrez un nombre a virgule : 123456.789012345123456789
Vous avez tapé 123456.789062.
Affichage du même nombre avec format : 123456.789.
Entrez un nombre a virgule : 1234567890123.45123456789
Vous avez tapé 1234567890123.451234.
Affichage du même nombre avec format : 1234567890123.451.
Entrez un nombre a virgule : 123456789012345.123456789
Vous avez tapé 123456789012345.123456.
Affichage du même nombre avec format : 123456789012345.123.
52. 52
Compilation
Sous Unix (Linux) la commande cc lance plusieurs programmes:
•le préprocesseur
•le compilateur
•l'assembleur
•l'éditeur de liens (qui résout les références externes: ex printf et scanf)
Plusieurs syntaxes sont possibles:
cc fichier.c l'exécutable a pour nom a.out.
cc fichier.c -o fichier l'exécutable a pour nom fichier.
cc -c fichier.c compilation sans édition de liens. Le résultat
d'assemlage est mis dans le fichier fichier.o.
cc fichier1.c fichier2.c fichier3.c -o resultat
si le programme est réparti dans plusieurs fichiers sources.
59. 59
Les itérations :
La boucle for
• Syntaxe :
for (exp1;exp2;exp3)
{
instructions;
}
• Toutes ces expressions influent sur la variable
d’itérations qui compte le nombre d’itérations
• exp1 : Initialisation
• exp2 : Condition d’arrêt
• exp3 : Mise à jour
60. 60
Les itérations :
La boucle for
exp2
exp1
vrai
faux
instructions
exp3
Initialisation
Condition d’arrêt
Mise à jour
61. 61
Les itérations :
La boucle while
• Syntaxe :
while (condition)
{
instructions;
}
Tant que condition
vraie exécuter les
instructions
condition
instructions
vrai
faux
62. 62
Les itérations :
La boucle do…while
• Syntaxe :
do
{
instructions;
}
while (condition);
Exécuter les
instructions tant que
condition vraie
condition
instructions
vrai
faux
63. 63
Les itérations
• Utilisation des différents types de boucles :
– for : boucle basée sur une variable d’itération dont on
connaît a priori le début et la fin
– while ou do…while : boucle dont on ignore a priori
quand arrivera la condition de fin
• Une boucle doit respecter uniquement ses
conditions d’arrêt : pas de break !
64. 64
Les fonctions
Définition :
les fonctions sont les sous-programmes du C; elles permettent de
regrouper des instructions et de lancer leur exécution grâce à un
identificateur.
Syntaxe :
[classe] [type] <identificateur>(liste des paramètres formels])
{
. . .
< corps de la fonction>
. . .
} /* fin de la fonction
65. 65
Remarques :
•le type d ’une fonction est déterminé par le type du résultat qu ’elle
retourne.
•Une fonction qui ne renvoie pas de valeur au programme appelant est
de type void.
•Le type par défaut d ’une fonction est int.
•Par défaut la classe d’une fonction est "extern" c-a-d accessible par
toutes les fonctions du programme que celles-ci appartiennent ou non
au fichier où elle est définie. Par contre, une fonction de classe
"static" est locale à son fichier de définition; seules les fonctions du
même fichier peuvent l'appeler.
Exemple:
Considérons les deux fichiers prog_princ.c et fonction1.c
66. 66
cours_C> cat prog_prin.c
void main(void)
{
affiche_le_message();
}/* prog_prin.c*/
cours_C> cat fonction1.c
Void affiche_le_message(void)
{
printf("bonjour tout le monde.n");
}/* fonction1.c*/
cours_C> cc prog_prin.c fonction1.c -o bonjour
prog_prin.c:
fonction1.c:
cours_C>bonjour
Bonjour tout le monde.
67. 67
cours_C> cat fonction2.c
static void affiche_le_message(void)
{
printf("bonjour tout le monde.n");
}/* fonction1.c*/
cours_C> cc prog_prin.c fonction2.c -o bonjour
prog_prin.c:
fonction1.c:
Id: Undefined –
.affiche_le_message
_affiche_le_message
_end
cours_C>
La fonction affiche_le_message est locale au fichier fonction2.c
68. 68
•Dès qu’une instruction de retour est rencontrée, l ’exécution de la
fonction s ’interrompt.
Syntaxe : return;
return <expression>;
return (<expression>);
si la fonction ne contient pas d ’instruction « return », elle s ’achève
automatiquement à la fin de son bloc.
•La compilation s'effectue fichier par fichier, le compilateur peut
rencontrer une référence à une fonction définie dans un autre fichier:
il ignore alors son type; il lui attribue systématiquement le type int.
Exemple:
Le programme principal main affiche le résultat retourné (3.14159)
Par une fonction ce_reel. Ces deux objets sont définis dans des
fichiers différents.
69. 69
cours_C> cat p_princ1.c
void main(void)
{
double le_reel;
le_reel = ce_reel();
Printf(" valeur de le_reel : %f .n", le_reel);
}/* main de p_prin1.c*/
cours_C> cat fonction3.c
double ce_reel(void)
{
return 3.14159;
} /* fonct3.c*/
cour_C>cc p_prin1.c fonct3.c -o echange
p_prin1.c :
fonct.c:
cour_C>echange
Valeur de le_reel : 1074340345.000000
Pour éviter ce genre d'erreur, il faut appliquer la règle suivante:
Tout objet utilisé doit être au préalable déclaré.
70. 70
La déclaration d'une fonction a por but d'avertir le compilateur que cet
objet va être utilisé et de lui préciser le type de son résultat et de chacun
de ses paramètres formels éventuels.
Une fonction est déclarée dans un fichier à partir :
* soit de sa définition (en-tête + corps),
* soit de la simple donnée de son prototype:
<type> <identificateur de fonction> (liste des paramètres) ;
Exemple: modifions le programme p_prin.c précédent.
cours_C> cat prog_prin2.c
double ce_reel(void) /* prototype de la fonction ce_reel() */
void main(void)
{
double le_reel;
le_reel = ce_reel();
printf(" valeur de le_reel : %f .n", le_reel);
}/* main de p_prin1.c*/
71. 71
Exemple de déclaration et d'appel de fonction
Cours_C> cat bissextile.c
#include <stdio.h>
int I_annee;
int cette_annee_est bissextile(void)
{
if (!(I_annee % 4) && I_annee % 100 || !(I_annee % 400))
return 1;
else return 0;
} /* cette année est bissextile */
void main(void)
{
printf(" Donnez une année :");
scanf("%d", &I_annee);
if (cette_annee_est_bissextile())
printf("l'année %d est bissextile.n", I_annee);
else
printf("l'année %d n'est pas bissextile.n", I_annee);
}
72. 72
cours_C> cat pgcd1.c
#include <stdio.h>
long int le_a , le_b;
long int ce_pgcd(void)
{
while ( le_a != le_b)
if (le_a > le_b)
le_a - = le_b;
else le_b - = le_a;
return le_a;
} /* ce_pgcd */
void main(void)
{
printf("Donnez deux nombres >0");
scanf("%ld %ld", &le_a, &le_b);
printf(" le pgcd est %ld. n", ce_pgcd());
} /* main de pgcd1.c */
73. 73
Les paramètres formels
Une écriture plus élégante de la fonction ce_pgcd, consiste à utiliser les
paramètres formels.
cours_C> cat pgcd2.c
#include <stdio.h>
long int ce_pgcd(long int tel_a , tel_b;)
{ while ( tel_a != tel_b)
if (tel_a > tel_b) tel_a - = tel_b;
else tel_b - = tel_a;
return tel_a;
} /* ce_pgcd */
void main(void)
{ long int le_a , le_b;
printf("Donnez deux nombres >0");
scanf("%ld %ld", &le_a, &le_b);
printf("le pgcd de %ld et %ld est %ld.n",le_a,le_b, ce_pgcd(le_a,le_b));
} /* main de pgcd1.c */
74. 74
Le mécanisme d'appel est le suivant:
• dans le programme appelant les arguments éventuels sont évalués,
•Pour chaque paramètre, une variable "interne" à la fonction appelée est
crée et reçoit la valeur de l'argument; cette variable est détruite dès que la
fonction appelée se termine.
180
135
le_a
le_b
main
180
tel_a
tel_b
135
Ce_pgcd
Ce_pgcd()
travaille sur
des copies
et non sur
les
originaux
Les variables le_a et le_b sont locales à la fonction main et ne sont donc
pas accessibles de la fonction ce_pgcd.
75. 75
La récursivité
Une fonction est dite récursive si elle s'appelle elle-même.
Par exemple, réécrivons la fonction ce_pgcd en appliquant
strictement la définition :
long int ce_pgcd( long int tel_a , long int tel_b)
{
if (tel_a == tel_b )
return tel_a ;
else
if ( tel_a > tel_b )
return ce_pgcd( tel_a -tel_b , tel_b )
else
return ce_pgcd( tel_a , tel_b -tel_a )
} /* ce pgcd */
Une fonction récursive doit contenir une condition d'arrêt.
76. 76
Les variables
Déclaration et définition d'une variable.
La déclaration précise les caractéristiques d'une variable; la
définition lui réserve aussi de la place en mémoire: elle est
alors créée. Cette réservation s'appelle l'allocation; elle peut
intervenir soit à la compilation, soit à l'exécution.
Toute variable doit être déclarée avant toute utilisation.
Distinguons trois sortes de variable.
a) Les variables de fichier: elles sont déclarées à l'extérieur
de toute fonction.
b) Les variables de bloc : elles sont déclarées à l'intérieur
d'un bloc.
c) Les paramètres d'une fonction
77. 77
Initialisation.
En C, initialiser une variable c'est lui affecter une valeur au
moment de son allocation; l'affectation apparaît donc dans
la définition. Syntaxe :
[classe] <type> <identificateur> = <expression>
Exemple
int I_entier = 12 ;
A chaque fois que la variable l_entier est créée, le nombre
12 lui est affecté
78. 78
Visibilité d'une variable.
Rappelons qu'une variable doit être déclarée avant son
utilisation et que la portée d'une déclaration est le fichier.
a) Une variable de fichier est visible (utilisable) de sa
déclaration jusqu'à la fin du fichier.
b) Un paramètre de fonction n'est visible que du bloc de
fonction.
c) Une variable de bloc n'est visible que de son bloc.
Toutefois la déclaration d'un paramètre ou d'une variable
de bloc annule localement la déclaration de toute variable
de même nom faite à l'extérieur de ce bloc. Ainsi :
79. 79
Les variables de fichier I_entier et
le_reel ne sont visibles que des blocs
D et C.
Le paramètre I_entier de la fonction f
n'est visible que des blocs A et B.
La variable le_reel du bloc B n'est
visible que de B.
le_reel représente trois variables
distinctes suivant que l'on se trouve
dans A, dans B ou dans C ou D.
80. 80
Redéclaration d'une variable. Droit d'accès.
On peut redéclarer une variable de fichier, évidemment sous
le même nom et avec le même type, en faisant précéder cette
déclaration du mot clé extern. Exemple:
extern int I_entier ; . La redéclaration n'a de sens que si la
variable "originale" est accessible et est effectivement
déclarée et allouée (c'est à dire définie) "ailleurs" afin que
l'on puisse accéder à la donnée qu'elle contient.
Durée de vie d'une variable.
Une variable est :
-soit créée (allouée) à la compilation : elle existe en mémoire
tant que dure la tâche,
-soit créée à l'exécution à chaque fois que cela est nécessaire
et détruite à la fin de son utilisation.
81. 81
Classe de mémorisation d'une variable.
En C, il y a quatre classes de variables: externe,
statique, automatique, registre.
Syntaxe complète de la déclaration d'une variable.
[classe] <type> <identificateur> [=<valeur>];
a)Externe.
Une variable de classe "extern " est :
-soit définie dans le fichier à l'extérieur de toute fonction
(c'est donc une variable de fichier). Elle est accessible à
partir de n'importe quel fichier du programme: elle est
"exportable"; bien sûr, elle doit être déclarée dans les
fichiers où elle n'est pas définie. On peut ne pas faire
précéder sa définition du terme "extern". Cette variable
est de classe extern au sens" global " .
82. 82
-soit définie "ailleurs" .Il faut alors indiquer
explicitement sa classe par le mot clé extern. C'est
alors une simple déclaration; ce mécanisme permet
d'"importer" une variable globale d'un fichier à un
autre.
La norne fournit un moyen très simple de distinguer
ces "deux" points :
-une variable de fichier de classe extern est définie si
elle est initialisée et si le mot extern n'est pas
précisé,
-une variable de classe extern est simplement
déclarée si on spécifie le mot extem sans préciser
d'initialisation.
83. 83
b) Statique.
Une variable de classe "static" est allouée à la compilation dans la
zone des données statiques; elle existe donc en mémoire tant que
Dure la tâche. Elle n'est accessible Que du bloc ou fichier où elle
est définie.
c) Automatique.
Une variable de classe "auto" est allouée à l'exécution dans la pile.
Elle est créée lorsque le bloc dans lequel elle est définie devient
actif; elle est détruite à la sortie du bloc.
d) Registre.
Une variable de classe "register" est allouée à l'exécution dans l'un
des registres de la machine. Elle est créée lorsque le bloc dans
lequel elle est déclarée devient actif; elle est détruite à la fin du
bloc. On ne peut pas connaître l'adresse d'une variable "register".
Si tous les registres sont occupés ou si sa taille ne lui permet pas
d'être mémorisée dans l'un d'eux, une variable "register" est
allouée automatiquement dans la pile.
84. 84
Mettons en évidence la différence entre variable locale
statique et automatique.
void affiche( void ){
int le_nombre = 0; le_nombre ++ ;
(void)printf("% d ", le_nombre ) ;
} /* affiche () * /
int main( void ){
int I_indice = 0 ;
while ( ++I_indice < 10 ) affiche() ;
(void)printf("n") ; return 0;
} /* main de auto.c */
cours_C>cc auto.c
cours_C>a.out
1 1 1 1 1 1 1 1 1
Dans la fonction affiche la variable le_nombre est de classe auto
donc elle est créée et initialisée à chaque appel.
85. 85
#include <stdio.h>
void affiche( void ){
static int le_nombre = 0;
++ le_nombre ;
(void)printf("% d ", le_nombre ) ; } /* affiche () * /
int main( void){
int I_indice = 0 ;
while ( ++I_indice < 10 ) affiche() ;
(void)printf("n") ; return 0;
} /* main de static.c * /
cours_C>cc static.c
cours_C>a.out
1 2 3 4 5 6 7 8 9
Ici la variable le_nombre est de classe "static" aussi elle a été
créée et initialisée à la compilation, et existe tant que dure la
tâche; elle conserve donc sa valeur entre chaque appel.
86. 86
Les tableaux (1)
• « Structure de données permettant de
rassembler une suite de valeurs de même
type en leur donnant un nom commun et en
accédant aux valeurs de la suite par un
indice »
87. 87
Les tableaux (2)
0 2 3 4 5 6
1
int anArray [7] -> 9 3 12 1 1 2
0
anArray[3]
v
void main()
{
int anArray[7];
anArray[0]=9;
anArray[1]=0;
anArray[2]=3;
...
}
!
89. 89
Les tableaux (4)
• Parcours de la totalité d’un tableau :
#define ARRAY_SIZE 1000
for (i=0;i<ARRAY_SIZE;i++)
{
…
}
90. 90
Les tableaux (5)
• Recherche dans un tableau :
#define ARRAY_SIZE 1000
void main()
{
int searchingArray[ARRAY_SIZE];
int element,i=0;
initialization(searchingArray,&element,ARRAY_SIZE);
while((i< ARRAY_SIZE) && (searchingArray[i]!=element))
i++;
if (i== ARRAY_SIZE)
printf("Element %d not found !n",element);
else
printf("Element %d found at indice %dn" ,element,i);
}
91. 91
Les tableaux (6)
• Tableaux et fonctions
• Passage de paramètres
– void readMarks(float markArray[], int nbMark)
• Utilisation dans la fonction:
– markArray[3]=9.75
• Appel :
– readMarks(SMIMarks,nbStudentSMI);
92. 92
Les tableaux (7)
• Résumé :
– Parcours de tous les éléments du tableau ->
boucle for
– Parcours partiel d’un tableau en connaissant les
bornes inférieures et supérieures -> boucle for
– Parcours partiel d’un tableau lorsque la borne
supérieure ou inférieure n’est pas connue ->
boucle while ou do…while
93. 93
Les chaînes de caractères
• Chaîne de caractères -> tableau spécial
o
l
l
e
h 0
o
l
l
e
h
Chaîne de caractères
Tableau de caractères
Fin de chaîne
• Attention prévoir un caractère de plus pour le 0 !!!
94. 94
Les chaînes de caractères (2)
• Ordinateur ne comprend que le binaire
• Représentation des caractères par un nombre entier :
c ’est l ’ASCII
• ASCII : American Standard Code for Information
Interchange
• Tableau de correspondance entre lettre et
représentation ASCII -> table ASCII
95. 95
Les chaînes de caractères (3)
l’ASCII
• Proposé par l ’ANSI (AN Standards Institute) en 1963,
finalisé en 68, utilisé à partir de 80
• Créé par Bob Bemer d’IBM
• Codage sur 7 bits avec en plus l’escape caracter
• 32 premiers caractères sont des caractères de contrôle
(7 est une sonnerie, 8 effacement du caractère
précédent, 13 retour à la ligne, …)
96. 96
Les chaînes de caractères (3)
l’ASCII
• Exemple de codage ASCII :
Notation ASCII décimale
Notation humaine
104 101 108 108 111 0
h e l l o 0
68 65 6C 6C 6F 0 Notation ASCII hexadécimale
97. 97
Les chaînes de caractères (4)
l’ASCII
• C ’est l ’ordinateur qui gère la conversion
• Utiliser de préférence la notation humaine (c ’est plus
clair pour les humains…)
• ‘A’ est équivalent à 65, ‘a’ à 97, etc.
• Ex :
– char mLetter=‘a’+12;
98. 98
Les chaînes de caractères (2)
0 2 3 4 5
1
char aString [6] ->
aString[3]
v
#include <string.h>
void main()
{
char aString[6]="hello0";
aString[0]=‘h’;
aString[1]=‘e’;
...
strcpy(aString,"hello");
}
0
o
l
l
e
h
99. 99
Les chaînes de caractères (3)
• Initialisation d’une chaîne :
– Lors de la déclaration
– Element par élément
• Fonctions dédiées :
– scanf (stdio.h)
– strcpy (string.h)
100. 100
Les chaînes de caractères (4)
• Affichage avec printf :
• printf(“%sn”,myString);
101. 101
Les chaînes de caractères (5)
Les fonctions standard
• Longueur : length=strlen(myString);
• Copie : strcpy(myString,”hello”);
• Concaténation :strcat(myString,”lo”);
• Comparaison :strcmp(string1,string2);
• Transformation en entier :
integer=atoi(myString);
• Transformation en flottant :
floatingPoint=atof(myString);
102. 102
Les tableaux à plusieurs
dimensions
• 2 dimensions
– Déclaration : int matrix[LINE_SIZE][COL_SIZE];
– Utilisation : matrix[4][3]=4;
• 3 dimensions
– Est-ce bien utile ?
103. 103
Structures en C
• Tableau : ensemble de valeurs de même
type
• Structure : ensemble de valeurs de types
différents
• Une structure s’utilise comme un type de
données
104. 104
Structures : Définition
struct Student
{
char firstName[50];
char lastName[50];
int age;
};
int main()
{
struct Student toto;
toto.age=19;
return 0;
}
Champ
Définition de la structure
Ne pas oublier le ;
Déclaration d’une variable
Accès aux champs avec .
105. 105
Structures : Définition
• Définition globale ou dans le header (.h)
• mot-clef struct devant la déclaration de
variable (possibilité d’utiliser un typedef)
• . est l ’opérateur d ’accès aux champs
106. 106
Structures : Imbrication
struct Date
{
int jour,mois,annee;
};
struct Etudiant
{
char nom[50];
char prenom[50];
int age;
struct Date dateInscription;
};
int main()
{
struct Etudiant toto;
toto.dateInscription.jour=1;
return 0;
}
107. 107
Tableaux de structures
struct Etudiant
{
char nom[50];
char prenom[50];
int age;
};
int main()
{
struct Etudiant smi[50];
smi[0].age=19;
return 0;
}
109. 109
Plan du cours
• La notion d'adresse mémoire
• La notion de pointeur
• Pointeurs et passage de paramètres
• Pointeurs et tableaux
• Pointeurs et chaînes de caractères
• Allocation dynamique de mémoire
• Les allocations mémoire en C
110. 110
La notion d'adresse mémoire
La définition de variable int i = 5; peut être interprétée de 2 façons.
Point de vue conceptuel Point de vue du compilateur C
• i est un nom symbolique
qui désigne une variable
qui prend des valeurs entières
i 5
• i est une zone mémoire dimensionnée
pour contenir des valeurs entières
• le compilateur attribue une adresse
à i en mémoire
5
102
adresse mémoire
111. 111
Accès à l'adresse mémoire d'une variable
• l'adresse d'une variable est une donnée en elle-même
=> on peut manipuler les adresses mémoire
• le langage C autorise :
-> l'accès à l'adresse mémoire d'une variable
-> la manipulation des adresses mémoire à l'aide d'opérateurs
-> la déclaration de variables dont les valeurs sont
des adresses mémoire (notion de pointeur)
• l'opérateur "&"
si i est une variable entière, alors &i est une expression dénotant
l'adresse de i
5
&i
112. 112
La notion de pointeur
• Déclaration d'une variable pointeur sur un type
• Affectation à un pointeur
• L'opérateur *
pi *pi
variable pointeur variable pointée
l'opérateur * permet d'accéder
à la variable pointée : il sert
à déréférencer le pointeur
5
int i = 5; ==> pi = &i;
int * pi; /* pi est un pointeur sur entier */
char * pc; /* pc est un pointeur sur caractère */
-> on peut déclarer un pointeur sur un type quelconque
i ⇔* (&i)
113. 113
Les opérations sur les pointeurs
•le déférencement "*"
• l'affectation "="
• les opérateurs de comparaison "==", "!="
• les opérateurs "+" et "-" sur les adresses
• la constante NULL est une valeur spéciale du fichier stdio.h
-> un pointeur à NULL ne pointe sur rien
• les opérations d'allocation dynamique de la mémoire malloc et de
désallocation free offertes par la librairie standard (fichier stdlib.h)
114. 114
Un programme illustrant les pointeurs
main ()
{
int i = 5, j = 9;
int *p1, *p2; /* deux pointeurs sur entier */
p1 = &i; /* *p1 est la variable i */
p2 = p1; /* p2 désigne la variable pointée par p1, c'est à dire i */
*p1 = 9; /* la variable i est modifiée */
if (p1 == p2) printf (" Nécessairement *p1 == *p2 ");
p2 = &j; /* *p2 est la variable j */
if (*p1 == *p2) printf (" Ne signifie pas p1 == p2 !!! ");
}
115. 115
Pointeurs et typage
• Typage d'un pointeur
- un pointeur est typé par le type de l'objet pointé
int * pi1, * pi2; /* pi1 et pi2 sont de type pointeur sur entier */
char * pc; /* pc est de type pointeur sur caractère */
• Affectation entre pointeurs
- l'affectation p1 = p2 est correcte si p1 et p2 sont de même type
- pi1 = pi2; /* affectation correcte */
- pi1 = pc; /* affectation erronée !!! */
116. 116
Passage de paramètres par valeur
#include <stdio.h>
int carre ( )
{
return (x * x);
}
main ()
{
int i = 3;
int car;
car = carre ( );
printf ("%d", car);
}
main Carre
i
i
car
car
i
3
copie
valeur
retour
valeur
avant
appel
de carre
appel
de carre
fin de
l'exéc.
de carre
3 3
3
9 9
car
x
int x
i
117. 117
Passage de paramètres par adresse
#include <stdio.h>
void raz ( )
{
*ip = 0;
}
main ()
{
int i = 3;
raz ( );
printf ("%d", i);
}
main Raz
i
i
i
3
copie
avant
appel
de raz
appel
de raz
fin de
l'exéc.
de raz
3
int *ip
&i
&i ip
adresse
0
*ip
118. 118
Synthèse sur le passage de paramètres
• Passage par valeur
- la valeur du paramètre effectif est recopiée dans le paramètre for
- le paramètre effectif est la valeur d'une expression
- le paramètre effectif ne peut pas être modifié par la fonction
• Passage par adresse
- l'adresse du paramètre effectif est recopiée dans le paramètre form
- le paramètre effectif est une variable
- le paramètre effectif peut être modifié par la fonction
- un tableau est toujours passé par adresse
119. 119
Pointeurs et tableaux
• Identificateur de tableau
le nom d'un tableau est une constante dont la valeur
est l'adresse du premier élément du tableau
0 1 2
ou &t[0]
• Opérateurs "+" et "-" sur les pointeurs
int *p;
p = &t[1]; ==> p+1 pointe sur t[2] et p-1 pointe sur t[0]
• Equivalence tableau / pointeur
int t[N]; ==> &t[k] equivaut à t+k pour k dans 0..N-1
t
int t[3];
120. 120
Tableau en paramètre de fonction
• Prototype d'une fonction triTableau
void triTableau (int tab[], int n);
• Appel de la fonction triTableau
int t[3] = {4, 7, 2};
triTableau (t,3);
• Passage du tableau t en paramètre
à l'appel de triTableau, l'argument tab est initialisé avec &t[0]
==> un tableau est toujours passé par adresse
/* tab est une variable
de type pointeur sur entier */
/* t est une constante de type pointeur sur entier */
122. 122
Pointeurs et chaînes de caractères
• Constantes chaînes de caractères
- "ada", "pascal" sont des constantes littérales
- une constante chaîne de caractères est implantée comme
une séquence de caractères, terminée par le caractère '0'
- sa valeur est l'adresse de son premier caractère
- son type est pointeur sur caractère
• Pointeurs sur chaîne de caractères
char * ch = "ada";
• Tableaux de caractères
char tc[] = {'a', 'd', 'a', '0'};
a a
d 0
non modifiable !!
ch
a a
d 0
modifiable !!
tc
non modifiable !!
modifiable !!
123. 123
Allocation dynamique de mémoire
• Principe de l'allocation dynamique
- le programmeur alloue demande au système d'exploitation de lu
allouer de la mémoire durant l'exécution
- les variables allouées dynamiquement sont stockées
dans une zone mémoire dédiée appelée tas (heap)
• Fonctions d'allocation
- fournies par la bibliothèque standard : fichier <stdlib.h>
- allocation d'une zone mémoire : fonction malloc
- désallocation d'une zone mémoire : fonction free
124. 124
La fonction malloc
• L'opérateur sizeof
- donne la taille en octets d'un type ou d'une expression
- sizeof (int) vaut 4, sizeof (char) vaut 1, ...
- int i; => sizeof i vaut 4
• Allocation d'une variable de type simple
int * ip;
ip = malloc ( sizeof (int) ); /* ou malloc ( sizeof *ip )*/
• Allocation d'une variable structurée
typedef struct {float re,im;} Complexe;
Complexe * cp;
cp = malloc ( sizeof (Complexe) ); /* ou malloc ( sizeof *cp ) */
125. 125
La fonction free
• Contexte initial
z *z
z->re ou (*z).re z->im ou (*z).im
0.0 1.0
Complexe * z;
z = malloc (sizeof(Complexe));
z->re = 0.0; z->im = 1.0;
• Suppression d'une variable dynamique
free (z);
z
• Attention danger !!!
- après free(z), une référence à *z est une erreur !
- suppression d'une variable dynamique désignée par n pointeurs !
?
126. 126
Les allocations mémoire en C
• Allocation statique
- variable externe à une fonction (variable globale)
- variable locale à une fonction mais déclarée static
- allocation statique à la compilation
- initialisation par défaut à 0
• Allocation automatique
- variable interne à une fonction (variable locale)
- allocation automatique à l'exécution dans la pile (stack)
- initialisation indéfinie
• Allocation dynamique avec malloc
- variable dynamique
- allocation dynamique à l'exécution dans le tas (heap)
- initialisation indéfinie
128. Le type fichier
• On manipule les fichiers par l’intermédiaire de
structures FILE décrites dans stdio.h
FILE *monFichier;
– Nom physique
– Type d’accès(binaire ou formaté … distinction floue)
– Adresse du buffer
– Position dans le fichier
– Indicateur d’erreur
• Trois fichiers/flux standard, ouvert par défaut:
stdin, stdout et stderr
129. Ouverture/Fermeture d’un fichier
• Faire le lien entre le nom physique (chaîne de caractère,
chemin absolu ou relatif) et le nom logique (nom du
pointeur)
• Ouvrir dans le mode choisi (binaire, écriture, écraser,
lecture,…)
• Se positionner au début de fichier
fich = fopen(nom_physique, mode);
TESTER si le fichier a été ouvert (pas null).
fopen(nom, ``r``); →0 si le fichier n’existe pas.
fopen(nom, ``w``); →0 si le chemin d’accès est faux.
fclose(fich);
130. Mode d’ouverture
• r ouverture d’un fichier texte en lecture
• w crée un fichier texte en écriture, écrase le contenu
précédent si le fichier existait.
• a ajoute: ouvre ou crée un fichier texte et se positionne en
écriture à la fin du fichier.
• r+ ouvre un fichier en mode mise à jour (lecture et
écriture)
• w+ crée un fichier texte en mode mise à jour, écrase le
contenu précédent si le fichier existait.
• a+ ajoute, ouvre ou crée un fichier texte en mode mise à
jour et se positionne en écriture à le fin du fichier.
132. Les entrées/sorties caractère
• int getc(FILE *); int fgetc(FILE *); int getchar();
• int putc(FILE *); int fputc(FILE *); int putchar();
Exemple:
void main(void){
int c;
FILE *fich;
fich = fopen(``données``, ``r``);
do{
c = getc(fich);
} while(c= = EOF);
}
Autre test sortie: int feof(FILE *) retourne pas zéro si EOF
133. Les entrées/sorties formatées
• Les fonctions fprintf() et fscanf() s’utilisent
exactement de la même façon que printf et scanf,
il suffit d’ajouter un paramètre pointeur de fichier:
FILE *fichier;
fichier = fopen(nomFichier, ``w``);
int x=25;
fprintf(fichier, ``%dn``,x);
Qui pourra être lu par: fscanf(fichier,``%d``,&a);
134. Les entrées/sorties binaires
bufferisées
• Sur fichiers ouverts en binaire fich = fopen(monFichier,
``rb``);
• size_t fread(void *ptr, size_t size, unsigned int n, FILE
*stream);
• size_t fwrite(void *ptr, size_t size, unsigned int n, FILE
*stream);
• Principe: écrire directement la représentation machine des
variables (c’est-à-dire de leur contenu mémoire)
• Exemple: short x =1024; 00000100 00000000
fprintf(fich,``%d``,x) écrira les 4 caractères ‘1’, ‘0’, ‘2’ et
‘4’ dans le fichier texte
fwrite(&x, sizeof(x), 1, fich) écrira les deux octets dans le
fichier
135. Les entrées/sorties binaires
bufferisées(2)
• Avantages: stockage réduit et
lecture/écriture efficace. (une copie de la
mémoire)
• Inconvénients: non portable (taille des
objets diff.), non lisibles par éditeurs de
textes. (créer des programmes scanf/fwrite
et fread/printf C pour les convertir)
136. Fonction de parcours du fichier
int fseek(FILE *flux, long int offset, int flag);
Modifie la position du pointeur de fichier (lieu
du prochain accès).
Flag:
– SEEK_SET début de fichier
– SEEK_CUR relativement à la position courante
– SEEK_END fin du fichier
137. Traitement des erreurs de gestion de
fichier
Accès à des fichiers est source d’erreurs
multiples:
• Lors de l’ouverture (fichier inexistant, droits
restrictifs, manque de place, erreur
matérielle)
• Rencontre d’une fin de fichier
• Manque de place sur l’unité concernée
• Destruction de la structure FILE
• Mauvaise opération sur pointeur de fichier
138. Détection des erreurs
• Seule l’erreur matérielle est détecté par le système,
toute les autres ne provoquent PAS l’arrêt du
programme: il faut les traiter.
• Un indicateur ferror peu efficace (oui/non)
int ferror(FILE *);
• Un indicateur errno peu fiable
• Détection de la fin de fichier avec feof (il faut
avoir lu la fin de fichier pour la reconnaître)
• Consulter les valeurs de retour des fonctions
139. Détection des erreurs
• nb_ecrit = fwrite(…,nblocs,fich);
Si nb_ecrit == nblocs OK, si inf: erreur
• nb_lu = fread(…, nblocs,fich);
Si nb_lu == nblocs et !feof, OK
Si nb_lu est inf. à nblocs et !feof, pb materiel
Si nb_lu == 0 et feof, fin de fichier normal
Si nb_lu !=0 et eof, fin de fichier anormal
140. Détection des erreurs
• ncar = fprintf(fich, …); si negatif alors pb
• nb_lu = fsanf (fich,…);
Si nb_lu == nb_attendu et !feof, OK
Si nb_lu est inf. à nb_attendu et !feof, pb materiel
Si nb_lu == EOF et feof, fin de fichier normal
Si nb_lu !=EOF et eof, fin de fichier anormal
141. Détection des erreurs
• c_ecrit = fputc(…,fich);
c_ecrit != EOF, l’écriture s’est bien déroulé
sinon, erreur d’écriture par manque de place ou
erreur matériel.
• ret = fgetc(fich);
ret != EOF et !feof lecture normale
ret == EOF et !feof pb matériel
feof fin de fichier normale