Sunteți pe pagina 1din 200

UNIVERSITE CADI AYYAD

FACULTE DES SCIENCES


DEPARTEMENT D’INFORMATIQUE
MARRAKECH

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

1-1-Structure générale d’un programme en C :


La structure d’un programme en C est sous la forme :
# include <stdio.h>
void main()
{
printf ("bonjour");
}
Résultat:
bonjour

2
# include <stdio.h>
void main()
{
printf ("bonjour");
}

la ligne void main() : est une sorte d’entête.


le programme principal est écrit à sa suite, il est délimité par 2 accolades {…}.

- En langage C toute instruction doit être suivi d’un « ; ».

- Le langage C fait la distinction entre les majuscules et les minuscules.

3
1-2-Caractère de fin de ligne :

La notation "\n" provoque un passage à la ligne suivante.


Exemple :
#include <stdio.h>
void main()
{
printf("Bonjour \n");
printf("Monsieur ");
}
Résultat:

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);

• L’instruction printf permet d’afficher sur l’écran une ou plusieurs valeurs


selon un format qui est toujours précisé entre "…".
• La présence du caractère % signifie que ce qui arrive à sa suite est non plus
du texte à afficher tel quel mais un code de format.

• Le code de format %d précise qu’il faut considérer la valeur reçue comme un


entier.
Remarque 2 :
Tout ce qui n’est pas "code de format" est affiché tel quel est.

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 */
}

Résultat: La somme de 20 et 40 est: 60

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 ;

- Le %c est le format d’écriture d’un caractère.

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);

- L’instruction scanf comme printf possède en argument un format exprimé sous


forme de chaîne de caractères.

- L’opérateur & signifie adresse de…

Remarque :

Si on oublie le caractère & qui précède le nom des variables de scanf, le


compilateur ne détectera aucune erreur mais les informations lues au clavier
seront rangées dans des emplacements aléatoires.

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 » :

L’instruction putchar permet d’afficher un seul caractère.


Exemple :
#include <stdio.h>
void main()
{
char x;
x='e';
printf("La lettre est : ");
putchar(x);
}

Résultat: La lettre est : e

12
1-8-Les commentaires :

Comme tous les langages, le langage C autorise l’insertion des commentaires


dans un programme.

Un commentaire doit être limité entre /*………et………*/.

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 :

Les identificateurs servent à désigner les différents "objets" manipulés par le


programme : variables, fonction, …

- 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.

Liste de 32 mots clés du langage C : .

auto const double float int short struct unsigned


break continue else for long signed switch void
case default enum goto register sizeof typedef volatile
char do extern if return static union while

15
On peut classer ces mots clés par catégories :

• les spécificateurs de stockage : auto, register, static, extern, typedef

• les spécificateurs de type : char, double, enum, float, int, long,


short, signed, struct, union, unsigned,
void
• les qualificateurs de type : const, volatile

• les instructions de contrôle : break, case, continue, default, do, else,


for, goto, if, switch, while

• divers : return, sizeof

16
CHAPITRE 3 : Les opérateurs et les expressions :

3-1-Les opérateurs arithmétiques :

Le langage C dispose de cinq opérateurs arithmétiques :


+, -, *, /, % / : Quotient

Exemple :

11 / 3 =3 ; -11 / 3 = -3 ; 5. / 2. = 2.5

11 % 3 =2 ; -11 % 3 = -2 % : Reste de la division entière (modulo)

17
3-2-Les opérateurs relationnels :
On trouve dans le langage C, six opérateurs relationnels :

<, <=, >, >=, ==, != avec == : Egalité , ! = : Différent de

3-3-Les opérateurs logiques :


On trouve dans le langage C les trois opérateurs logiques :

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.

Exemple : ++i : opérateur de pré -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

- L’opérateur « -- » joue de la même façon que « ++ » le rôle de la décrémentation.

20
CHAPITRE 4 : Les types de base du langage C

La déclaration des variables en C est obligatoire.

Les types de bases dans le langage C se répartissent en trois grandes


classes en fonction de la nature des informations qui permettent de
présenter :

o Nombres entiers (mot clé : int)

o Nombres flottants (mot clé : float ou double)

o Caractères (mot clé : char)

21
4-1-Les différents types du langage C :

Déclaration du type Taille en octets


signed char 1
char 1
unsigned char 1
short 2
short int 2
int 2
signed short int 2
signed int 2
signed short 2

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 :

en C nous allons voir quatre types d’entiers différents caractérisé par :

- Leur taille <=32 bits :

16 bits pour short, short int ou int


32 bits pour long, ou long int

- La présence ou l’absence de signe : « signed ou unsigned »

25
Dans le cas signed :

• le signe est représenté par le bit de poids fort

• la valeur absolue du nombre est codée sur les bits restants 15 ou 31

• Si le nombre est négatif sa valeur absolue est codée suivant la méthode du


complément à 2

Dans cas unsigned :

On ne représente que des nombres positifs ou nuls en utilisant tous les bits
disponibles.

26
Les limitations relatives au type entier :

Type Taille en octets Domaine


unsigned 2 0 à 65535

