Documente Academic
Documente Profesional
Documente Cultură
Initiation à la programmation
Présenté par Ghislain AKINOCHO
Généralités
Historique du langage
Création d’un programme C
Edition du programme
Compilation
Edition des liens
Bibliothèques de fonctions prédéfinies
Les composants d’un programme C
1
30/10/2009
Historique du langage C
Le langage a été crée en 1972 par Denis Ritchie
avec un objectif relativement limité : l’écriture d’un
système d’exploitation (UNIX). Mais ses qualités
opérationnelles l’ont très vite fait adopter par une
large communauté de programmeurs.
Historique du langage C
Kernighan et Ritchie réalisent une première
définition rigoureuse de ce langage en publiant
l’ouvrage The C programming Language en 1978.
De nombreux compilateurs ont alors vu le jour en
se fondant sur cette définition.
2
30/10/2009
Historique du langage C
Le succès international du langage à conduit à sa
normalisation dans cet ordre :
ANSI (American National Standard Institute)
ISO (International Standardization Organisation)
CEN en 1993 (Comité Européen de Normalisation)
Historique du langage C
Fort heureusement, toutes ses normes sont
identiques, et l’usage veut qu’on parle de « C
ANSI » ou de « C Norme ANSI »
3
30/10/2009
4
30/10/2009
L’édition du programme
Elle consiste à créer un texte qu’on nomme :
programme source. Il est conservé dans un ou
plusieurs fichiers (fichier source).
Un fichier, en général peut, en plus de son nom,
être caractérisé par un groupe de caractères
qu’on appelle : extension ou parfois type
L’édition du programme
La plupart du temps, en langage C les fichiers
sources porteront l’extension C
5
30/10/2009
La compilation
Elle consiste à traduire le programme source (ou
le contenu d’un fichier source) en langage
machine en faisant appel à un programme ou
logiciel nommé compilateur.
Le résultat de cette opération porte le nom de
module objet.
La compilation
En C, la traduction d’un fichier source se déroule
en deux étapes totalement indépendantes :
Un prétraitement
Une compilation proprement dite
6
30/10/2009
La compilation
Généralement, on parle de préprocesseur pour
désigner le programme réalisant le prétraitement.
L’étape de prétraitement correspond à une
modification du texte du fichier source.
La compilation
Cette modification est basée essentiellement sur
l’interprétation d’instructions particulières dites
directives à destination du préprocesseur.
Elles sont reconnaissables par le fait qu’elles
commencent par le symbole #.
7
30/10/2009
La compilation
Les deux directives les plus importantes sont :
La directive d’inclusion d’autres fichiers sources
#include
La directive de définition de macros ou de symboles
#define
La compilation
La directive #include est surtout utilisée pour
incorporer le contenu de fichiers prédéfinis dits
fichiers en-tête, indispensable à la bonne
utilisation des fonctions de la bibliothèque
standard,
la plus connue
#include <stdio.h>
8
30/10/2009
La compilation
La seconde est généralement exploitée par le
programmeur dans les définitions de symboles
telles que :
#define TAILLE_MAX 50
#define NBnotes 30
La compilation
Bien que formé d’instructions machine, le
module objet obtenu après la seconde étape
(compilation proprement dite) n’est pas
exécutable tel quel car :
Il peut lui manquer d’autres modules objets
Il lui manque les instructions exécutables des
fonctions standard appelées dans le fichier source
(par exemple printf, scanf, …)
9
30/10/2009
10
30/10/2009
Utilisation
La pratique en C exige l'utilisation de
bibliothèques de fonctions. Ces bibliothèques sont
disponibles dans leur forme précompilée
(extension: .LIB)
Pour pouvoir les utiliser, il faut inclure des fichiers
en-tête (header files - extension .H) dans nos
programmes
Ces fichiers en-têtes contiennent des 'prototypes'
des fonctions définies dans les bibliothèques et
créent un lien entre les fonctions précompilées et
nos programmes.
Lors de la programmation en C, nous travaillerons
avec différents types de fichiers identifiés par
leurs extensions :
11
30/10/2009
*.C – fichier source
*.OBJ – fichiers compilés (module objet)
*.EXE – fichiers compilés et liés (version
exécutable)
*.LIB – bibliothèque de fonctions
précompilées
*.H – fichiers en-têtes (header files)
12
30/10/2009
Fichiers en-têtes
#include<stdio.h>
maths.h
void main()
stdio.h { ….
}
Bibliothèques
précompilées Génération du .OBJ
module objet
maths.lib
Edition des liens
.EXE
13
30/10/2009
14
30/10/2009
Les fonctions
En C, le programme principal et les sous-
programmes sont définis comme fonctions. Il
n'existe pas de structures spéciales pour le
programme principal ni de procédures (comme en
Pascal ou en langage algorithmique).
15
30/10/2009
16
30/10/2009
17
30/10/2009
La fonction main
C’est la fonction principale des programmes en C.
Elle se trouve obligatoirement dans tous les
programmes. L’exécution d’un programme
entraîne automatiquement l’appel de la fonction
main
18
30/10/2009
Résultat de main
Tout programme devrait en principe retourner
une valeur comme code d’erreur à son
environnement. Par conséquent, le type de
résultat de main est toujours int. Le type de
main peut donc ne pas être déclaré
explicitement car c’est le type par défaut.
19
30/10/2009
Résultat de main
Les programmes se termineront alors par :
return 0;
qui indique à l’environnement que le programme
s’est terminé avec succès, sans anomalies.
Les variables
Les variables sont des emplacements mémoire
portant un nom et dont le contenu est susceptible
d’évoluer ou de varier comme son nom l’indique.
Ces variables contiennent des valeurs qui sont
utilisées pendant l’exécution du programme.
20
30/10/2009
Les identificateurs
Dans un programme en C, les noms de fonctions
et de variables sont composés d’une suite de
lettres et de chiffres. Cette suite de caractères est
désigné par un nom qu’on appelle identificateur.
Le premier caractère doit être une lettre. Le
symbole ‘_’ est considéré comme une lettre
Les identificateurs
L’ensemble des symboles utilisables est donc :
{0,1,2,…,9,A,B,…,Z,_,a,b,…,z}
C distingue les majuscules des minuscules, ainsi :
« Nomvar » est différent de « nomvar »
21
30/10/2009
Remarque:
Il est déconseillé d'utiliser le symbole '_' comme
premier caractère pour un identificateur, car il est
souvent employé pour définir les variables
globales de l'environment C.
Les commentaires
Un commentaire commence toujours par les deux
symboles '/*' et se termine par les symboles '*/'. Il
est interdit d'utiliser des commentaires imbriqués.
Exemple
/* Ceci est un commentaire correct */
/* Ceci est /* évidemment */ défendu */
22
30/10/2009
Les mots-clés
Certains mots sont réservés par le langage à un
usage bien défini. On les nomme des mots clés.
Un mot clé ne peut pas être employé comme
identificateur!!
23
30/10/2009
Le format libre
Le langage C autorise une mise en page
parfaitement libre. En particulier :
une instruction peut s’étendre sur un nombre
quelconque de lignes
une même ligne peut comporter autant d’instructions
que voulu.
Cette liberté de mise en page peut aboutir si l’on n’y
prend garde, à l’édition de programmes illisibles.
24
30/10/2009
25
30/10/2009
26
30/10/2009
27
30/10/2009
28
30/10/2009
29
30/10/2009
30
30/10/2009
Notation Code ASCII Abréviation Signification
en C (hexadécimal) usuelle
\a 07 BEL Cloche ou bip
\b 08 BS Retour arrière
(Backspace)
\f 0C FF Saut de page
\n 0A LF Saut de ligne
\r 0D CR Retour charriot
\t 09 HT Tabulation horizontal
\v 0B VT Tabulation verticale
\\ 5C \
\ 2C
\ 22
\? 3F ?
31
30/10/2009
32
30/10/2009
33
30/10/2009
Le type booléen
En C il n'existe pas de type spécial pour
variables booléennes.
Tous les types de variables numériques
peuvent être utilisés pour exprimer des
opérations logiques:
valeur logique faux valeur numérique zéro
valeur logique vrai toute valeur différente de zéro
34
30/10/2009
35
30/10/2009
const
En utilisant l’attribut const, nous pouvons
indiquer que la valeur d’une variable ne change
pas au cours d’un programme :
const int MAX = 767;
const float PI = 3.14;
const double e = 2.718281828459;
const char NEWLINE = '\n';
36
30/10/2009
37
30/10/2009
|| ou logique (or)
Opérateurs de comparaison
== égal à
!= différent de
<,<=,>,>= inférieur à, …
38
30/10/2009
Opérations logiques
Les opérateurs logiques considèrent toute valeur
différente de zéro comme vrai et égale à zéro
comme faux
1 && 9 1
!78.89 0
0||!(32 > 12) 0
39
30/10/2009
Conversions implicites
Les opérateurs arithmétiques n’étant définis que
lorsque les deux opérandes sont de même type, il
est cependant possible de faire intervenir dans
une expression des opérandes de types différents
(« expression mixte »)
40
30/10/2009
Exemple
int n, p; float x ; n * x + p;
Compte tenu des règles de priorité, le compilateur
doit d’abord effectuer le produit n * x. Pour que
cela soit, il effectuera une conversion de la valeur
de n dans le float. La multiplication portera alors
sur deux opérandes de type float et fournira un
résultat de type float.
Exemple
int n, p; float x ; n * x + p;
Pour l’addition, on se retrouve à nouveau dans la
même situation (float + int). Le même mécanisme
de conversion est mis en place et le résultat final
est un float.
41
30/10/2009
Expressions
La formation des expressions est définie par
recurrence :
Les constantes et les variables sont des expressions.
Les expressions peuvent être combinées entre elles par
des opérateurs et former ainsi des expressions plus
complexes.
Les expressions peuvent contenir des appels de
fonctions et peuvent apparaître comme
paramètres dans les appels de fonctions.
Exemples
i=0
i++
X=pow(A,4)
printf(" Bonjour !\n")
a=(5*x+10*y)*2 (a+b)>=100
position!=limite
42
30/10/2009
Instructions
Une expression comme :
i=0 ou
i++ ou
X=pow(A,4) devient une instruction, si elle est
suivie d’un point-virgule.
Exemples
i=0;
i++;
X=pow(A,4);
printf(" Bonjour !\n");
a=(5*x+10*y)*2; (a+b)>=100;
position!=limite;
43
30/10/2009
printf()
La fonction printf est utilisée pour transférer du
texte, des valeurs de variables ou des résultats
d'expressions vers le fichier de sortie standard
stdout (par défaut l'écran).
Ecriture formatée en C
printf("<format>",<Expr1>,<Expr2>, ... )
<format> : format de représentation
<Expr1>,…: variables et expressions dont les valeurs
sont à représenter
44
30/10/2009
printf()
La partie <format> est en fait une chaîne de caractères
qui peut contenir :
du texte
des séquences d’échappement (\n , \t, \’)
des spécificateurs de format
Ils indiquent comment la manière dont les valeurs des
expressions <Expr1 … N> sont imprimées. (Un spécificateur
de format pour chaque exppression <Expr1 … N> )
Ils commencent toujours par le symbole % et se terminent par
un ou deux caractères qui indiquent le format d'impression.
Exemple :
La suite d’instructions
int a = 12;
int b = 4;
printf("%d fois %d est %d\n", a, b,
a*b);
va afficher à l’écran
12 fois 4 est 48
45
30/10/2009
scanf()
La fonction scanf est la fonction symétrique à printf;
elle nous offre pratiquement les mêmes conversions
que printf, mais en sens inverse.
Lecture formatée en langage algorithmique
lire <NomVariable1>,<NomVariable2>, ...
Lecture formatée en C
scanf("<format>",<AdrVar1>,<AdrVar2>, ...)
"<format>" : format de lecture des données
<AdrVar1>,... : adresses des variables auxquelles les données seront attribuées
46
30/10/2009
La suite d'instructions:
int JOUR, MOIS, ANNEE;
scanf("%i %i %i", &JOUR, &MOIS, &ANNEE);
lit trois entiers relatifs, séparés par des espaces,
tabulations ou interlignes. Les valeurs sont attribuées
respectivement aux trois variables JOUR, MOIS et
ANNEE.
47
30/10/2009
Exemples
char A = 225; char B = '\a'; int C = '\a';
putchar('x'); /* afficher la lettre x */
putchar('?'); /* afficher le symbole ? */
putchar('\n'); /* retour à la ligne */
putchar(65); /* afficher le symbole avec le
code 65 (ASCII: 'A') */
putchar(A); /*afficher la lettre avec le
code 225 (ASCII:'ß') */
putchar(B); /* beep sonore */
putchar(C); /* beep sonore */
48
30/10/2009
49
30/10/2009
if – else
La structure alternative en langage algorithmique
si (<expression logique>)
alors <bloc d'instructions 1>
sinon <bloc d'instructions 2>
fsi
La structure alternative en C
if ( <expression> )
<bloc d'instructions 1>
else
<bloc d'instructions 2>
50
30/10/2009
Exemples
if (a > b)
max = a;
else
max = b;
if (EGAL)
printf("A est égal à B\n");
else
printf("A est différent de B\n");
51
30/10/2009
Exemple
La suite d'instructions
if (A>B)
MAX=A;
else
MAX=B;
MAX = (A > B) ? A : B;
52
30/10/2009
while
La structure while correspond tout à fait à la structure
tant que du langage algorithmique.
La structure tant que en langage algorithmique
tant que (<expression logique>) faire
<bloc d'instructions>
ftq
Tant que l'<expression logique> fournit la valeur vrai,
le <bloc d'instructions> est exécuté.
Si l'<expression logique> fournit la valeur faux,
l'exécution continue avec l'instruction qui suit ftant.
Le <bloc d'instructions> est exécuté zéro ou plusieurs fois.
La structure while en C
while ( <expression> )
<bloc d'instructions>
Tant que l'<expression> fournit une valeur différente de
zéro, le <bloc d'instructions> est exécuté.
Si l'<expression> fournit la valeur zéro, l'exécution continue
avec l'instruction qui suit le bloc d'instructions.
Le <bloc d'instructions> est exécuté zéro ou plusieurs fois.
53
30/10/2009
Exemple 1
/* Afficher les nombres de 0 à 9 */
int I = 0;
while (I<10)
{
printf("%i \n", I);
I++;
}
do – while
La structure do - while est semblable à la
structure while, avec la différence suivante :
while évalue la condition avant d'exécuter le bloc
d'instructions,
do - while évalue la condition après avoir exécuté
le bloc d'instructions. Ainsi le bloc d'instructions est
exécuté au moins une fois.
54
30/10/2009
La structure do - while en C
do
<bloc d'instructions>
while ( <expression> );
Le <bloc d'instructions> est exécuté au moins une fois et
aussi longtemps que l'<expression> fournit une valeur
différente de zéro.
En pratique, la structure do - while n'est pas si
fréquente que while; mais dans certains cas, elle fournit
une solution plus élégante.
Une application typique de do - while est la saisie de
données qui doivent remplir une certaine condition.
Exemple 1
float N;
do
{
printf("Donnez un nombre entre 1 et 10 :");
scanf("%f", &N);
} while (N<1 || N>10);
55
30/10/2009
for
La structure for en Pascal et la structure pour en
langage algorithmique sont utilisées pour faciliter la
programmation de boucles de comptage. La structure
for en C est plus générale et beaucoup plus puissante.
La structure for en C
for ( <expr1> ; <expr2> ; <expr3> )
<bloc d'instructions>
est équivalent à :
<expr1>;
while ( <expr2> )
{
<bloc d'instructions>
<expr3>;
}
56
30/10/2009
Exemple
int I;
for (I=0 ; I<=20 ; I++)
printf("Le carré de %d est %d \n", I, I*I);
57
30/10/2009
Exemple
int n, tot;
for (tot=0, n=1 ; n<101 ; n++)
tot+=n;
printf("La somme des nombres de 1 à 100 est
%d\n", tot);
58
30/10/2009
Exemple
La déclaration
int mois[12]={31,28,30,31,30,31,30,31,30,31,30,31}
définit un tableau de type int de dimension 12. Les
douze composantes sont initialisées par les valeurs
31,28 ... , 30,31.
On peut accéder à la première composante du tableau
par mois[0], à la deuxième par mois[1],...,
à la dernière par mois[11]
59
30/10/2009
60
30/10/2009
61
30/10/2009
Affectation avec des valeurs provenant de
l'extérieur
main()
{
int A[5];
int i; /* Compteur */
for(i=0;i<5;i++)
scanf("%d ", &A[i]);
return 0;
}
Remarques
Comme scanf a besoin des adresses des
différentes composantes du tableau, il faut faire
précéder le terme A[i] par l'opérateur adresse '&'.
62
30/10/2009
......
Tab L lignes
... ... ... ...... ... ...
......
C colonnes
63
30/10/2009
Exemple
Considérons un tableau NOTES à une dimension
pour mémoriser les notes de 20 élèves d'une
classe dans un devoir:
int NOTE[20] = {15, 14, ... , 16, 11};
0 1 ... 18 19
NOTES 15 14 ... ... 16 11
Pour mémoriser les notes des élèves dans les 10 devoirs, il faut
rassembler plusieurs de ces tableaux uni-dimensionnels dans un
tableau NOTES à deux dimensions :
On obtient alors :
int NOTE[10][20] = {{15,14, ... ,16,11},
{19,14, ... ,9,15},
... ... ...
15 14 ...... 16 11 {10,10, ... ,14,14}};
20 colonnes
64
30/10/2009
Affectation et Affichage
En algo
• Accès en lecture
– Afficher(NOTES [1,3])
{ La note contenue en ligne 1 colonne 3 est affichée à
l’écran}
• Accès en écriture
– NOTES[2,4] 36
– lire(NOTES[2,4])
• { La valeur fournie est enrégistré en ligne 2 colonne 4}
Affectation et Affichage
En C
• Accès en lecture
– printf("%d",NOTES[0][2]);
{ La note contenue en ligne 1 colonne 3 est affichée à
l’écran}
• Accès en écriture
– NOTES[1][3] = 36;
– scanf("%d",&NOTES[1][3]);
• { La valeur fournie est enrégistré en ligne 2 colonne 4}
65
30/10/2009
Exemples
char NOM [20];
char PRENOM [20];
char PHRASE [300];
66
30/10/2009
Espace à réserver
Lors de la déclaration, nous devons indiquer l'espace à
réserver en mémoire pour le stockage de la chaîne.
La représentation interne d'une chaîne de caractères est
terminée par le symbole '\0' . Ainsi, pour un texte de n
caractères, nous devons prévoir n+1 octets.
Malheureusement, le compilateur C ne contrôle pas si
nous avons réservé un octet pour le symbole de fin de
chaîne; l'erreur se fera seulement remarquer lors de
l'exécution du programme ...
67
30/10/2009
Observation
Pour la mémorisation de la chaîne de caractères "BONJOUR
!", C a besoin de neuf (!!) octets.
'a' est un caractère constant, qui a une valeur numérique:
P.ex: 'a' a la valeur 97 dans le code ASCII.
"a" est un tableau de caractères qui contient deux caractères:
la lettre 'a' et le caractère NUL: '\0'
'x' est codé dans un octet
"x" est codé dans deux octets
68
30/10/2009
nom de variable i p
mémoire : … 10 … 124 …
adresse : 124 226
Remarques
Si un pointeur P contient l'adresse d'une variable A, on dit
que
'P pointe sur A'.
Les pointeurs et les noms de variables ont le même rôle: Ils
donnent accès à un emplacement dans la mémoire interne
de l'ordinateur. Il faut quand même bien faire la différence:
Un pointeur est une variable qui peut 'pointer' sur
différentes adresses.
Le nom d'une variable reste toujours lié à la même
adresse.
69
30/10/2009
70
30/10/2009
Remarque
Lors de la déclaration d'un pointeur en C, ce
pointeur est lié explicitement à un type de
données. Ainsi, la variable PtrNum déclarée
comme pointeur sur int ne peut pas recevoir
l'adresse d'une variable d'un autre type que int.
Exemple :
main (){
int n,m;
int *p; /* déclaration d’une variable de type
pointeur sur un entier */
n = 20; m = 10;
p = &n;/*p pointe sur n ou p reçoit l’adresse de n */
*p = m;
return 0;
}
71
30/10/2009
Pointeurs et Tableaux
le nom d'un tableau est un pointeur constant sur
le premier élément du tableau.
En d'autre termes:
&tableau[0]et tableau sont une seule et même
adresse.
En déclarant un tableau A de type int et un
pointeur P sur int,
int A[10]; int *P;
l'instruction: P = A; est équivalente à P = &A[0];
72
30/10/2009
73
30/10/2009
Affectation
On peut attribuer l'adresse d'une chaîne de
caractères constante à un pointeur sur char:
Exemple
char *C;
C = "Chaine de caractères constante";
Nous pouvons lire cette chaîne constante (p.ex: pour
l'afficher), mais il n'est pas recommandé de la modifier,
parce que le résultat d'un programme qui essaie de
modifier une chaîne de caractères constante n'est pas
prévisible en ANSI-C.
74
30/10/2009
Conclusions
Utilisons des tableaux de caractères pour déclarer les
chaînes de caractères que nous voulons modifier.
Utilisons des pointeurs sur char pour manipuler des
chaînes de caractères constantes (dont le contenu ne
change pas).
Utilisons de préférence des pointeurs pour effectuer les
manipulations à l'intérieur des tableaux de caractères.
(voir aussi les remarques ci-dessous).
75
30/10/2009
76
30/10/2009
Définition
Dans la définition d'une fonction, nous indiquons:
le nom de la fonction
le type, le nombre et les noms des paramètres de la
fonction
le type du résultat fourni par la fonction
les données locales à la fonction
les instructions à exécuter
Formalisme
typeRés NomFonct (typeParam1 Param1,
typeParam2 Param2, … )
{
<Déclarations locales>
<instructions>
}
77
30/10/2009
Déclaration
En C, il faut déclarer chaque fonction avant de pouvoir
l'utiliser. La déclaration informe le compilateur du type
des paramètres et du résultat de la fonction.
A l'aide de ces données, le compilateur peut contrôler si
le nombre et le type des paramètres d'une fonction sont
corrects.
Si dans le texte du programme la fonction est définie
avant son premier appel, elle n'a pas besoin d'être
déclarée.
Notion de prototype
La déclaration d'une fonction se fait par un prototype de
la fonction qui indique uniquement le type des données
transmises et reçues par la fonction.
Déclaration : Prototype d'une fonction
<TypeRés> <NomFonct> (<TypePar1>, <TypePar2>, ...);
ou
<TypeRés> <NomFonct> (<TypePar1> <NomPar1>,
<TypePar2> <NomPar2>, ... );
78
30/10/2009
Renvoyer un résultat
Par définition, toutes les fonctions fournissent un résultat
d'un type que nous devons déclarer. Une fonction peut
renvoyer une valeur d'un type simple ou l'adresse d'une
variable ou d'un tableau.
Pour fournir un résultat en quittant une fonction, nous
disposons de la commande return:
L'instruction
return <expression>;
a les effets suivants:
conversion automatique du résultat de l'expression dans
le type de la fonction
renvoi du résultat
terminaison de la fonction
79
30/10/2009
Exemples
La fonction CARRE du type double calcule et
fournit comme résultat le carré d'un réel fourni
comme paramètre.
double CARRE(double X)
{
return X*X;
}
80
30/10/2009
Exemple Carre
int carre (int x) {
return (x*x); Avant appel i=3
} de carre j=?
void exemple () {
int i =3; Appel de i= 3 x= 3
int j ; carre j=?
j = carre (i) ;
printf (%d , j) ;
} Après appel i=3
de carre j=9 9
81
30/10/2009
82