COURS Langage C - 16V17 PDF
COURS Langage C - 16V17 PDF
COURS Langage C - 16V17 PDF
PROGRAMMATION AVANCEE
EN LANGAGE C
Introduction : Ce cours est basé sur celui dispensé par M. Mouslim en 2007
d'après l'ouvrage de Claude Delannoy : Programmer en langage C (Eyrolles)
1
CHAPITE 1 : Présentation du langage C
2
# include <stdio.h>
void main()
{
printf ("bonjour");
}
3
1-2-Caractère de fin de ligne :
Bonjour
Monsieur
4
1-3-Variables et leurs types :
Exemple :
#include <stdio.h>
void main()
{
int n;
n=10;
printf("valeur de n : %d", n); /* %d : est le format d'écriture */
}
Résultat: valeur de n : 10
• int : est une instruction qui permet de déclarer une variable de type entier,
( en C, il existe plusieurs types de variables qu' on verra.)
• L’affectation d’une valeur à une variable se fait à l’aide du signe « = ».
• Les déclarations des types des variables sont obligatoires
et doivent être regroupé au début du programme.
5
Remarque 1:
Il est possible d’initialiser une variable au moment de sa déclaration
Exemple : int n=10 ;
printf("valeur de n : %d", n);
6
Exemple 1 : Exemple 2 :
#include <stdio.h> #include <stdio.h>
void main() void main()
{ {
int n=50; int a, b, c;
printf("somme : %d Dhs", a=20;
n); b=40;
/* %d : format d'écriture */ c=a+b;
} printf("La somme de %d et %d est: %d
Résultat: somme : 50 Dhs ",a, b, c);
/* %d : est le format d'écriture */
}
7
1-4-Le type caractère et le code format « %c »
Exemple :
#include <stdio.h>
void main()
{
char x;
x='e';
printf("Lettre = %c ", x); /* %c : est le format d'écriture */
}
Résultat: Lettre = e
- char : est une instruction qui permet de déclarer une variable de type caractère
Exemple : char x ;
8
1-5-L’instruction « scanf » :
scanf : est une instruction qui permet de lire des informations de type quelconque.
Exemple :
#include <stdio.h>
void main()
{
int n,p;
printf("Donnez deux nombres SVP : ");
scanf("%d %d", &n, &p); /* & : signifie l'adresse de… */
printf("\nLeur somme est : %d ", n+p);
/* %d : est le format d'écriture */
}
Résultat:
Donnez deux nombres SVP : 30 50
Leur somme est : 80
9
scanf("%d %d", &n, &p);
Remarque :
10
-6-L’instruction « getchar » :
L’instruction getchar permet de lire un seul caractère.
Exemple :
# include <stdio.h>
void main()
{
char c;
printf("Donnez SVP un caractère : ");
c=getchar();
printf("Votre caractère est : %c",c);
/* %c : est le format d'écriture */
}
Résultat:
Donnez SVP un caractère : k
Votre caractère est : k
11
1-7-L’instruction « putchar » :
12
1-8-Les commentaires :
Exemple :
/* Programme de d'ecriture
d'un caractere
*/
printf("Votre caractère est : %c",c); /* fonction printf */
/* %c : est le format d'écriture */
13
CHAPITRE 2 : Règles générales d’écriture d’un programme en langage C
2-1-Les identificateurs :
- Le nom d’un identificateur doit commencer par une lettre suivi par des chiffres ou
des lettres.
- Les majuscules et les minuscules sont autorisées mais ne sont pas équivalentes.
14
2-2-Les mots clés :
Les mots clés sont réservés par le langage à un usage bien défini, ils ne peuvent
pas être utilisé comme un identificateur.
15
On peut classer ces mots clés par catégories :
16
CHAPITRE 3 : Les opérateurs et les expressions :
Exemple :
11 / 3 =3 ; -11 / 3 = -3 ; 5. / 2. = 2.5
17
3-2-Les opérateurs relationnels :
On trouve dans le langage C, six opérateurs relationnels :
ET : && OU : || Négation : !
18
3-4-Les opérateurs d’incrémentation et de décrémentation : « ++ , - - »
L’expression « ++i » a pour effet d’incrémenter de 1 la valeur de i, sa valeur est
celle de : après incrémentation.
#include <stdio.h>
void main()
{
int i, n;
i =5;
n =++i - 5; /* incrémente i puis fait i -5 */
printf("i= %d n= %d ",i ,n);
}
Résultat: : i= 6 n= 1
19
Exemple : i++ opérateur de post incrémentation
#include <stdio.h>
void main()
{
int i, n;
i =5;
n =i++ - 5; /* il fait i -5 puis il incrimente le i */
printf("i= %d n= %d ",i ,n);
}
Résultat: i= 6 n= 0
20
CHAPITRE 4 : Les types de base du langage C
21
4-1-Les différents types du langage C :
22
Déclaration du type Taille en octets
unsigned short 2
unsigned short int 2
unsigned int 2
Long 4
long int 4
signed long 4
signed long int 4
unsigned long 4
unsigned long int 4
23
Déclaration du type Taille en octets
float 4
double 8
long double 10
Remarque :
Les déclarations suivantes sont équivalentes :
signed long int a, x ;
signed long a, x ;
long a, x ;
24
4-2-Représentation mémoire des types entiers :
25
Dans le cas signed :
On ne représente que des nombres positifs ou nuls en utilisant tous les bits
disponibles.
26
Les limitations relatives au type entier :
27
CHAPITRE 5 : Les instructions de contrôles
5-1 L’instruction « if » :
Syntaxe :
If (expression logique)
{
Bloc d’instruction _1
}
else
{
Bloc d’instruction_2
}
28
Remarque :
If (expression logique)
{
Bloc d’instruction
}
5-2-Les « if » imbriquées :
On a la possibilité, en langage C, de mettre une instruction if à l’intérieure d’une
autre ce qui constituent des if imbriquées.
Il ne faut pas oublier que chaque else se rapporte toujours au dernier if.
29
5-3-L’instruction swich :
Syntaxe :
30
Exemple :
# include <stdio.h> Résultat :
void main()
{ Donnez un chiffre <= 3 : 2
deux
int n;
printf("Donnez un chiffre <= 3 : ");
scanf("%d",&n);
switch(n)
{
case 0 : {printf(" zero \n"); break;}
case 1 : {printf(" un \n"); break;}
case 2 : {printf(" deux \n"); break;}
case 3 : {printf(" trois \n"); break;}
}
/* break permet la sortie de switch*/
}
31
5-4- Les boucles :
a- La boucle « do…while » :
Syntaxe :
do
{Bloc d’ instructions}
while (expression);
32
Exemple :
# include <stdio.h> Résultat :
void main()
{ Donnez un nombre > 0 : 5
int i, n; 1
printf("Donnez un nombre >0 : 2
"); 3
scanf("%d", &n); 4
i=0; 5
do
{
i=i+1;
printf("%d \n",i);
}
while (i < n);
}
33
b- La boucle « while » :
Syntaxe :
While (expression)
{
(Bloc d’ instructions)
}
34
Exemple:
#include <stdio.h> Résultat :
void main()
{ Donnez un nombre : 48
int n, som; Donnez un nombre : 10
som=0; Donnez un nombre : 50
while(som<100) Somme = 108
{
printf("Donnez un nombre :");
scanf("%d",&n);
som+=n; /*som=som+n;*/
}
printf("Somme = %d ",som);
}
35
c- La boucle « for » :
Syntaxe :
36
Exemple :
# include <stdio.h> Résultat :
void main() Bonjour 1 fois
{ Bonjour 2 fois
int i; Bonjour 3 fois
for (i=1;i<=5;i++) Bonjour 4 fois
{ Bonjour 5 fois
printf("Bonjour ");
printf("%d fois \n",i);
}
}
37
5-5-Les instructions de branchement inconditionnel « break ; continue ; goto
»:
5-5-1-L’instruction « break » :
38
Exemple:
39
Remarque :
5-5-2-L’instruction « continue » :
L’instruction continue permet d’enchaîner l’exécution au début du bloc de la
boucle.
40
Exemple: 1
Résultat :
#include <stdio.h> 1
void main() 2
{ 3
int i; 4
for (i=1;i<=10;i++) 5
{ moins 6
printf("%d \n",i); moins 7
if (i<5) continue; moins 8
printf("moins "); moins 9
} moins 10
}
41
#include <stdio.h> Résultat :
void main()
{ Donnez un nombre > 0 : 2
int n; /* ---------- avec do…while ---------*/ son carré est : 4
do Donnez un nombre > 0 : 0
{ son carré est : 0
printf("Donnez un nombre >0 :");
scanf("%d", &n);
if (n<0)
{
printf(" SVP>0 \n");
continue;
}
printf("son carré est : %d \n",n*n);
}
while(n!=0);
}
42
5-5-3-L’instruction « goto » :
L’instruction « goto » permet d’enchaîner l’exécution à la ligne ou se trouve
l’étiquette.
Syntaxe :
goto étiquette ;
43
Exemple:
44
CHAPITRE 6 : LES TABLEAUX
45
Chaque élément est repéré par un indice précisant sa position au sein de
l’ensemble (tableau).
46
6-1-Exemple de tableau à une seule dimension :
47
C'est Le tableau qui va nous offrir la solution
La déclaration :
int note[20] ;
réserve l’emplacement pour 20 éléments de type int. Chaque élément est repéré
par sa position dans le tableau, nommée indice.
48
int note[20] ;
49
Exemple:
50
6-2-Tableaux à plusieurs dimensions :
Exemple :
51
6-3-initialisation des tableaux à une dimension :
La déclaration int t[5]={10,20,5,0,3} place les valeurs 10,20,5,0,3 dans
chacun des cinq éléments du tableau t.
Exemple:
int t[5]={10,20}
int t[5]={ , ,5, ,3}
52
6-4-initialisation des tableaux à plusieurs dimensions :
ou bien
Cette seconde forme énumère les valeurs du tableau, et c'est dans cet ordre
qu'elles seront rangée en mémoire.
53
Autre exemple : affectation de 1 à tous les éléments du tableau t[3][4]
#include <stdio.h>
#include <stdlib.h>
int main()
{
int i, j ;
int t[3][4];
for (i=0 ; i<3 ; i++)
for (j=0 ; j<4; j++)
t[i][j] = 1 ;
return 0;
}
54
6-5-notions de pointeurs : Les opérateurs * et & :
55
6-5-1-Exemples :
Exemple 1 :
Int *ad; ad |__? _|
/**réserve une variable ad comme
pointeur sur des entiers.
*/
int n; n |__?__| reservé pour n à l'adresse **
n=20 ; n |__20__|
ad=&n; ad |__**__|
56
Exemple 2 :
a=10 ;
b=20 ;
p=&a ;
57
Exemple 3 :
int *ad1, *ad2, *ad3 ;
int a=10,b=20 ;
58
6-5-2-Arithmitique sur les pointeurs :
59
Les opérateurs autorisés sur les pointeurs sont.
60
6-5-3-Utilisation des pointeurs en argument d’une fonction :
61
Exemple :
#include <stdio.h>
void main()
{ int a=10, b=20;
printf("Avant appel a= %d et b= %d \n",a,b);
change(&a,&b);
printf("Après appel a= %d et b= %d \n",a,b);
}
/*---------------- définition de la fonction change--------------*/
change (int *ad1, int *ad2)
{ int x;
x=*ad1;
*ad1=*ad2;
*ad2=x;
}
Résultat : Avant appel a= 10 et b= 20 et Après appel a= 20 et b= 10
62
6-6-Lien entre les pointeurs et les tableaux :
63
Exemple 3 :
Exemple :
Soit la déclaration suivante : int t[2][3] ;
t[0] <=> t <=> &t[0][0] et t[1] <=> &t[1][0]
64
Schéma illustrant cette situation :
t[0] [0] t[0] [1] t[0] [2] t[1] [0] t[1] [1] t[1] [2]
t[0] t[1]
• Ne peut pas être placé dans une variable. ( aussi dans d'autres langages)
65
Exemple :
Supposons connues 2 foctions fct1 et fct2 :
int (*adf)() ; /* déclare la variable adf comme étant un pointeur sur
une fonction restituant un résultat entière.*/
adf=fct1 ; /* il est possible de réaliser des affectations d’adresse
de fonction
adf=fct2 ;
….
( *adf )(…) : /* il est possible de faire appel à une fonction dont
l’adresse est contenu dans la variable
arguments adf. */
Remarque :
66
CHAPITRE 7 : Les chaînes de caractères
• le compilateur pour :
67
Un tableau de caractères est utilisé pour les données Alpha-
Numériques
68
Exemple :
# include <stdio.h>
# include <string.h>
void main()
{
char *adr; /* cette déclaration réserve un
emplacement pour un pointeur adr
sur une suite de caractères */
69
Remarque :
adr="Bonjour" ;
B o n j o u r \0
adr
Résultat : Bonjour
70
7-1-2-Initialisation de tableaux de caractères :
Exemple :
ou bien :
71
7-1-3-initialisation de tableaux de pointeurs sur des chaînes :
Exple :
char *jour[7]={"lundi","mardi","mercredi","jeudi",
"vendredi","samedi","dimanche"} ;
72
• Exemple :
# include <stdio.h>
# include <string.h>
void main()
{ char *jour[7]={"lundi","mardi","mercredi","jeudi",
"vendredi","samedi","dimanche"};
int i;
printf("Donnez un entier entre 1 et 7 SVP:");
scanf("%d",&i);
printf("Le jour N° %d de la semaine est %s \n",i,jour[i-1]);
}
Résultat :
Donnez un entier entre 1 et 7 SVP : 5
Le jour N° 5 de la semaine est vendredi
73
7-2-Les entrées sorties de chaînes :
74
La délimitation de la chaîne lue ne s’effectue pas de la même façon pour
scanf et gets :
• Avec scanf, le code format %s interdit la lecture d’une chaîne
contenant des espaces.
75
Exemple :
# include <stdio.h>
# include <string.h>
void main()
{ char nom[20], prenom[30], ville[30];
printf("Quelle est votre ville : ");
gets(ville);
printf("Donnez votre nom et prénom : ");
scanf("%s %s" ,nom , prenom );
printf("Bonjour cher(e) %s %s \nqui habite a ", nom, prenom);
puts(ville);
}
Résultat :
Quelle est votre ville : Marrakech
Donnez votre nom et prÚnom : SALIM Med Amine
Bonjour cher(e) SALIM Med
qui habite a Marrakech
76
Remarques :
1- Dans le précédant programme on "ne doit pas" fournir le nom en données avec
plus de 19 caractères.
77
7-2-2- La fonction « cgets » :
78
Exemple :
#include<stdio.h>
#include<string.h>
void main()
{ char texte[30];
printf("Donner un texte :");
texte[0]=28;
_cgets(&texte);
printf("Il a %d caracteres,\n le voici : ",texte[1] );
puts(&texte[2]);
}
Résultat :
Donner un texte :ORDINATEUR
Il a 10 caracteres,
le voici : ORDINATEUR
79
7-3 Les fonctions de concaténation de chaînes :
7-3-1 La fonction « strcat » :
Exemple :
#include<stdio.h>
#include<string.h>
void main()
{
char ch1[50]="Bonjour";
char *ch2=" Monsieur";
printf("Avant : %s \n",ch1);
strcat(ch1,ch2);
printf("Après : %s ",ch1);
}
Résultat :
Avant : Bonjour
80
Après : Bonjour Monsieur
strcat(but,source);
81
Exemple :
#include<stdio.h>
#include<string.h>
void main()
{
char ch1[50]="Bonjour";
char *ch2=" Monsieur";
printf ("Avant : %s \n",ch1);
strncat (ch1,ch2,6);
printf("Apres : %s \n",ch1);
}
Résultat :
Avant : Bonjour
Apres : Bonjour Monsi
82
7-3-3 La fonction « strlen » :
Syntaxe :
Strlen (ch)
Exemple :
N=strlen(ch1) ;
83
7-4 Les fonctions de comparaison de chaîne :
Il est possible de comparer deux chaînes en utilisant l’ordre des caractères définis
par le code ASCII.
Strcmp(ch1,ch2) ;
La fonction « strcmp » compare deux chaîne dont on lui fournie l’adresse et elle
fournie une valeur entière définie comme étant :
- Positive : si ch1 > ch2
- Nulle : si ch1 = ch2
- Négative : si ch1 < ch2
84
7-4-2 La fonction « strncmp » :
Exemple :
strncmp("bonjour”,”bon”,4) est positif
strncmp("bonjour”,"bon”,2) vaut zéro
85
7-5 Les fonctions de copie de chaînes :
7-5-1- La fonction « strcpy » :
Syntaxe :
strcpy(destin,source) ;
86
7-6 Les fonctions de recherche dans une chaîne :
En trouve en langage C des fonctions classiques de recherche de l’occurrence
dans une chaîne d’un caractère ou d’une autre chaîne.
7-6-1 La fonction « strchr » :
Syntaxe :
strchr(chaîne,caractère) ;
« strchr » recherche dans chaîne la première position où apparaît le caractère.
La fonction strrchr réalise le même traitement que strchr, mais explorant la chaîne
concernée à partir de la fin.
87
7-6-3 La fonction « strstr » :
Syntaxe :
strstr(chaîne,sous chaîne) ;
88
7-7 Les fonctions de conversion :
7-7-1 Conversion d’une chaîne en une valeur numérique :
Remarque :
89
7-7-2 Exemple :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
char ch[40];
int n;
do
{
printf("Donnez SVP une chaîne : \n");
gets(ch);
printf("int : %d \n",n=atoi(ch));
printf("double: %e \n",atof(ch));
}
while(n);
90
}
Résultat :
91
7-7-3 Conversion d’une valeur numérique en une chaîne :
92
7-7-4 Exemple :
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void main()
{
char ch[40];
int n,b;
do
{
printf("Donnez SVP un nombre et un base : \n");
scanf("%d %d",&n,&b);
printf("%s \n",itoa(n,ch,b));
}
while(n);
}
93
Résultat :
94
CHAPITRE 8 : Les structures et les unions
Nous avons déjà vu que le tableau permet de désigner sous un seul nom un
ensemble de valeurs de même type, chacune d’entre elles repérée par un indice.
95
8-1- Exemple de déclarations de structure :
struct enreg
{
int numero ;
int qte ;
float prix ;
};
Par exemple :
struct enreg art1 ;
Ou bien struct enreg art1, art2 ;
96
Il est également possible de regrouper la définition du modèle de structure et
la déclaration du type de variable dans une seule instruction comme dans l’exemple
suivant :
Exemple :
struct enreg
{
int numero ;
int qte ;
int prix ;
} art1, art2 ;
97
8-2 Utilisation d’une structure :
8-2-1- Utilisation des champs d’une structure :
Exemple :
Printf("%e ",art1.prix); /* affiche (%e), lla valeur du champ prix de la structure art1 */
scanf("%e ",&art2.prix); /* lit (%e), une valeur du champ prix de la structure art2 */
98
8-2-2 Utilisation globale d’une structure :
Il est possible d’affecter à une structure le contenu d’une structure définie à
partir du même modèle.
Exemple :
Ceci est possible lorsque art1 et art2 sont définie selon le même modèle.
Remarque : l’affectation globale n’est pas possible entre tableaux mais elle l’est,
par contre, entre structures.
99
8-2-3 Initialisation de structures :
Exemple :
100
8-3-1- Exemples d’utilisation de « type def » :
la declaration : typedef int entier ; Signifie que entier est synonyme à int
De même : typedef int * ptr signifie que ptr est synonyme de int *.
101
8-3-2 Application aux structures:
102
8-4 Exemples de structures:
8-4-1- Structures comportant des tableaux:
Soit la déclaration suivante :
struct personne
{
char nom[30] ;
char prenom[50] ;
float heures[31] ;
} employe, agent ;
103
8-4-2 Tableaux des structures:
Exemple :
struct point
{
char nom ;
int x ;
int y ;
};
Cet structure point représente un point d’un plan, qui est défini par son nom
(caractère) et ses deux coordonnées.
104
struct point courbe[50] ;
Notez bien que pointe st un nom de modèle de structure, tandis que courbe
représente effectivement un tableau de 50 éléments du type point.
105
struct point
{
char nom ;
int x ;
int y ;
};
struct point courbe[50] ;
struct point courbe[50]= { {'A', 10, 25}, {'M', 12, 28},, {'P', 18,2} };
106
8-4-3 Structures comportant d’autres structures :
Exemple :
struct date
{
int jour ;
int mois ;
int annee ;
};
struct personne
{
char nom[30] ;
char prenom[50] ;
float heures[31] ;
struct date date_embauche ;
struct date date_poste ;
107
} employe, agent ;
108
Remarquons que la deuxième déclaration
struct personne
{
char nom[30] ;
char prenom[50] ;
float heures[31] ;
struct date date_embauche ;
struct date date_poste ;
} employe, agent ;
fait intervenir un modèle de structure date précédemment définie.
La notation : employe.date_embauche.annee
représente l’année d’embauche correspondant à la structure employe.
Il s’agit d’une valeur de type int.
109
employe.heures[4]
désigne le cinquième élément du tableau heures de la structure employe.
Il s’agit d’un élément de type float.
employe.nom[0] 1er caractère du champ nom de la structure employe.
&agent.heures[4] 5ème élément du tableau heures de la structure agent .
agent .nom champ nom de la structure agent (et aussi adresse de ce tableau)
110
8-5 Les champs de bits :
Les ordinateurs ou processeurs modernes utilisent des données de 8, 16, 32
ou 64 bits. La nomenclature actuelle est comme suit :
• donnée de 8 bits : « byte » ou «octet»;
• donnée de 16 bits : « word » ou « mot » ;
• donnée de 32 bits : « dword » ou « double mot;
• donnée de 64 bits : « qword » ou « quadruple mot ».
Mais on peut définir au sein des structures des variables occupant un nombre
défini de bits de 1 à 16. Cela peut être utile dans les cas suivants :
-a) Pour compacter l’information :
un nombre entier compris entre 0 et 15 sera rangé sur 4 bits au lieu de 16
bits. (il faut utiliser convenablement les bits restants).
-b) Pour utiliser un mot de 16 bits pour représenter plusieurs informations.
111
Exemple :
struct etat
{
unsigned prêt :1; Avec ces déclarations la notation
unsigned ok :1;
int donnee1 :5; mot.donnee1
int :3;
unsigned ok2 :1; désigne un entier signed
int donnee2 :4;
}; qui peut prendre des valeurs comprise
struct etat mot;
entre -16 et 15.
La variable mot peut être schématisée par :
112
les bits en Noir ne sont pas utilisés, pas de nom attribué lors de la description.
Les seuls types susceptibles de figurer dans un mot de champs de bits est int
et unsigned int.
113
8-6 Les unions :
La déclaration :
union essai
{
long n;
float x;
}u;
114
La syntaxe de la description d’une union est analogue à celle d’une structure.
Exemple :
#include<stdio.h>
main()
{ Résultat :
union essai
{ Donnez SVP un nombre réel: 7.123E4
long n; En entier cela fait : 71230
float x;
} u;
printf("Donnez SVP un nombre
réel: \n");
scanf("%f",&u.x);
printf("En entier cela fait : %ld",u.n);
}
115
CHAPITRE 9 : Les Fichiers
9-1- Introduction :
116
9-2 L’accès séquentiel :
9-2-1-Création séquentielle d’un fichier :
Exemple :
117
---> FILE *sortie ; :signifie que sortie est un pointeur sur un objet de type FILE,
structure définie dans le fichier stdio.h (par une instruction
typedef, ce qui explique l’absence du mot struct).
---> sortie=fopen(nomfich,"wb");
- fopen est une fonction d’ouverture, elle possède deux arguments :
o Le nom du fichier nomfich
o Une indication sous forme de chaîne :
« w » : comme write pour ouvrir le fichier nomfich en écriture
« b » : signifie que les informations seront stockées en binaire.
- fwrite (&n, sizeof(int), 1, sortie) : La fonction fwrite possède quatre arguments :
o L’adresse de l’information à écrire «ici &n ».
o La taille d’un bloc en octet : «ici sizeof(int)».
o Le nombre de bloc de cette taille: «ici 1 ».
o Le nom du fichier : «ici sortie ».
118
---> fclose(sortie); : cette instruction réalise la fermeture du fichier de nom logique
de « sortie ».
119
9-2-2 Lecture séquentiel d’un fichier :
Exemple :
#include <stdio.h>
main()
{
char nomfich[21] ;
int n ;
FILE * entree ;
printf ("nom du fichier à lister : ") ;
scanf ("%20s", nomfich) ;
entree = fopen (nomfich, "r") ;
while ( fread (&n, sizeof(int), 1, entree), ! feof(entree) )
printf ("\n%d", n) ;
fclose (entree) ;
}
120
- fopen(nomfich,"rb"); : le “r” désigne que le fichier est ouvert en lecture.
121
}
while ( !feof(entree) ) ;
Pour fwrite et fread ,il est préférable d’utiliser l’opérateur sizeof pour
déterminer avec certitude la taille des blocs correspondants.
123
a)- création séquentielle d’un fichier :
Exemple :
#include<stdio.h> do
main() {
{ printf("Donnez un entier :");
char nomfich[21]; scanf("%d",&n);
int n,ret, etat; if(n!=0)
FILE *sortie; {
printf("nom du fichier à créer: "); ret=fwrite(&n,sizeof(int),1,sortie);
scanf("%20s",nomfich); if(!ret) printf("ERREUR
sortie=fopen(nomfich,"wb"); d'ouverture de fichier");
if(!sortie) }
{ }
printf("ERREUR d'ouverture de while(n && ret);
fichier"); fclose(sortie);
exit(etat); }
124
}
#include<stdio.h> if(!entree)
main() { printf("ERREUR d'ouverture de fichier");
{ system("PAUSE");
char nomfich[21]; exit(etat);
int n, etat; exit(etat);
FILE *entree; }
printf("nom du fichier à lire: "); while(fread(&n, sizeof(int), 1,entree),
scanf("%20s",nomfich); !feof(entree)) printf("\n %d",n);
entree=fopen(nomfich,"rb"); fclose(entree);
system(“PAUSE”);
}
125
126
Remarque : En MSDOS les fichiers sont une simple suite d’octets
127
Il est également possible d’agir directement sur ce pointeur de fichier à l’aide
de la fonction fseek (chercher en français).
128
9-3-1- L’accès direct en lecture sur un fichier existant :
On peut accéder à n’importe quel entier du fichier crée précédemment :
#include<stdio.h>
main() while(num!=0)
{ {
char nomfich[21]; printf("No de l'entier à lire :");
int n, etat; scanf("%ld",&num);
long num; fseek(entree,sizeof(int)*(num-1),0);
FILE *entree; fread(&n,sizeof(int),1,entree);
printf("Nom du fichier à lister: "); printf("valeur : %d \n",n);
scanf("%20s",nomfich); }
entree=fopen(nomfich,"rb"); fclose(entree);
if(!entree) }
{
printf("ERREUR d'ouverture");
exit(etat);
129
}
130
o SEEK_END ou 2 : le second argument désigne un déplacement depuis la
fin du fichier.
131
9-3-2 Les possibilités de l’accès directs :
132
scanf ("%20s", nomfich) ; fclose (entree) ;
entree = fopen (nomfich,"r") ; }
Remarque :
• Rappelons qu'en C dès que vous écrivez le Nième octet d’un fichier, il y a
automatiquement réservation de la place de tous les octets précédents, leur
contenu étant aléatoire.
133
Le positionnement dans le fichier se fait sur un octet de rang donné et non
sur un bloc ou un enregistrement.
134
b)- Tentative de positionnement hors fichier :
136
9-5 Les noms des fichiers associés à des périphériques :
Exemple :
Sous DOS la fin de ligne est représentée par un couple de deux caractères :
De plus la fin de fichier est caractérisée par CTRL/Z (code ASCII 26).
138
Remarque :
139
============ Fin pour aujourd'hui ================================
140
9.7 L’accès séquentiel en niveau 1
Exemple
# include <stdio.h>
# include <fcntl.h>
# include <sys/stat.h>
main ( )
{char nomfich [21];
Int n;
Int nfich;
Print f (“Donnez le nom du fichier à créer:”);
Scanf(“ %20s”, nomfich) ;
nfich =open (nomfich, O_CREAT | O_BINARY|O_WRONLY,
S_IWRITE) ;
141
Do
{print f (“donnez un entire: “) ;
Scanf(« %d »,&n) ;
If (n) write (nfich, &n, 2);
}
While (n);
Close (nfich);
}
142
La fonction open fournit en retour un numéro de fichier
O_CREAT spécifie que si le fichier n’existe pas, il faudra le créer.
O_WRONLY demande une ouverture en écriture seulement
S_WRITE sert à préciser les permissions
O-BINARY correspond à un mode non translaté (binaire)
-
Les permissions sont spécifiées qu’en cas de création d’un nouveau fichier,
c'est-à-dire les opérations que le fichier pourra subir par la suite :
S-IWRITE : permission d’écriture. Notez que sous DOS elle entraîne aussi la
permission de lecture ce qui n’est pas le cas dans
l’environnement UNIX.
S-IREAD : permission de lecture. Un fichier disposant de cette permission ne
peut plus être effacé par exemple par la commande ERASE.
143
La combinaison utilisée dans ce programme est équivalente au mode wb du niveau
2.
Pour l’instruction write on a 3 arguments :
• numéro de fichier
• adresse de début de l’information à écrire dans le fichier
• nombre d’octets à transférer
la notion de bloc (nombre d’enregistrements) en est totalement absente.
Exemple
# include <stdio.h>
# include <fcnt.h>
main ( )
{char nomfich [21] ;
int n ;
144
Int ret ;
Int nfich ;
Printf(« non du fichier à lister ») ;
Scanf(“ %20s “,nomfich) ;
nfich = open (nomfich ,O_BINARY|O_RDONLY);
while(!eof(nfich))
{
read (nfich, &n, 2);
print f ( “%d\n”, n);
}
close (nfich);
}
Open réalise une ouverture qui correspond à rb au niveau 2 utilisé avec fopen.
145
9.7 L’accès direct en niveau 1
Exemple
# include <stdio.h>
# include <fcntl.h>
# include <io.h>
main ( )
{char nomfich [21];
int n;
long num;
int nfich;
print f(“nom du fichier à consulter:”);
scanf(« %20s », nomfich) ;
nfich = open (nomfich, O_BINARY | O_RDONLY) ;
while (printf(« numéro de l’entier recherché : »)
146
scanf(« %ld », &num),num)
{lseek(nfich, sizeof(int)* (num-1),0) ;
read (nfich,&n,sizeof(int)) ;
printf (« valeur = %d \ n » , n) ;
}
while (num) ;
close (nfich) ;
}
147
.
.
taille = file length (nfich) ;
taille est exprimé en octets.
148
CHAPITRE 10 : Les fonctions
Comme tous les langages C permet de découper un programme en plusieurs
parties nommées souvent « module ».
Remarque :
C autorise la compilation séparée des modules.
149
10-1-Notion de fonction en C :
150
a)- Exemple :
#include<stdio.h>
main()
{
optimist() ;
}
optimist()
{
printf(“ il fait beau”);
}
151
b)- Arguments d’une fonction :
Exemple :
#include <stdio.h>
main()
{
ecris(int n);
int a=10, b=20 ;
ecris(a) ;
ecris(b) ;
ecris(a+b) ;
}
ecris(int n)
{
printf("valeur : %d \n",n) ;
}
152
La variable « n » n’a aucune signification sauf au sein de la fonction
ecris(int n)
{
printf("valeur : %d \n"n) ;
}
et elle n’a aucun rapport avec une éventuelle variable de même nom qui peut être
définie en dehors de la fonction. En dit que « n » est un argument muet.
153
10-2 Fonctions fournissant un résultat :
a)- Exemple : #include<stdio.h>
main()
{
double som();
double a, b, c, d, x, y ;
a =1 ; b =2 ; c =3 ; d =4 ;
x=som(a,b)+5 ;
printf(" x= %e \n" ,x) ;
y=3*som(c,d);
printf(" y= %e \n" ,y) ;
}
double som(double u, double v) {
double s ;
s= u+v ;
return(s);
}
154
double som(): indique le type de résultat que fournira la fonction.
return(s) : c’est l’instruction qui spécifie le résultat qui sera fournit par la fonction
lors de son appelle.
155
b)- Rôle de prototype :
Exemple :
156
c)- Le type void :
Il sert à spécifier une fonction qui ne retourne pas de résultat. Il peut être
employé aussi bien dans l’entête de la fonction que dans le prototype.
Exemple :
void optimist()
void ecris(int n)
157
10-4 Les arguments transmis par valeur :
Exemple :
#include<stdio.h>
main()
{
echange(int a, int b) ;
int n=10, p=20 ;
printf(“ Avant appel : %d %d \n”,n,p) ;
echange(n,p) ;
printf(“ Après appel : %d %d \n”,n,p) ;
}
158
echange(int a, int b)
{
int temp ;
printf(Debut echange : %d %d \n”,a,b) ;
temp=a;
a=b;
b=temp;
printf(“ Fin échange : %d %d \n”,a,b) ;
}
Résultat :
Avant appel : 10 20
Début échange : 10 20
Fin échange : 20 10
Après appel : 10 20
159
Ce mode de transmission interdit à une fonction de produire une ou plusieurs
valeurs en retour autres que celles de la fonction elle-même.
160
Exemple :
#include<stdio.h>
int i;
main()
optimiste() ;
{
for(i=1;i<=3;i++)
optimiste();
}
optimiste()
{
printf("Il fait beau %d fois \n",i);
}
Résultat :
Il fait beau 1 fois
Il fait beau 2 fois
161
Il fait beau 3 fois
int i;
main()
« i » a été déclaré en dehors de la fonction main, il est alors connu de toutes les
fonctions qui seront définies par la suite au sein de la même source.
Les variables globales ne sont connues que dans la partie source suivant
leurs déclarations, on dit que leur portée ou bien espace de validité sont limité à la
partie de source qui suit leur déclaration.
162
Exemple :
main()
{
fonct1( ……) ;
fonct2( ……) ;
………
}
int n ;
float x ;
fonct1( ……) /* Les variables n et x sont accessible fonctions */
{ /* fonct1 et fonct2 mais pas au programme */
……… /* principal. */
}
focnt2(……)
{
………
}
163
b)- Initialisation:
Les variables globales sont initialisées à zéro avant le début d’exécution du
programme, sauf si on introduit une valeur initiale au moment de la déclaration.
164
a)- Portée des variables locales :
Exemple :
int n ;
main()
{
int p ;
…
}
foct1()
{
int p ;
int n ;
…
}
la variable p de main() n’a aucun rapport avec p de foct1 de même la variable n de
foct1 n’a aucun rapport avec la variable globale n.
165
Les variables locales ne sont connues qu’à l’intérieur de la fonction où elles
sont déclarées, elles n’ont aucun lien avec des variables globales de même nom ou
avec d’autre variables locales pour d’autres fonctions.
Dans l’exemple précédent la variable p de main n’a aucun rapport avec p de
foct1 et la variable n de foct1 est différente de la variable globale n.
166
Exemple :
#include<stdio.h>
main()
{
void fct();
int n;
for(n=1;n<=5;n++)
fct();
}
void fct()
{
static int i;
i++;
printf("Appel numéro : %d \n",i);
}
167
Résultat:
Appel numéro : 1
Appel numéro : 2
Appel numéro : 3
Appel numéro : 4
Appel numéro : 5
Remarque :
Les variables locales de classe statique sont par défaut initialisées à zéro.
168
10-8 La récursivité :
La récursivité est la caractéristique des fonctions capables de s’appeler elles-
mêmes d’une façon répétitive jusqu’à ce que soit vérifié une condition donnée.
Exemple : Calcule de n !
#include<stdio.h>
main()
{
int n;
long int fac(int n);
printf("Donnez la valeur de n : \n");
scanf("%d",&n);
printf("N! = %ld \n",fac(n));
}
169
long int fac(int n)
{
if(n>1) return(fac(n-1)*n);
else
return(1);
}
Résultat:
Donnez la valeur de n : 5
N ! = 120
170
CHAPITRE 11 : La gestion dynamique
171
11-1- Les outils de base de la gestion dynamique :
a)- La fonction « malloc » :
Exemple :
#include<stdio.h>
#include<malloc.h>
... ... malloc(50): réserve un emplacement de 50
char *adr; octets dans le Tas et fournit l’adresse en retour
... ... qui est placé dans le pointeur « adr ».
adr = malloc(50);
... ...
for(i=0; i<50; i++)
*(adr+i)=’x’;
... ...
172
b)- La fonction « free » :
Exemple :
#include<stdio.h>
#include<malloc.h>
... ...
char *adr;
... ...
adr = malloc(50);
... ...
free(adr) ;
……
173
c)- La fonction « calloc » :
Syntaxe :
calloc(nbr_bloc, taille) ;
La fonction calloc réserve un certain nombre de blocs consécutifs avec une taille
en octet pour chaque bloc.
Remarque :
- La taille et le nombre de bloc sont tout les deux de type unsigned int .
- calloc : remet à zéro chacun des octets de la réservé.
174
d)- La fonction « realloc » :
Syntaxe :
realloc(pointeur, taille) ;
175
11- 2 structure transmise en argument :
Exemple 1 Structure transmise par valeur:
#include<stdio.h> printf("\n Avant appel fct : %d %e ",x.a,x.b);
struct enreg fct(x);
{ printf("\n Retour dans main : %d %e", x.a,
int a; x.b);
float b; }
};
void main() void fct(struct enreg s)
{ {
struct enreg x; s.a = 11;
void fct (struct enreg y); s.b = 13,5;
x.a= 10; printf(" \n Dans fct : %d %e ",s.a,s.b);
x.b= 12.5; }
176
Résultats :
• Les valeurs de x ne sont pas modifiées par la fonction fct qui travaille sur s.
• La structure est transmise par valeur.
177
Exemple 2: Transmission de l’adresse d’une structure : L’opérateur (->)
#include<stdio.h> printf("\nAvant appel fct : %d , %e", x.a, x.b);
struct enreg fct(&x);
{ printf("\nRetour dans main : %d, %e", x.a, x.b);
int a; }
float b;
}; void fct(struct enreg *s)
{
void main() s->a= 11;
{ s->b= 13.5;
struct enreg x; printf(" \n Dans fct : %d , %e ",s->a,s->b);
void fct (struct enreg *y); }
x.a= 10;
x.b= 12.5;
178
L’opérateur -> permet d’accéder aux différents champs d’une structure à
partir de son adresse de début.
Résultats :
Avant appel fct : 10 1.250000e+001
Dans fct : 11 1.3500000e+001
Retour dans main : 11 1.3500000e+001
179
11- 3 Création d’une liste chaînée :
180
a) Appliquons cela à des éléments de b) adaptons notre structure de la
type point, manière suivante :
Dans b), nous avons utilisé dans la description du modèle element, un pointeur
sur ce même modèle element .
181
Ensuite, nous pouvons ensuite utiliser «typedef » et donner le nom s_point à notre
nouveau type.
182
CHAPITRE 12 : Les pré processeurs
12-1- Définition :
Un pré processeur est un programme qui est exécuté automatiquement avant
la compilation et qui transforme un fichier source à partir d’un nombre de directives.
Ces dernières sont introduites par un nom précis commençant par le caractère « #
».
Les diverses possibilités offertes par le pré processeur sont :
- L’incorporation de fichier source (directive #include).
- La définition de symboles et de macros (directive #define).
- La compilation conditionnelle.
12-2 La directive « #include » :
183
La directive include permet d’incorporer avant la compilation le texte figurant dans
un fichier qui fait porter du langage C ou bien un fichier du programmeur.
Syntaxe :
#include <nom de fichier> ou bien #include "nom de fichier"
La recherche du fichier se fait d’abord dans le répertoire courant puis dans le cas
d’échec dans le répertoire (Include directory)
12-3 La directive « #define » :
La directive #define offre deux possibilités :
a)- Définition de symboles :
Exemple 1 :
#define NBMAX 10
Cette directive demande d’attribuer au symbole nbmax la valeur 10, et ceci à
chaque fois que NBMAX apparaît dans le fichier source.
Exemple 2 :
#define ENTIER int
184
Cette directive placé au début du programme permettra de remplacer le mot entier
par int.
ENTIER a,b ; --> serait remplacées par int a, b ;
ENTIER *p ; serait remplacées par int *p ;
Le pré processeur remplacera tout les textes de la forme Carre(x) par x*x.
Exemple :
185
Carre(z) --> z*z
Carre(valeur) --> valeur* valeur
Carre(12) --> 12*12
Exemple :
Pour qu’un symbole soit définie il doit faire l’objet d’une directive #define.
187
b)- Incorporation liée à la valeur d’une expression :
Syntaxe :
#if condition
………
………
#else
………
………
#endif
Exemple :
#define code 1
………
………
#if code == 1
Bloc instructions-1
188
#endif
#if code == 2
Bloc instructions-2
#endif
Ceci permet d’incorporer l’une des deux parties du texte suivant la valeur de la
condition indiquée.
189
Annexe
Conversions implicites de type dans le calcul d’expressions
les opérateurs arithmétiques ne sont définis que pour des opérandes sont de
même type.
Pour des expressions "mixtes" avec des opérandes de types différents, une
conversion d’ajustement de type .
Elle se fait selon une hiérarchie qui respecte la valeur initiale (l’intégrité des
données)
int -> long -> float -> double -> long double
190
E xemple : Calcul de n * x + p pour n et p de type int, et x de type float :
c-) n * x + p : n*x est de type float mais p de type int : même conversion
qu'en a-) et b-) : le résultat final sera de type float.
Remarque :
191
Exemple :
192
Promotion Numérique
Dans toute expression, une valeur de type short ou char est d'abord
convertie en int.
Exemple :
Soient p1, p2 et p3 de type short et x de type float , calculer p1 * p2 + p3 * x
p1 * p2 + p3 * x
| | | |
int int int | promotions numériques short -> int
|____ * ___ | | |
| float | conversion d’ajustement detype
int |___ * ___ |
| |
float float conversion d’ajustement de type
|_________ + ________|
|
float
193
Remarque :
2- le type char
194
Exemple :
c1 + 1 c1 + n
| | | |
int | promotion numérique int | promotion numérique
|___ + ___| char -> int |___ + ___| pour c1
| |
int int
c1 - c2
| |
int int promotion numérique
|____ ____ | char -> int
|
int
195
Rappel :
int Conteur = 5;
float Miles = 5.6;
/* Doubles pour les GRANDS Flottants
double atomes = 2500000.375;
char Letter = 'x';
Modificateurs
short
long
signed
unsigned
196
Type Octets bits Range
short int 2 16 -32,768 -> +32,767 (16kb)
unsigned short int 2 16 0 -> +65,535 (32Kb)
unsigned int 4 16 0 -> +4,294,967,295 ( 4Gb)
int 4 32 -2,147,483,648 -> +2,147,483,647( 2Gb)
long int 4 32 -2,147,483,648 -> +2,147,483,647 ( 2Gb)
signed char 1 8 -128 -> +127
unsigned char 1 8 0 -> +255
float 4 32
double 8 64
long double 12 96
Valeurs valable sur les PCs. Pour les autres, utiliser sizeof .
197
CHAPITRE 10 : la Compilation Séparée
jusqu'à présent, on a travaillé avec toutes nos fonctions dans un seul fichier
appelé main.c, mais Il est possible de mettre du code C dans plusieurs fichiers.
Séparer le code est un bon moyen d'avoir des parties de codes réutilisables,
on disposera donc de fonctions qui peuvent servir dans plusieurs programmes.
198
Ici notre projet tp1 est constitué d'un seul fichier main.c
199
200