int 2 -32768 à 32767

unsigned long 4 0 à 4294967295

long 4 -2147483648 à 2147483647

%ld est le code format correspondant au type long.

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 :

else : est facultatif, l’instruction if peut être sous la forme :

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 :

swich (expression ) /* expression entière */


{
case constante_1 : {suite d’instructions_1}
case constante_2 : {suite d’instructions_2}
… …
… …
case constante_n : { suite d’instructions_ n}
default : { suite d’instructions}
}

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 :

for ([expression_1] ;[ expression_2] ;[ expression_3])


{
(Bloc d’instructions)
}

Les crochets […] signifient que leurs contenu est facultatif.

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 » :

• vue dans le bloc régie par une instruction switch.

• Autorisée également dans une boucle.

• Stoppe le déroulement de la boucle et passe à l’instruction qui suit cette


boucle.

38
Exemple:

# include <stdio.h> Résultat :


void main()
{ Donnez la valeur de n: 10
int i,s,n; Donnez la valeur de n: 2
for (i=1,s=0;i<=10;i++) Donnez la valeur de n: 0
{ Somme = 12
printf("Donnez la valeur de n: ");
scanf("%d",&n);
if (n==0) break;
s=s+n;
}
printf("%d \n",s);
}

39
Remarque :

En cas de boucles imbriquées « break » fait sortir de la boucle la plus intérieure.

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:

#include <stdio.h> Résultat :


void main()
{ Debut tour 1
int i; Bonjour
for(i=1;i<=10;i++) Fin tour 1
{ Debut tour 2
printf("Debut tour %d \n",i); Bonjour
printf("Bonjour \n"); Fin tour 2
if (i==3) goto sortie; Debut tour 3
printf("Fin tour %d \n",i); Bonjour
} Fin boucle
sortie: printf("Fin boucle \n");
}

44
CHAPITRE 6 : LES TABLEAUX

Comme tous les langages, C permet d’utiliser les tableaux.

Un tableau : ensemble d’éléments de même type, désignés par un


identificateur unique.

45
Chaque élément est repéré par un indice précisant sa position au sein de
l’ensemble (tableau).

● La taille ou dimension d’un tableau est le nombre


d’éléments du tableau.

● Les éléments d’un tableau sont indicés de 0 à dimension - 1.

● Déclaration de tableau : type NomTableau[dimension]

● !!! Aucune vérification n’est faite par le compilateur sur la valeur de i,


qui doit être compris entre 0 et dimension - 1.

● L’opérateur [ ] permet de désigner un élément du tableau :

Exemple : t[i] désigne le ième élément du Tableau t.

46
6-1-Exemple de tableau à une seule dimension :

Soit à déterminer, à partir de 20 notes d’élèves (fournies en données),


combien d’élèves ont obtenu une note supérieures à la moyenne de la classe.

Pour la moyenne de la classe, on cumule (somme) ces notes dans une


variable, au fur et à mesure de leur lecture, puis on divise ensuite cette somme
par le nombre de notes (20).

Mais pour savoir quelles notes sont supérieure à la moyenne de la classe,


Il est nécessaire de mémoriser ces 20 notes.

on pourrait prévoir vingt variables scalaires différentes, note1, note2, note3,


note4, note5, …, note15, note16, note17, note18, note19, et ouf ! Note20

cette méthode est difficilement applicable pour un nombre important de notes.

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.

En langage C, la première position porte le numéro 0 (ou l'indice 0).

48
int note[20] ;

Ici, donc, nos indices vont de 0 à 19.

Le premier élément du tableau sera désigné par note[0], le troisième par


note[2], le dernier par note[19].

et note[i] désigne : un élément dont la position dans le tableau est fournie


par la valeur de i.

note[i] joue le même rôle qu’une variable scalaire de type int.

La notation &note[i] désigne l’adresse de l'élément note[i],


comme &n désignait l’adresse de n.

49
Exemple:

#include <stdio.h> /* Calculer la somme */


#include <stdlib.h> for(i=0,som=0; i<N; i++)
#define N 7 som=som+note[i];

int main() /* Calculer la moyenne */


{ moy=som/N;
int i,nbr; printf("\n Moyenne : %f\n",moy);
float som, moy , note[N]; /* Nombre de Notes >= moyenne de Classe */
/* Memoriser les Notes */ for(i=0,nbr=0; i<N; i++)
for(i=0; i<N; i++) if(note[i]>=moy) nbr=nbr+1;
{ printf("%d eleves ont une note >= à la
printf("Note%d : ",i); moyenne de la classe \n",nbr);
scanf("%f",&note[i]); return 0;
} }

50
6-2-Tableaux à plusieurs dimensions :

C autorise l’utilisation de tableaux à plusieurs indices (ou dimensions) sans


limitation sur leur nombre.
La déclaration :
int t[5][3] ;

réserve un tableau de 15 éléments ( 2 indices : 5 lignes et 3 colonnes).

Un élément quelconque de ce tableau est repéré par le numéro de la ligne et


le numéro de la colonne.

Exemple :

t[3][2] ou bien t[i][j] avec i et j entiers.

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.

Il est possible de ne mentionner dans les accolades que de certaines


valeurs seulement.

Exemple:
int t[5]={10,20}
int t[5]={ , ,5, ,3}

Les valeurs manquantes d'un tableau sont initialisées à 0.

52
6-4-initialisation des tableaux à plusieurs dimensions :

int t[3][4] = { { 1, 2, 3, 4},


{ 5, 6, 7, 8},
{ 9,10,11,12}
};

Cette forme considère que ce tableau est formé de 3 tableaux de 4 éléments


chacun.

ou bien

int t[3][4 ]= { 1,2,3,4, 5,6,7,8, 9,10,11,12 };

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 & :

Le langage C permet de manipuler des adresses par l’intermédiaire de variables


nommées " pointeurs".
La déclaration : int *ad ;

réserve une variable nommé ad comme pointeur sur des entiers.


 * est un opérateur qui désigne le contenu de l’adresse qui le suit.
 L’instruction ad = &n place l’adresse de la variable n dans la variable ad.

 *ad est la variable pointée par ad, sa valeur est celle de n.

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 |__**__|

*ad=30; /* équivaut à faire n=30 */ n |__30__|

56
Exemple 2 :

Soit a =10 et b=20 deux variables entières


et p un pointeur, de type entier non initialisé.

a=10 ;
b=20 ;

p=&a ;

b=*p ; /*------- b=a=10 -------*/

*p=30 ; /*------- a=30 -----------*/

57
Exemple 3 :
int *ad1, *ad2, *ad3 ;

int a=10,b=20 ;

ad1=&a; /*---- place dans ad1 l’adresse de a----*/

ad2=&b ; /*--- place dans ad2 l’adresse de b ----*/

*ad1 = *ad2 + 2 ; /*---------------- a=b+2 ------------------*/

*ad1 += 3 ; /*--------------- a=a+3 -----------------*/

(*ad1) ++; /* joue le même rôle que a++ donc a=a+1 */

58
6-5-2-Arithmitique sur les pointeurs :

• Si ad une variable pointeur déclarée par :


int *ad;

• alors ad+1 représente l’adresse de l’entier suivant


très utile pour le traitement de tableaux et de chaînes de caractères .

• ad++ incrémente l’adresse contenue dans ad,


ad désignera l’objet suivant.

59
Les opérateurs autorisés sur les pointeurs sont.

 Addition ou Soustraction d’un entier à un pointeur, le résultat est de même


type que le pointeur.

Si le type int est représenté en mémoire par 2 octets


et le type double par 8 octets,
- pour int *ad ; la différence entre ad+1 et ad est de 2 octets,

- pour double *ad ; la différence entre ad+1 et ad est de 8 octets .


La différence de deux pointeurs de même type donne un résultat entier.
 Les autres opérations arithmétique ( somme, produit, ...) sont illégales.

60
6-5-3-Utilisation des pointeurs en argument d’une fonction :

• Le mode de transmission par valeur interdit à une fonction de modifier la


valeur de ses arguments effectifs.

• L’utilisation des pointeurs autorise la modification de ces arguments .

Le programme suivant réalise cette opération :

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 :

En langage C l’identificateur ( le nom ) d’un tableau lorsqu’il est employé seul


(sans indice à sa suite), il désigne l’adresse de début de ce tableau.
6-6-1-Cas des tableaux à une dimension :

Soit la déclaration suivante : int t[10] ;


Les notations :
t est équivalent à &t[0]
et t+1 <=> &t[1]
et t+i <=> &t[i]

63
Exemple 3 :

3 façons de faire la même chose : mettre 1 dans chaque élément du tableau t

int i; int i; int i; int * p;


for( i=0; i<=10; i++) for(i=0; i<=10; i++) for(p=t, i=0; i<=10;i++,p++)
*(t + i)=1; t[i]=1; *p=1;
6-6-2-cas des tableaux à plusieurs dimensions:
Comme les tableaux à une dimension, l’identificateur d’un tableau t à
plusieurs dimensions, employé seul représente l’adresse du début de t

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]

6-7- Les pointeurs sur les fonctions :

En langage C le nom d'une fonction f :

• Ne peut pas être placé dans une variable. ( aussi dans d'autres langages)

• Si le nom f est employé seul, il est traduit en l'adresse de cette fonction


• cette adresse peut être placée dans une variable adf, destinée à pointer sur
cette fonction ( adf devient un pointeur sur la fonction f)

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 :

Il est possible grâce au pointeur de transmettre des fonctions en argument.

66
CHAPITRE 7 : Les chaînes de caractères

En langage C il n’existe pas de variable type chaîne.

Il existe une convention de représentation des chaînes de caractères


utilisée par:

• le compilateur pour :

✔ représenter les constantes chaînes,


• certaines fonctions pour :
✔ Les lectures ou écritures de chaînes,

✔ Les traitements classiques tels que : concaténation, copie,


comparaison, extraction de sous chaîne.

67
Un tableau de caractères est utilisé pour les données Alpha-
Numériques

(En C,il n'y a pas de type chaîne de caractères)

7-1-représentation des chaînes en langage C :

Une chaîne de n caractères occupe un emplacement de n+1 octets.

7-1-1-Les constantes chaînes de caractères :

Une constante chaîne de caractères est repéré en langage C à l’aide d’une


adresse donc d'un pointeur.

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 */

adr="Bonjour" ; /* signifie que bonjour


est repéré par pointeur adr */
printf ("%s \n",adr);

69
Remarque :

adr="Bonjour" ;

la notation "Bonjour" a comme valeur, non pas la valeur de la chaîne de


caractère elle même, mais son adresse.

La notation adr="Bonjour" correspond à constante pointeur qui n'est pas


modifiable.

B o n j o u r \0

adr

Résultat : Bonjour
70
7-1-2-Initialisation de tableaux de caractères :

Le langage C autorise d’initialiser un tableau à l’aide d’une chaîne constante.

Exemple :

✗ char ch[20]= "bonjour"

ou bien :

✗ char ch[20]={‘ b ’,’ o ’,’ n ’,’ j ’,’ o ’,’ u ’,’ r ’,’ \0 ’}


" \0 " : fin de chaîne à ne pas oublier.

71
7-1-3-initialisation de tableaux de pointeurs sur des chaînes :

On a vu qu'une constante chaîne de caractère est traduite par le compilateur


en une adresse, qu'on peut affecter à un pointeur.

On peut le généraliser à un tableau de pointeurs

Exple :
char *jour[7]={"lundi","mardi","mercredi","jeudi",
"vendredi","samedi","dimanche"} ;

• création de 7 constantes chaines de caractères (une pour chaque jour de la


semaine)
• initialisation d'un tableau jour avec les 7 adresses de ces
7 chaines

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 :

Le langage C offre plusieurs possibilités de lecture et d’écriture.

7-2-1-Les fonctions : « gets », « puts », et le code format %s :

Les fonctions printf et scanf permettent de lire ou d’afficher simultanément


plusieurs informations de type quelconque.

Par contre, gets et puts ne traitent qu’une chaîne à la fois.

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.

Les délimiteurs de chaines étant l’espace, la tabulation ou la fin de


ligne.
• Avec gets c'est la fin de ligne qui sert de délimiteur.

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.

char nom[20], prenom[30], ville[30] ;

2 – Dans les appels de fonction scanf et puts les identificateurs de tableau


comme nom, prénom et ville ne doivent pas être précédé de l’opérateur & puisqu’il
représentent déjà des adresses.

3- La fonction puts réalise un changement de ligne à la fin de l’affichage de la


chaîne, printf avec le code format %s ne le fait pas.

77
7-2-2- La fonction « cgets » :

La fonction cgets ou (_cgets pour devc++) utilise les deux première


caractère de la zone dont on lui fournit l’adresse pour gérer sa lecture :

- Le premier octet doit être initialisé par le programmeur au nombre maximum


de caractère que l’on souhaite rangé en mémoire y compris le caractère nul
de fin de chaîne « \0 ».

- Le second octet sera renseigné par « cgets » à la fin de l’opération pour


indiqué le nombre de caractère effectivement lue.

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);

Cette fonction strcat recopie la seconde chaîne (source) à la suite de la première


(but), après avoir effacé le caractère de fin de la première chaîne.

7-3-2 La fonction « strncat » :


Syntaxe :

strncat(but , source , lgmax);

“strncat” travaille de façon semblable à strcat en offrant un contrôle sur le nombre


de caractères qui seront concaténes à la chaîne d’arrivée ( but ).

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)

La fonction “strlen” donne la longueur d’une chaîne ;

Exemple :

strlen(ch1) : fournie une valeur entier (int) correspondante à la valeur de la


longueur de chaîne ch1. Le caractère (\0) n’est pas comptabilisé.

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.

7-4-1 La fonction « strcmp » :


Syntaxe :

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 » :

Syntaxe : strncmp(ch1 , ch2 , lgmax) ;


La fonction « strncmp » travail comme strcmp mais elle limite la comparaison en
nombre maximum de caractère indiquer par l’entier « lgmax ».

Exemple :
strncmp("bonjour”,”bon”,4) est positif
strncmp("bonjour”,"bon”,2) vaut zéro

7-4-3 Les fonctions « stricmp » et « strnicmp » :


Les deux fonctions « stricmp » et «strnicmp » travaillent comme strcmp et
strncmp mais sans tenir compte de la différence entre majuscule et minuscule.

85
7-5 Les fonctions de copie de chaînes :
7-5-1- La fonction « strcpy » :
Syntaxe :
strcpy(destin,source) ;

La fonction strcpy recopie la chaîne située à l’adresse « source » dans


l’emplacement d’adresse « destin ».
7-5-2 La fonction « strncpy » :
Syntaxe :
strncpy(destin,source,lgmax) ;

La fonction strncpy procède de manière analogue à strcpy en limitant la recopie


au nombre de caractères précisé par l’expression entière « lgmax ».

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.

7-6-2 La fonction « strrchr » :


Syntaxe :
strrchr(chaîne,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) ;

La fonction strstr recherche dans chaîne la première occurrence complète de la


sous chaîne mentionné.

7-6-4 La fonction « strpbrk » :


Syntaxe :
strpbrk(chaîne1,chaîne2) ;
La fonction strpbrk recherche dans chaîne1 la première occurrence d’un caractère
quelconque de chaîne2.

88
7-7 Les fonctions de conversion :
7-7-1 Conversion d’une chaîne en une valeur numérique :

Trois fonctions de <stdlib.h> permettant de convertir une chaîne de caractère


en une valeur numérique int, long, ou double

atoi(chaîne) fournit un résultat de type int




atol(chaîne) fournit un résultat de type long




atof(chaîne) fournit un résultat de type double




Remarque :

Si aucun caractère n’est exploitable, ces fonctions retourne un résultat nul.

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 :

Donnez SVP une chaîne :123


int :123
double:1.230000e+002
Donnez SVP une chaîne :xy
int :0
double:0.000000e+00

91
7-7-3 Conversion d’une valeur numérique en une chaîne :

ces fonctions, réservése MsDos, non conformes ANSI-C, non portables.

ces fonctions expriment un nombre d’une suite de chiffres dans n’importe


quelle base entre 2 et 36.

– itoa(entier,chaîne,base), entier est de type int

– ltoa(entier,chaîne,base), entier est de type long


– ultoa(entier,chaîne,base), entier de type unsigned long

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 :

Donnez un nombre et une base : 123 10 123


Donnez un nombre et une base : -123 10 -123
Donnez un nombre et une base : 200 16 c8
0Donnez un nombre et une base : -200 16 ffffff 38
Donnez un nombre et une base : 200 2 11001000

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.

La structure (enregistrement en PASCAL) va nous permettre de désigner


sous un seul nom un ensemble de valeurs pouvant être de type différent.

En C il est possible d’utiliser une structure de deux manières, en


travaillant :

• individuellement sur chacun de ses champs.


• de manière globale sur l’ensemble de la structure.

95
8-1- Exemple de déclarations de structure :
struct enreg
{
int numero ;
int qte ;
float prix ;
};

Après avoir définie le modèle il faut déclarer des variables correspondants à ce


module.

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 :

La désignation d’un champ se note en faisant suivre le nom de la variable


structure du nom de champ tel qu’il a été définie dans le modèle.

Exemple :

art1.numero = 30 ; /*affecte 30 au champ numero de la structure art1.*/

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 */

art1.numero++ ; /* incrémente la valeur du champ numero (structure art1). */

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 :

art1 = art2 ; <=> (plus avantageux que)


art1.numero = art2.numero ;
art1.qte = art2.qte ;
art1.prix = art2.prix ;

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 :

struct enreg art1={15,285,50.125} ;

8-3 Déclaration de types synonymes : « typedef »

La déclaration typedef permet de définir ce que l’on nomme en langage C les


types synonyme.

Elle s’applique à tous les types et pas seulement à la structure.

100
8-3-1- Exemples d’utilisation de « type def » :

la declaration : typedef int entier ; Signifie que entier est synonyme à int

Int n,p ; <=> entier n,p ;

la declaration : typedef int vecteur[3] ;


Int V[3],W[3] ; <=> vecteur V,W ;

De même : typedef int * ptr signifie que ptr est synonyme de int *.

int * p1, * p2 <=> ptr p1, p2 ;

101
8-3-2 Application aux structures:

En faisant usage de typedef, les déclarations des structures art1 et art2 vu


précédemment peuvent être réalisé comme suite :

struct enreg ou bien :


{ typedef struct enreg
int numero ; {
int qte ; int numero ;
float prix ; int qte ;
} ; float prix ;
typedef struct enreg s_enreg ; } s_enreg ;
s_enreg art1, art2 ; s_enreg art1, art2 ;

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 ;

Cette structure permet de conserver pour un employé d’une entreprise les


informations suivantes :
- Nom
- Prénom
- Nombre d’heures de travail effectué pondant chacun des jours du mois.

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.

Si iest un entier, la notation :

courbe[i].nom représente le nom du point de rang i du tableau courbe.


Il s’agit donc d’une valeur de type char.
Attention : courbe.nom[i] n’a pas de sens.

courbe[i].x est la valeur du champ x de l’élément de rang i du tableau courbe.

105
struct point
{
char nom ;
int x ;
int y ;
};
struct point courbe[50] ;

Courbe est un identificateur de tableau, et désigne aussi son adresse de début.


Courbe[4] représente la structure de type point correspondant au cinquième
élément du tableau courbe.

Exemple d’initialisation (partielle) de notre variable courbe, lors de sa déclaration :

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)

struct personne emp = {"Dupont", "Jules", { 8, 7, 8, 6, 8, 0, 0, 8}};

initialisation cette structure de type personnelors de sa déclaration :

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.

La réservation se fait de la droite vers la gauche.

Les seuls types susceptibles de figurer dans un mot de champs de bits est int
et unsigned int.

Un champ de type int est de longueur 1 ses valeurs possibles sont 0 et -1

Un champ de type unsigned int , a valeurs possibles 0 et 1

113
8-6 Les unions :

L’union en C permet de faire partager un même emplacement mémoire par


des variables de types différents pour économiser des emplacements mémoires.

La déclaration :
union essai
{
long n;
float x;
}u;

Réserve un emplacement de 32 bits (4 octet) sera considéré


- tantôt comme un entier long désigné par u.n,
- tantôt comme un float qui sera désigné par u.x.

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 :

Le langage C comme tous les langages dispose de plusieurs instructions de


gestion de fichier.

Un fichier est un ensemble de données structurées et enregistrées sur un


support magnétique.

116
9-2 L’accès séquentiel :
9-2-1-Création séquentielle d’un fichier :
Exemple :

#include <stdio.h> do { printf ("donnez un entier : ") ;


main() scanf ("%d", &n) ;
{ if (n) fwrite (&n, sizeof(int), 1, sortie) ;
char nomfich[21] ; }
int n ; while (n) ;
FILE * sortie ; fclose (sortie) ;
printf ("nom du fichier à créer : ") ; system("PAUSE");
scanf ("%20s", nomfich) ; return 0;
sortie = fopen (nomfich, "wb") ; }

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.

-fread (&n, sizeof(int), 1, entree); : lit un entier « n » de taille sizeof(int) octets


en 1 bloc à partir du fichier « entree ».

- feof(entree): c’est une fonction qui détecte la fin du fichier.

On pourrait remplacer la boucle while :

while ( fread (&n, sizeof(int), 1, entree), ! feof(entree) )


printf ("\n%d", n) ;

par la construction (moins concise) suivante :


do
{ fread (&n, sizeof(int), 1, entree) ;
if ( !feof(entree) ) printf ("\n%d", n) ;

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.

9-2-3 Gestion des erreurs :

Nous pouvons améliorer les deux programmes précédents, afin de prendre


en compte convenablement les éventuelles situations d’erreur .

• fopen : fournit un pointeur Nulle en cas de problème d’ouverture d’un


fichier

• fread : fournit le nombre de blocs effectivement lus (et pas le nombre


d’octets lus)
122
Si ce nombre est inférieur au nombre de blocs demandés, soit on a
rencontré une fin de fichier, soit une erreur de lecture est apparue.

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
}

b)- Lecture séquentielle d’un fichier :


Exemple :

#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

• Il n'y a pas de notion d’enregistrement (ou de bloc)


• On peut créer un fichier par bloc de 20 octets et le relire par bloc de 7 octets.
• l’utilisateur doit d’assurer la cohérence dans la gestion de ses informations.
9-3 L’accès direct :
Les fonctions fread et fwrite lisent et écrivent un certain nombre d’octets
dans un fichier à partir d’une position courante, à l'aide d'un "pointeur" dans le
fichier c’est à dire un nombre précisant le rang du prochain octet à lire ou à
écrire.
Après chaque opération de lecture ou d’écriture ce pointeur se trouve
incrémenté d’un nombre d’octets transférés. C’est comme ça que ’on réalise un
accès direct dans le fichier.

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
}

La principale nouveauté dans ce programme est la fonction fseek :


fseek(entree,sizeof(int)*(num-1),0);
Cette fonction a trois arguments :
- Le nom logique du fichier concerné (entree).
- Un entier long spécifiant la valeur que l’on souhaite donner au pointeur du fichier
sizeof(int)*(num-1)
- Le mode d’action sur le pointeur du fichier dépend d'une constante entière,
prédéfinie dans <stdio.h>, qui peut être SEEK_SET, SEEK_CUR ou SEEK_END
Pour des raisons de portabilité, il est conseillé d'utiliser ces constantes

o SEEK_SET ou 0 : le second argument désigne un déplacement en octet


depuis le début du fichier.
o SEEK_CUR ou 1 : le second argument désigne un déplacement exprimé à
partir de la position courante.

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 :

• Consultation immédiate de la valeur voulue


• facilite et accélère les opérations de mise à jour d’un fichier.
• Permet de remplir un fichier de façon quelconque, en laissant l’utilisateur
fournir ces entiers dans l’ordre de son choix, comme dans cet exemple de
programme :
Exemple :
#include <stdio.h>
main() while (printf ("No de l’entier recherché : ") ,
{ scanf ("%ld", &num), num )
char nomfich[21] ; {
int n ; fseek (entree, sizeof(int)*(num-1), SEEK_SET) ;
long num ; fread (&n, sizeof(int), 1, entree) ;
FILE * entree ; printf (" valeur : %d \n", n) ;
printf ("nom du fichier : ") ; }

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.

• On peut aussi, avant d’exécuter le programme précédent, commencer par


initialiser tous les emplacements du fichier à une valeur spéciale.

9-3-3 En cas d’erreur :


a)- Erreur de pointage :

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 :

Il arrive au moment de la lecture de se positionner en dehors du fichier, en


principe la fonction « fseek » retourne :
- La valeur 0 lorsque le positionnement s’est déroulé correctement.
- Une valeur quelconque dans le cas contraire.
9-4 Les différents modes d’ouverture d’un fichier « fopen » :
w : écriture seulement, si le fichier n’existe pas il est crée, s’il existe son ancien
contenu est perdu.
r : lecture seulement, le fichier doit existé.
b : données enregistrées sous forme binaire.
t : données enregistrées sous forme ASCII.
a : écriture en fin de fichier si le fichier existe déjà, s’il n’existe pas il sera créer.
a+ : extension et mise à jour.
r+ : mise à jour (lecture, écriture) le fichier doit exister, il faut utiliser fseek de
l’accès direct.
135
w+ : création d’un fichier et ouverture en lecture, écriture si le fichier existe déjà.

136
9-5 Les noms des fichiers associés à des périphériques :

Un certain nombre de périphériques sont assimilables à des fichiers ils


portent un nom qui peut apparaître dans les instructions fopen.

Exemple :

Des instructions telles que : sortie = fopen ("PRN","w"); fwrite(sortie, ... )


dirigent les informations sur imprimante :

CON : (console) clavier en entrée, écran en sortie.


PRN ou LPT1 : première imprimante (interface parallèle)
LPT2 : deuxième imprimante (interface parallèle)
LPT3 : troisième imprimante (interface parallèle)
AUX ou COM1 : première sortie série.
COM2 : deuxième sortie série …
137
9.6 Mode translaté et mode binaire

Sous DOS la fin de ligne est représentée par un couple de deux caractères :

- Un retour chariot CR de code ASCII 13 (en décimal)


- Un changement de ligne, noté LF, de code 10 (en décimal)

De plus la fin de fichier est caractérisée par CTRL/Z (code ASCII 26).

Sous UNIX le changement de ligne est représenté par LF (en langage C : \ n)

138
Remarque :

Certains compilateurs C, assurent une transportabilité des programmes


traitant des fichiers de type texte, en agissant sur les fonctions de lecture pour
considérer LF équivalent à CR/LF.

Cette possibilité porte le nom de « mode translaté », elle s’oppose au mode


non translaté (au mode binaire)

Travail à Faire : recherche sur :


fscanf ( fichier, format, liste_d’adresses )
fprintf ( fichier, format, liste_d’expressions )
fgetc ( fichier )
fputc ( entier, fichier )
fgets ( chaîne, lgmax, fichier )
fputs ( chaîne, fichier )

139
============ Fin pour aujourd'hui ================================

140
9.7 L’accès séquentiel en niveau 1

9.7.1 Création séquentielle d’un fichier.

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);
}

Par rapport au programme correspondant de niveau 2 les fonctions portent des


noms semblables.
Niveau1 niveau 2
Open fopen
Write fwrite
Close fclose

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.

9.7.2 lecture d’un fichier séquentielle

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) ;
}

la différence entre niveau 1 et 2


lseek et fseek
lseek on trouve un numéro de fichier, dans fseek on trouve un
pointeur sur une structure FILE.
En niveau 1 on peut connaître la taille d’un fichier
long
.

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 ».

La programmation modulaire permet :

La maîtrise d’un programme qui dépasse deux pages de texte.

Eviter des instructions répétitives.

Partager des outils, écrit et au point une seule fois.

Remarque :
C autorise la compilation séparée des modules.

149
10-1-Notion de fonction en C :

La plupart des langages de programmation utilisent 2 sortes de modules :

- La fonction assez proche de la notion mathématique.


- La procédure (terme PASCAL) ou bien sous programme (FORTRAN)

o En C il n’existe qu’une seule sorte de module : la fonction.

o En C la fonction remplace la procédure ou le sous- programme des autres


langages.

150
a)- Exemple :

#include<stdio.h>
main()
{
optimist() ;
}
optimist()
{
printf(“ il fait beau”);
}

Résultat : 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.

Pour les appels : ecris(a) ; ecris(b) ; a et b sont des arguments effectifs.


Un argument effectif peut aussi être sous forme d'une expression.

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.

b)- L’instruction « return » :

return(s) : c’est l’instruction qui spécifie le résultat qui sera fournit par la fonction
lors de son appelle.

Remarque : return peut apparaître à plusieurs reprises dans une fonction.

10-3 Les prototypes et le type « void » :


a)- Notion de prototype :

C autorise la déclaration d’une entête de fonction complete nommée prototype


fournissant les types des arguments. La déclaration « double som() ; » de
l’exemple précédent pourrait être remplacer par : double som(double, double);

155
b)- Rôle de prototype :

Le prototype permet à C de corriger les erreurs de déclaration de type entre les


arguments.

Exemple :

double som() ; ou double som(double, double) ;

Si on appelle la fonction « som » avec « som(n,p) ; » le compilateur mettra en


place une conversion des valeurs n et p en valeurs de type double avant qu’elles
ne soit transmises à la fonction « som ».

En absence de prototype des erreurs peuvent se produire.

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)

La fonction « optimist » ne retourne pas de résultat, ainsi que la fonction « ecris ».

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.

10-5 Les variables globales :


En C plusieurs fonctions dans le programme principale main, peuvent
partager des variables communes : on les qualifie par globale.

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.

10-6 Les propriétés des variables globales :


a)- portée :

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.

10-7 Les variables locales automatiques ou statiques :


Les variables qui sont définies au sein d’une fonction sont dites locales à la
fonction.

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.

b)- Les variables locales automatiques :


Les valeurs des variables locales ne sont pas conservées d’un appel au suivant.
Les variables locales ont une durée de vie limitée au temps d’exécution de la
fonction où elles figurent.

c)- Les variables locales statiques :


Il est possible de demander d’attribuer un emplacement permanant à une variable
locale, et ainsi sa valeur se conserve d’un appel au suivant. Il suffit de la déclarer à
l’aide du mot réservé « static ».

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

Un programme en train de s'exécuter utilise essentiellement


2 segments mémoires :
• Un Segment De Mémoire Pour Les Données
Le segment de données alloue la mémoire selon
deux techniques :
• la pile(statique) et
• le Tas (dynamique).

• Un Segment de Mémoire pour le Code


exécutable.

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 » :

La fonction free permet de libérer un emplacement réservé par malloc.

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) ;

La fonction realloc permet de modifié la taille d’une zone préalablement


allouée par malloc ou calloc.

Le pointeur doit être l’adresse du début de la zone dont on veut modifier la


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 :

Avant appel fct : 10 1.250000e+001


Dans fct : 11 1.3500000e+001
Retour dans main : 10 1.250000e+001

• 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 :

En C, impossible de déclarer un tableau dont le nombre d’éléments n’est pas


connu lors de la compilation. Un tableau est réservé en mémoire statique.
Mais la gestion dynamique du langage C permet d’allouer des emplacements
aux différents éléments du tableau au fur et à mesure des besoins.
D'autre part si on n'a pas besoin d’accès direct à chacun des éléments, on
peut économiser la mémoire statique à l'aide d'une « liste chaînée », dans laquelle
• un pointeur désigne le premier élément ;
• chaque élément comporte un pointeur vers l’élément suivant. c’est une
récursivité de déclaration qui est autorisé en C.

180
a) Appliquons cela à des éléments de b) adaptons notre structure de la
type point, manière suivante :

Struct point Struct element


{ {
int num ; int num ;
float x ; float x ;
float y; float y;
}; struct element *suivant;
};

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.

typedef struct element { int num ;


float x ;
float y;
struct element *suivant;
} s_point ;

À partir de cette structure on peut écrire un programme de création d’une liste


chaînée.

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 ;

b)- Définition de macros :


La définition de macros ressemble à la définition de symboles en faisant intervenir
en plus des paramètres.
Exemple :

#define Carre(a) a*a ;

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

Il est possible de faire intervenir plusieurs paramètres.

Exemple :

#define dif(a,b) a-b


dif(x,z) --> x-z
dif(valeur+10,n) --> valeur+10 – n

12-4 La compilation conditionnelle :


L’incorporation par le pré processeur d’un texte dans un fichier source peut être
selon une condition sous l’une des formes suivantes :
186
- Soit l’existence ou l’inexistence de symboles.
- Soit selon une valeur d’une expression.
a)- Incorporation liée à l’existence de symboles :
Exemple :

# if def symbole Si symbole est définie le texte entre # if def symbole


et #else sera
…… … incorporé. Sinon c’est le texte entre #else et endif qui
sera incorporé.
…… …
#else
………
………
#endif

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

On peut convertir un int en double mis pas un double en float ou en int.

190
E xemple : Calcul de n * x + p pour n et p de type int, et x de type float :

le compilateur effectue le produit n * x :

a-) n : est convertit en float

b-) n * x : devient une multiplication entre 2 floats et donnera un 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 :

La conversion est effectuée en considérant les opérandes un à un et pas


l’expression de façon globale

191
Exemple :

Calcul de n * p + x pour n de type int, p de type long et x de type float

n * p + x est évaluée suivant ce schéma :


n * p + x
| | |
long | | conversion de n en long
|__* _ | | multiplication par p
| |
long | le résultat de * est de type long
| |
float | il est converti en float
|____+ __| puis additionné à x
|
float ce qui donne un résultat de type float

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 :

1- les types entiers signés et non signés (unsigned).

Il est fortement déconseillé de mélanger, dans une même expression, des


types signés et des types non signés, car les conversions qui en résultent sont
généralement dénuées de sens.

2- le type char

une valeur de type caractère peut être considérée de deux façons :


- Comme le caractère concerné : a, Z, fin de ligne,
- Comme code de ce caractère, motif de 8 bits. Mais on peut toujours lui faire
correspondre un nombre entier, son code ASCII, A <----> 65

194
Exemple :

Soient c1et c2 sont de type char, n type int.

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

short int <= int <= long int


float <= double <= long double

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.

Ces parties de code séparés (fichiers sources), peuvent être développées et


testées par des personnes différentes.

En général on crée un projet, dans lequel on va mettre l'ensemble des


fichiers sources de notre programme.

Jusqu'ici, nos projets étaient constitués d'un seul fichier : main.c

198
Ici notre projet tp1 est constitué d'un seul fichier main.c

199
200

S-ar putea să vă placă și