Vous êtes sur la page 1sur 158

16/05/2018

Programmer, c'est quoi ?

Initiation au langage C

1 2

1
16/05/2018

Programmer, c'est quoi ? Classification des langages

Langages de
programmation

Langages Langages
impératifs déclaratifs

Programmation Programmation Programmation programmation Programmation


procédurale Orienté Objet concurrente logique fonctionnelle
Pascal, C C++, Java Ada 95 PROLOG LISP

3 4

2
16/05/2018

Caractéristique du langage C Comment ça marche?

Compilateur C
.C
✓ Langage a été inventé par Dennis Ritche en 1973; fichier

✓ Langage procédurale;

✓ Langage simple -peu de mot clé; Les outils nécessaires au Code


programmeur ? assembleur
✓ Code prévisible;

✓ Efficacité (système embarqué, os); Assembleur

✓ Assembleur de haut niveau.


Code
objet
.exe Linker
Code executable

5 6

3
16/05/2018

Premier programme un fichier C (extension .c)

Monprogramme.c /* exemple de programme C :


- somme des nb de 1 à 10 et affichage En C le programme principal
1
de la valeur*/ s'appelle toujours main
0
déclarations de variables de
#include <stdio.h> type entier (cases mémoire
2
int main (void) 1 pouvant contenir un entier)
{ instruction d'affectation de 3
int somme; int i; 2 valeur à la variable somme
somme = 0; 3 4
instructions exécutées
for (i = 1; i <= 10; i++) en séquence
{ l'instruction entre accolades 4
somme = somme + i; est exécutée pour les valeurs
de i allant de 1 à 10
}
5
printf ("%d\n", somme); 5 affiche à l'écran la valeur de
l'entier contenu dans somme
Fenêtre ou Console? return 0;
7
}

4
16/05/2018

Anatomie Les commentaires, c'est très utile !

Programme typique en C Votre commentaire est court : double slash (//) suivi de votre commentaire.

printf("Bonjour "); // Cette instruction affiche Bonjour à l'écran


include
Main() toujours la
1ère fonction appelée
main()

/* commentaire s’étendant
fonction a() instructions
sur plusieurs lignes
de programme source */
fonction b() instructions

9
instructions
9 10

5
16/05/2018

Types d’instruction en langage C Types de données et de variables

• Déclarations des variables • Déclaration des variables


– int y;
• Assignations – char nom, adress;
– int id= 1, ref= 0;
• Fonctions – float total = 43.132;
– char *cptr = NULL;

• Contrôle

11 12

6
16/05/2018

Types de données et de variables Quick QCM

le nom de variable doit être :


✓ Formé de lettres et de chiffres ainsi que du caractère _ . Le 1er Vérifier la validité des noms des variables suivantes :(valide/invalide)
caractère doit obligatoirement être une lettre ou bien le caractère _.
✓ Peut contenir jusqu'à 31 caractères minuscules et majuscules.
a) id2
Il est d'usage de réserver les identificateurs entièrement en majuscules
aux variables du préprocesseur. b) 4eme
Les mots-clés c) x#y
d) _id
e) no-commande
f) taux change
g) _2344
h) %id

13 14

7
16/05/2018

Types de données et de variables Types de données et de variables

Type
Syntaxe

ensemble vide
void
• Type « char » ou « signed char »:
caractère
char – ASCII sur 8 bits
short int
entier court • de -128 et +127.

entier par défaut


int
• Type « unsigned char »:
entier long
long int – ASCII sur 8 bits
réel simple précision • de 0 et 255.
float

réel double précision


double

long double réel précision étendue

15 16

8
16/05/2018

Types de données et de variables Types de données et de variables

• Type « int » ou « signed int » • Type « long » ou « signed long »


– en complément à 2 sur 32 bits – en complément à 2 sur 32 bits
• de -2147483648 à 2147483647. • de -2147483648 à 2147483647.

• Type « unsigned int »: • Type « unsigned long »:


– binaire sur 32 bits – binaire sur 32 bits
• de 0 à 4294967295. • de 0 à 4294967295.

17 18

9
16/05/2018

Les modificateurs des classes de mémorisation Les modificateurs des classes de mémorisation

• « const »:
• « extern »: – indique que le contenu d’une variable ne doit pas être
modifiée.
– indique une variable ou une fonction déclarée dans un
autre module.
• « volatile »:
• « register »: – indique qu’une variable peut voir son contenu changer
à tout moment par le programme, des interruptions ou
– demande au compilateur de placer des variables dans tout autre facteur extérieur. Empêche le compilateur
les registres du CPU. Augmente la vitesse de de faire des optimisations sur cette variable.
traitement.

22 23

10
16/05/2018

Opérateurs et expressions Opérateurs et expressions

• Opérateurs arithmétique:
• Opérateurs à un paramètre: – *,/,+,-
–- change le signe de la variable – % modulo
–* « indirection » (pointeurs)
• value = *salary; /* contenu pointé par salaire */ • Opérateurs sur bits:
– & adresse – & et
– ++/-- incrémentation/décrémentation –| ou
– sizeof()

24 25

11
16/05/2018

Opérateurs et expressions Opérateurs et expressions

• Opérateurs relationnels:
– <,>,<=,=> • Opérateur conditionnel:
– result = mode > 0 ? 1 : 0;
• Opérateurs d’égalité: – if mode>0 then result=1 else result=0.
– ==, !=
• Opérateurs d’assignation:
• Opérateurs logiques: – =, *=, /=, %=, +=, -=, <<=, >>=, &=, |=
– && et
– || ou

26 27

12
16/05/2018

Fonctions d’entrées-sorties Écriture avec format : printf

printf("chaine-de-controle-du-format", exp1, exp2,...,expN)


L’ entête <stdio.h> (abréviation de STandarDIn-Out) fournit trois
flux que l’on peut utiliser directement: Format d’ Écriture
– stdin, l’ entrée standard, %d int
%f double
– stdout, la sortie standard, %c char character
- stderr, la sortie standard des erreurs. %s char* chaîne de caracteres

28 29

13
16/05/2018

Lecture avec format: scanf Exemple


# include<stdio.h>
Int main(){
scanf("chaine-de-controle-du-format", arg-1,arg-2,...,arg-N) Int n=0;
Int m=0;
Char caractere=’A’;
Format d’ Écriture
%d int printf("\n Entrez 2 nombres au format\"**et**\":");
%f double scanf("%d et %d",&n, &m);
%c char character printf("\n Entrez un caractere:");
%s char* chaıne de caracteres scanf("%c",&caractere);
printf("\n Nombres choisis:%d et %d. Caractere
choisi:%c.\n", n, m, caractere);
return0; } Exécution avec saisie correcte:
1. Entrez 2 nombres au format"**et**": 12 et13
2. Entrez un caractère: B
30 31

14
16/05/2018

Contrôle des acquis Contrôle des acquis

1. Quel est le nom de la fonction principale d'un


2. Quel symbole termine toujours une instruction ?
programme ?
a) .
a) principal
b) ,
b) main
c) ;
c) N'importe quel nom
d) }
d) Start

32 33

15
16/05/2018

Contrôle des acquis Contrôle des acquis

4. Quelle est la fonction qui permet d'afficher du


3. Comment écrire un commentaire sur une seule ligne ? texte à l'écran en mode console ?
a) // mon commentaire //
a) Aff(" un message ");
b) // mon commentaire
c) /* mon commentaire */ b) print(" un message ");

d) /* mon commentaire c) printf(" un message ");


d) fprintf(" un message ");

34 35

16
16/05/2018

Contrôle des acquis Contrôle des acquis

6. Qu'est-ce qu'un programme en mode "console" ?


5. La programmation en C permet la création de quel type
de fichier ?
a) Un programme qui fonctionne uniquement sur une
a) Des images (*.jpg, *.png, *.bmp …
console de jeux
b) Des exécutables (*.exe sous Windows)
b) Un programme qui fonctionne dans une fenêtre Dos
c) Des sources (*.c)
c) Un programme en environnement graphique avec
d) Des fichiers texte (*.txt)
des fenêtres

36 37

17
16/05/2018

Contrôle des acquis Contrôle des acquis

7. Quel type de donnée permet de stocker 15.4528 ? 8. Quel type de donnée permet de stocker -25 ?

a) char a) int

b) long b) unsigned int

c) double c) unsigned double

d) int d) float

38 39

18
16/05/2018

Contrôle des acquis Contrôle des acquis

9. la variable A contient 10.5 , Qu'est-ce que la ligne 10. On souhaite récupérer un nombre décimal entré
suivante affiche ? au clavier, quelle ligne est correcte?
printf("A = %d ",A); a) scanf("%f", nombreDecimal);
a) A = %d b) scanf("%d", nombreDecimal);
b) A = 10.5 c) scanf("%lf", *nombreDecimal);
c) A = 10 d) scanf("%f", &nombreDecimal);
d) A = d , A

40 41

19
16/05/2018

Contrôle des acquis Contrôle des acquis/ Réponses

1. b
11. Combien vaudra Res après les opérations suivantes ? 2. c
int A = 4;
3. b
Res = 5 + A++;
Res += 2 + A; 4. c
Res -= 4 + (--A) 5. c
Res = Res + A++; 6. b
a) 9
7. c
b) 10
c) 12
8. a
d) 14 9. c
10. d
11. c
42 43

20
16/05/2018

Contrôle des acquis Contrôle des acquis

#include<stdio.h> #include<stdio.h>
int main(void) int main(void)
{ int a=2, b=3, c=4; { int a=2, b=3, c=4;
printf("opération a+++b égale %d\n",a+++b); printf("operation ++a+b égale %d\n",++a+b);
printf("la valeur de a est %d et la val de b est %d\n",a,b); printf("la valeur de a est %d et la val de b est %d\n",a,b);
return 0; return 0;
} }

44 45

21
16/05/2018

Contrôle des acquis Contrôle des acquis

#include<stdio.h> #include<stdio.h>
int main(void) int main(void)
{ int a=2, b=3, c=4; { int a=2, b=3, c=4;
printf("operation a+--b égale %d\n",a+--b); printf("operation a+b-- égale %d\n",a+b--);
printf("la valeur de a est %d et la val de b est %d\n",a,b); printf("la valeur de a est %d et la val de b est %d\n",a,b);
return 0; return 0;
} }

46 47

22
16/05/2018

Les structures de contrôle

✓ if...else
Instructions de contrôle ✓ For
✓ While
et les tableaux en langage C ✓ Do while
✓ Switch
✓ Break
✓ Continue
✓ Goto

48 49

23
16/05/2018

Les structures de contrôle if...else Les structures de contrôle- Imbrication des instructions if

Écrire un programme de facturation avec remise. Il lit en


Syntaxe:
donnée un simple prix hors taxes et calcule le prix TTC
1. if ( expression ) Instruction1;
correspondant (avec un taux de TVA constant de 20 %). Il
2. if ( expression ) Instruction1
else Instruction2; établit ensuite une remise dont le taux dépend de la valeur
ainsi obtenue, à savoir :
● 0 % pour un montant inférieur à 1 000 Dh
Exemple: ● 1 % pour un montant supérieur ou égal à 1 000 Dh
If (x>y) max= x;//Assigne la plus grande valeur entre
Else max=y;//`x et y à la variable max. et inférieur à 2 000 Dh
● 3 % pour un montant supérieur ou égal à 2 000 Dh
Obs.: Accolades entre blocs
Indentation (c’est plus lisible) et inférieur à 5 000 Dh
Intégration des opérations logiques
● 5 % pour un montant supérieur ou égal à 5 000 Dh
50 51

24
16/05/2018

Les structures de contrôle- Imbrication des instructions if La boucle for


#define TAUX_TVA 20
main()
{
double ht, ttc, net, tauxr, remise ;
printf("donnez le prix hors taxes : ") ;
scanf ("%lf", &ht) ;
ttc = ht * ( 1. + TAUX_TVA/100.) ;
if ( ttc < 1000.) tauxr = 0 ;
else if ( ttc < 2000 ) tauxr = 1. ;
else if ( ttc < 5000 ) tauxr = 3. ;
Syntaxe:
else tauxr = 5. ;
remise = ttc * tauxr / 100. ; for (expression1 ; expression2 ; expression3)
net = ttc - remise ;
printf ("prix ttc %10.2lf\n", ttc) ; Instruction;
printf ("remise %10.2lf\n", remise) ;
printf ("net à payer %10.2lf\n", net) ; }
52 53

25
16/05/2018

La boucle for La boucle for

/* Ceci un exemple de la boucle for */


#include <stdio.h> Écrivez un programme en langage C
#define NUMBER 22 qui lit une valeur entières (N) au clavier
main() et qui affiche sa factorielle
{
N! = 1*2*3*...*(N-1)*N
int count, total = 0;
for(count =1; count <= NUMBER; count++)
total += count;
printf(“Bonjour tout le monde!!!\n”);
printf(“Le total est %d\n”, total);
}
54 55

26
16/05/2018

La boucle while La boucle while

/* Boucle while */
#include <stdio.h>
#define NUMBER 22
main()
{
int count = 1, total = 0;

while(count <= NUMBER)


{
Syntaxe: printf(“Bonjour le langage C !!!\n”);
while (expression) Instruction count++;
total += count;
}
printf(“Le total est %d\n”, total);
Il s’agit d’une boucle : tant que expression est vraie, Instruction est exécutée. }

56 57

27
16/05/2018

La boucle do…while La boucle do…while

/* Boucle do while */
#include <stdio.h>
#define NUMBER 22
main()
{
int count = 1, total = 0;

do
{
printf(“Vive le langage C !!!\n”);
count++;
Syntaxe: total += count;
do instruction } while(count <= NUMBER);
while (expression); printf(“Le total est %d\n”, total);
}
58 59

28
16/05/2018

Les instructions de branchement inconditionnel : break Les instructions de branchement inconditionnel : continue

Syntaxe: Syntaxe:
break; continue ;
Exemple : Exemple:
main()
{ main()
int i ; { int i ;
for ( i=1 ; i<=5 ; i++ )
{ printf ("iteration %d\n", i) ; for ( i=1 ; i<=5 ; i++ )
printf ("bonjour\n") { printf ("début tour %d\n", i) ;
if ( i==3 ) break ;
printf ("fin tour %d\n", i) ; if (i<4) continue ;
} printf ("bonjour\n") ;
printf ("après la boucle") ;
} }}
60 61

29
16/05/2018

Les instructions de branchement inconditionnel : goto


Instruction Switch

Syntaxe:
Syntaxe:
goto etiquette ;
Switch (expression) {
Exemple: case constante1 : instructions1;
for(...)
for(...) case constante2 : instructions2;
If (erreur)
goto TRAITEMENT_ERREUR;
...
... case constante n : instructionsn ;
TRAITEMENT_ERREUR: //le traitement d’erreur est effectue ici
printf("Erreur:...."); default : liste d′ instructions
...
}
Cette instruction est un instruction if généralisée.
62 63

30
16/05/2018

Instruction Switch- sans break Instruction Switch- avec break

/* Utilisation de switch case */ /* Utilisation de switch case */


main() main()
{ {
int n ; int n ;
printf ("donnez un entier : ") ; printf ("donnez un entier : ") ;
scanf ("%d", &n) ; scanf ("%d", &n) ;
switch (n) switch (n)
{ case 0 : printf ("nul\n") ; { case 0 : printf ("nul\n") ; break ;
case 1 : printf ("un\n") ; case 1 : printf ("un\n") ; break ;
case 2 : printf ("deux\n") ; case 2 : printf ("deux\n") ; break ;
} }
printf ("au revoir\n") ; printf ("au revoir\n") ;
} }

64 65

31
16/05/2018

Quick QCM Fonctions en C

Vérifier la syntaxe des instructions suivantes :


a) If(x<y) { } • Plusieurs fonctions pré-définies:
– printf(), sin(), atoi(), …
b) If(x<y) { i = 1 ; }
c) If(x<y) { ; } • Le prototype de ces fonctions sont dans fichiers
d’entête (header file)
d) if(x<y){;};; – printf() dans stdio.h
e) If(x<y) { i = 5 ; k = 3 } – sin() dans math.h

f) If(x<y) { i = 5 , k = 3 }
g) If(x<y) { i = 5 ; k = 3 } ;
66 67

32
16/05/2018

Fonctions en C Fonctions en C

/* Routine de calcul du maximum */


int imax(int n, int m)
• Extrait de stdio.h { Déclaration de la fonction
int max;
/****************************************************************/
/* FORMATTED INPUT/OUTPUT FUNCTIONS */ if (n>m) Variable locale
/****************************************************************/ max = n;
extern int fprintf(FILE *_fp, const char *_format, ...); else
extern int fscanf(FILE *_fp, const char *_fmt, ...); max = m; Valeur retournée par la fonction
extern int printf(const char *_format, ...); return max;
extern int scanf(const char *_fmt, ...); }
extern int sprintf(char *_string, const char *_format, ...);
extern int sscanf(const char *_str, const char *_fmt, ...);
extern int vfprintf(FILE *_fp, const char *_format, char *_ap);
extern int vprintf(const char *_format, char *_ap);
extern
68 int vsprintf(char *_string, const char *_format, char *_ap); 69

33
16/05/2018

Fonctions en C Fonctions en C

• Fonctions sans arguments et ne retournant pas de valeur.


– void fonction(void)
• Les fonctions exigent la déclaration d’un
prototype avant son utilisation:
• Fonctions avec arguments ne retournant pas de valeur.
– void fonction(int x, int y, char ch) /* Programme principal */
#include <stdio.h>
int imax(int,int);
main() Prototype de la fonction
{ … }

int imax(int n, int m)


{ … } La fonction est définie ici

70 71

34
16/05/2018

Fonctions en C Les tableaux

/* Programme principal */ Un tableau est un ensemble fini d’ éléments de même type, stockés en
#include <stdio.h> mémoire à des adresses contigües.
• La récursivité void up_and_down(int);
main()
{
up_and_down(1);
Niveau 1 }
Niveau 2
Niveau 3 void up_and_down(int n)
Niveau 4 {
printf(“Niveau %d\n", n);
NIVEAU 4 if (n<4) Syntaxe
NIVEAU 3 up_and_down(n+1); Type nom-du-tableau[nombre- elements];
NIVEAU 2 printf(“NIVEAU %d\n”, n); Exemple
} Int tab[10];
NIVEAU 1
72 73

35
16/05/2018

#include <stdio.h>
Les tableaux main()
{ int i, som, nbm ;
#define N 10 float moy ;
Int main(){ int t[20] ;
Int tab[N];
Int i; for (i=0 ; i<20 ; i++)
... { printf ("donnez la note numéro %d : ", i+1) ;
for(i=0; i<N; i++) scanf ("%d", &t[i]) ;
printf("tab[%d]=%d\n",i, tab[i]); }
...}
Voici les points importants a retenir: for (i=0, som=0 ; i<20 ; i++) som += t[i] ;
• 1. On accède a un élément du tableau en lui appliquant l’operateur []; moy = som / 20 ;
• 2. les index des éléments d’un tableau vont de 0 a nombre-elements-1 printf ("\n\n moyenne de la classe : %f\n", moy) ;
• 3. la taille d’un tableau DOIT être connue statiquement par le compilateur. for (i=0, nbm=0 ; i<20 ; i++ )
• Impossible donc d écrire int[n] ou n est une variable. if (t[i] > moy) nbm++ ;
printf ("%d élèves ont plus de cette moyenne", nbm) ;
74
} 75

36
16/05/2018

Initialisation d’un tableau Réservation automatique

type nom-du-tableau[N]= {const1,const2,..., constN} ;


Int T []={1,2,3,4,5};//réservation de 5*sizeof(int)octets
Par exemple:
#define N 5
Float B[]={-1.05,3.3,87e-5,-1.3E4};
//réservation de 4*sizeof(float)octets
Int t[N]={14,27,3,18,81};
Int main(){
Int i;
for(i=0;i<N;i++)
printf("t[%d]=%d\n",i , t[i]);
...}
76 77

37
16/05/2018

Cas particulier des tableaux de caractères Cas particulier des tableaux de caractères

#include<stdio.h>
Un tableau de caractères peut être initialise comme une liste de
Int main(){
caractères.
Char t1[7]="bonjour";//sans’\0’
Exemple: char ch[3]={’a’,’b’,’c’}; Char t2[]=" bonjour";//avec’\0’
Printf ("t1(de taille%i) = %s\n", sizeof(t1) / sizeof(char), t1);
–On peut aussi initialiser un tableau de caractère par une chaine Printf ("t2(de taille%i )= %s\n", sizeof(t2) / sizeof(char), t2);
littérale: return0;
Char ch[8]="exemple"; }
Ce programme renverra:
t1(de taille 7)=bonjour
t2(de taille 8)=bonjour

En effet, pour t1, toute la zone mémoire est affichée jusqu’à


ce que le caractère nul soit rencontre.
78 79

38
16/05/2018

Tableaux multidimensionnels Tableaux multidimensionnels

#include<stdio.h>
Un tableau a deux dimensions se déclare donc de la manière #define L 3
suivante: #define C 2
Int mat[10][20]; int tab[L][C]={{1,2},{14,15},{100,200}};
Int main(){
On accède a un élément du tableau par l’expression mat[i][j]. Int i, j;
for(i=0; i<L; i++){
for(j=0; j<C; j++)
Initialisation
Printf ("tab[%d][%d]=%d\n", i, j, tab[i][j]);
Int tab [3] [4] = { { 1, 2, 3, 4 } , }
{ 5, 6, 7, 8 }, return0;
{ 9,10,11,12 } } }
int tab [3] [4] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 }

80 81

39
16/05/2018

Contrôle des acquis Contrôle des acquis

1. Combien de fois passe-t-on dans la boucle suivante ?


2. Combien de fois passe-t-on dans la boucle suivante ?
int Cpt = 10;
int Cpt = 10;
do { cpt++; printf("bonjour \n"); } while ( Cpt < 10) ;
while (( Cpt <11 ) { printf("bonjour\n"); }
a) 0 a) 0
b) 1 b) 1
c) 9
d) 10 c) 10
d) c'est une boucle infinie

82 83

40
16/05/2018

Contrôle des acquis Contrôle des acquis

3. Combien de fois passe-t-on dans la boucle suivante ? 4. Comment inclure une bibliothèque standard ?
for ( compteur = 2; compteur < 9; compteur += 2 ) a) #include <windows.h>
a) 4
b) #include "windows.h"
b) 5
c) #include [windows.h]
c) 7
d) #include {windows.h}
d) 8

84 85

41
16/05/2018

Contrôle des acquis Contrôle des acquis

5. Que donne le code suivant : &A ? 6. Lequel de ses codes crée un tableau de 5 entiers ?
a) L'adresse de la variable A a) int Tab(5);
b) La valeur de la variable A b) int *Tab[5];
c) La valeur de la variable sur laquelle pointe A c) int Tab[4];
d) int Tab [5]

86 87

42
16/05/2018

Contrôle des acquis Contrôle des acquis/ Réponses

7. Quelle est la bonne méthode d'initialisation d'un


tableau d'entiers ?
1. b
a) int tableau [4] = 10,5,8,9; 2. d
b) int tableau [4] = [ 10,5,8,9 ] ; 3. a
c) int tableau [4] = {10,5,8,9}; 4. a
d) int tableau [4] = (10,5,8,9);
5. a
6. d
7. c
88 89

43
16/05/2018

Problématique

int x;
Pointeurs et Chaines de x=20 ;
Caractères en langage C
Printf (la valeur de x=%d\n, x ); 20
Printf (l’adresse de x=%d\n, &x );

&x x
90 91

44
16/05/2018

Problématique

void incrementer (int x, int y)


{ x++;
y++;
}
int main(void){
int a=2, b=4;
incrementer(a, b);
printf("la valeur de a=%d\n", a );
printf("la valeur de b=%d\n", b );
return 0;
}
92 93

45
16/05/2018

Syntaxe Syntaxe

le langage C permet de manipuler des adresses par Exemple


l’intermédiaire des variables nommées pointeurs.
int *x;
Un pointeur est une variable de type adresse
int * pointeur1;

La syntaxe de déclaration char *pointeur2


Type *nom_pointeur int * pointeur3, *pointeur4;
int *pointeur5, variable1;
float *y;
void * //Pointeurs génériques

94 95

46
16/05/2018

Comment ça marche Quelques exemples

int *p ; int * ad1, * ad2, * ad ;


Int n = 10, p = 20 ;
int x ; 20
x= 20 ; Considérons maintenant ces instructions :
ad1 = &n ;
p = &x ; *p p ad2 = &p ;

*p = 30 ; &x x * ad1 = * ad2 + 2 ;

96 97

47
16/05/2018

Quelques exemples transmission par adresse avec un pointeur

main()
#include <stdio.h> {
int main (void) void echange (int * ad1, int * ad2) ;
int a=10, b=20 ;
{ printf ("avant appel %d %d\n", a, b) ;
echange (&a, &b) ;
int n=10; printf ("après appel %d %d", a, b) ;
}
int *p=&n;
void echange (int * ad1, int * ad2)
printf("%d\n", p); { int x ;
x = * ad1 ;
printf("%d\n",*p); * ad1 = * ad2 ;
* ad2 = x ;
} }
98 99

48
16/05/2018

Initialisation d’un pointeur Quelques exemples

Comme toute variable, un pointeur doit être initialise !:


Int main(){
✓ Affectation à l’adresse d’une autre variable de p Int i=14;
Int *p;
int*p1,*p2;
Int i=14; //supposons que i se trouve a l’adresse 0x352C p=&i; // p contient l’adresse de i(0x352C)
p1=&i; //affectation de l’adresse de i à p1, soit 0x352C Printf ("*p=%d\n",*p); //affiche "*p=14"
p2=p1; //affectation de p1 à p2: }
//p2 contient aussi l’adresse de i Pour résumer après les instructions précédentes:
– i désigne le contenu de i (soit 14)
✓ affectation de p à la valeur NULL (cette valeur est définie
dans le fichier stddef.h). Exemple: int*p=NULL; – &i désigne l’adresse de i (soit 0x352C)
– p désigne l’adresse de i (soit 0x352C)
✓ affectation directe de *p (la zone mémoire pointée par p). – *p désigne le contenu de i (soit 14)
100 101

49
16/05/2018

Tableaux et pointeurs Tableaux et pointeurs


void affiche(int *tableau, int tailleTableau);
int main(void ) #include <stdio.h>
{ #include <stdlib.h>
int tableau[4] = {10, 15, 3};
affiche(tableau, 4); 10 int main()
return 0; 15 {
3 int t[]={10, 20, 30, 40, 50, 60};
} 0
void affiche(int *tableau, int tailleTableau) int *p;
{
int i; for (p=t; p <&t[6]; p++)
for (i = 0 ; i < tailleTableau ; i++) printf(« bonjour =%d\n",*p);
{ printf("%d\n", tableau[i]); } return 0;
} }
102 103

50
16/05/2018

Tableaux et pointeurs Tableaux et pointeurs


#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
int main() int main()
{ {
int t1[8], t2[5]; int t1[8], t2[5];
int *p1=&t1[7], *p2 = &t1[2]; int *p1=&t1[7], *p2 = &t2[2];

ptrdiff_t diff=p1-p2; ptrdiff_t diff=p1-p2;


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

ptrdiff_t diff=p2-p1; ptrdiff_t diff=p2-p1;


printf("%d\n",diff); printf("%d\n",diff);
} 104
} 105

51
16/05/2018

En résumé Les chaînes de caractères

✓ Chaque variable est stockée à une adresse précise en


mémoire. Une « chaîne de caractères », c'est un jargon de

✓ Les pointeurs sont semblables aux variables, à ceci près programmation pour désigner… du texte, tout simplement !.
qu'au lieu de stocker un nombre ils stockent l'adresse à Une chaîne de caractère doit impérativement contenir un
laquelle se trouve une variable en mémoire.
caractère spécial à la fin de la chaîne, appelé « caractère de
✓ Si on place un symbole & devant un nom de variable, on fin de chaîne ».
obtient son adresse au lieu de sa valeur (ex. : &age).
Ce caractère s'écrit '\0'.
✓ Si on place un symbole * devant un nom de pointeur , on
obtient la valeur de la variable stockée à l'adresse indiquée
par le pointeur .
106 107

52
16/05/2018

Création et initialisation de la chaîne Création et initialisation de la chaîne

char chaine[6];
// Tableau de 6 char pour stocker S-a-l-u-t + le \0 int main(void )
{
chaine[0] = 'S';
chaine[1] = 'a'; char chaine[] = "Salut";
chaine[2] = 'l'; // La taille du tableau chaine est automatiquement calculée
chaine[3] = 'u'; printf("%s", chaine);
chaine[4] = 't';
chaine[5] = '\0'; return 0;
}

108 109

53
16/05/2018

Récupération d'une chaîne via un scanf Fonctions de manipulation des chaînes

int main(int argc, char *argv[])


Pensez à inclure string.h
{
char nom[100]; #include <string.h>
printf("Comment t'appelles-tu ? ");
scanf("%s", &nom);
printf("Salut %s, je suis heureux de te rencontrer !", nom);
return 0;
}

110 111

54
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes


int main(int argc, char *argv[])
{
strlen : calculer la longueur d'une chaîne char chaine[] = "Salut";
Int size_t = strlen(const char chaine[]); int longueurChaine = 0;
// On récupère la longueur de la chaîne dans longueurChaine
longueurChaine = strlen(chaine);
// On affiche la longueur de la chaîne

printf("La chaine %s fait %d caracteres de long",


chaine, longueurChaine);
return 0;
112
} 113

55
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes

strcpy : copier une chaîne dans une autre char chaine1[10], chaine2[10];
char* strcpy(char Chaine1[], const char chaine2[]); printf("saisissez la chaine 1\n");
scanf("%s", &chaine1);
strcpy(chaine2, chaine1);
printf("le contenu de la chaine 2 après la copié est
%s\n",chaine2);

114 115

56
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes

strcat : concaténer 2 chaînes char chaine1[10]="bonjour",chaine2[10]="ali";


chaine1 = "Bonjour "
chaine2 = " ali" printf("les deux chaines après concaténation %s\n",
strcat(chaine1, chaine2));
char* strcat(char* chaine1, const char* chaine2);

116 117

57
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes

int strcmp(const char* chaine1, const char* chaine2);


char chaine1[10]="bonjour",chaine2[10]="bonjour";
strcmp : comparer 2 chaînes
If (strcmp(chaine1,chaine2))
Il est important de récupérer ce que la fonction renvoie. En
printf("les deux chaine ne sont pas identiques\n");
effet, strcmp renvoie :
else
printf("les deux chaine sont identiques\n");
✓ 0 si les chaînes sont identiques ;
✓ une autre valeur (positive ou négative) si les chaînes sont
différentes.
118 119

58
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes


int main(int argc, char *argv[])
strchr : rechercher un caractère {
char chaine[] = "Texte de test", *suiteChaine = NULL;
char* strchr(const char* chaine, int caractereARechercher); suiteChaine = strchr(chaine, 'd');

if (suiteChaine != NULL) // Si on a trouvé quelque chose

{
printf("Voici la fin de la chaine a partir du premier d :%s",
suiteChaine);
}

return 0;
}
120 121

59
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes

Variante
strstr : rechercher une chaîne dans une autre

Il existe une fonction strrchr strictement identique à


char* strstr(const char* chaine, const char* chaineARechercher);
strchr, sauf que celle-là renvoie un pointeur vers le
dernier caractère qu'elle a trouvé dans la chaîne plutôt
que vers le premier.

122 123

60
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes

int main()
{ sprintf : écrire dans une chaîne
char *suiteChaine;
// On cherche la première occurrence de "test" dans "Texte de test" : Cette fonction se trouve dans stdio.h contrairement aux
suiteChaine = strstr("Texte de test", "test");
if (suiteChaine != NULL)
autres fonctions que nous avons étudiées jusqu'ici, qui
{ étaient dans string.h.
printf("Premiere occurrence de test dans Texte de test :
%s\n", suiteChaine);
}
return 0;
}

124 125

61
16/05/2018

Fonctions de manipulation des chaînes Fonctions de manipulation des chaînes

#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) strpbrk : premier caractère de la liste
{ char* strpbrk(const char* chaine, const char* caractere);
char chaine[100];
int age = 15;
// On écrit "Tu as 15 ans" dans chaine
sprintf(chaine, "Tu as %d ans !", age);
// On affiche chaine pour vérifier qu'elle contient bien cela :
printf("%s", chaine);
return 0;
}

126 127

62
16/05/2018

Contrôle des acquis Contrôle des acquis

1. Qu'affichera le code suivant ?


int N = 65; 2. Qu'est-ce qu'une chaine de caractères ?
char lettre = N; a) Une variable char
printf ("%d", lettre);
b) Un tableau de char
a) 65
c) Un tableau d'int
b) N
d) Un tableau de long
c) A
d) Provoque une erreur

128 129

63
16/05/2018

Contrôle des acquis Contrôle des acquis

3. Comment saisir une chaine de caractères (


4. Quelle fonction donne la longueur d'une chaine de
déclarée par : char Chaine[100] ) ?
caractères ?
a) scanf ("%c" , chaine);
a) LongueurChaine();
b) scanf ("%s" , chaine);
b) strlen();
c) scanf ("%c" ,&chaine);
c) len();
d) scanf ("%s" , &chaine);
d) taille();

130 131

64
16/05/2018

Contrôle des acquis Contrôle des acquis

Écrire un programme qui lit au clavier un mot (d’au plus

1. a 30 caractères) et qui l’affiche à l’envers.

2. b
3. b
4. b

132 133

65
16/05/2018

Contrôle des acquis

Écrire un programme déterminant le nombre de lettres « e »


(minuscules) présentes dans un texte de moins d’une ligne Retour sur les fonctions en
(supposée ne pas dépasser 132 caractères) fourni au clavier
langage C

134 135

66
16/05/2018

introduction introduction

main() Programme typique en C


{
int n ; include
printf ("donnez un entier : ") ; Main() toujours la
scanf ("%d", &n) ; 1ère fonction appelée
switch (n) main()
{ case 0 : printf ("nul\n") ; break ;
case 1 : printf ("un\n") ; break ; fonction a() instructions
case 2 : printf ("deux\n") ; break ;
}
printf ("au revoir\n") ; fonction b() instructions
}

137
instructions
136 137

67
16/05/2018

Définition Exemple

int somme (int a, int b, int c)


type_retour fonction (type1 par1, type2 par2, /* ..., */ typeN parN) {
{ int variable1=0 ;
/* Déclarations de variables ... */ variable1=a+b+c ;
return variable1 ;
/* Instructions ... */
}
}
int somme (int a, int b, int c)
{
L'exécution d'une fonction se termine soit lorsque l'accolade fermante est return a+b+c;
atteinte, soit lorsque le mot clef return est rencontré.

}
138

68
16/05/2018

Déclaration par prototype L’instruction return

L’instruction return peut mentionner toutes expressions


type_retour nom_fonction (type1, type2, /* ..., */ typeN);
float fonction1(float x, int b, int c)
{ return (x * x + b * x + c) ; }

double fonction2(double u, double v)


{
Exemple : double s ;
s=u+v;
int somme(int, int, int);
if (s>0) return (s) ;
else return (-s)
}
140

69
16/05/2018

Cas des fonctions sans valeur de retour/sans arguments En C, les arguments sont transmis par valeur

#include <stdio.h>
main()
void sansval (int n) { void echange (int a, int b) ;
int n=10, p=20 ;
void sansval (int) ; printf ("avant appel : %d %d\n", n, p) ;
echange (n, p) ;
float tirage (void) printf ("après appel : %d %d", n, p) }
void echange (int a, int b)
float tirage (void) ; {
int c ;
printf ("début echange : %d %d\n", a, b) ;
void message (void) c=a;
a=b;
void message (void) ; b=c;
printf ("fin echange : %d %d\n", a, b) ;
}

70
16/05/2018

Évaluation des arguments Évaluation des arguments

La norme du langage ne spécifie pas l'ordre d'évaluation des arguments.


Il faut donc faire particulièrement attention aux effets de bords. Ce code contient une erreur volontaire !
#include <stdio.h>
#include <stdio.h>
int fonction(int, int);
int somme(int a, int b)
int g(void);
{return a + b; }
int h(void);
int main(void)
int test(void)
{
{
int i = 0;
return fonction(g(), h());
printf("%d\n", somme (++i, i) );
}
return 0;
}
144 145

71
16/05/2018

Évaluation des arguments La portée des variables

La portée est définie selon l’endroit où on déclare une variable,


#include <stdio.h> celle-ci pourra être accessible (visible) partout dans le code ou
int fonction(int, int); seulement dans une partie de celui-ci .
int g(void);
int h(void);

int test(void)
{ Variables variables
int a,b; globales locales
a = g();
b = h();
return fonction(a, b);
} 146 147

72
16/05/2018

variables globales variables locales

#include <stdio.h> Les variables locales ne sont connues qu’à l’intérieur de


int STATUS; la fonction où elles sont déclarées.
void A(...){ Leur portée est donc limitée à cette fonction.
...
if (STATUS>0) void Fonction4() {
STATUS--;
else char nom[20];
... } printf("Introduisez votre nom : ");
void B(...) { scanf("%s",&nom);
...
STATUS++; printf("Bonjour %s !\n", nom);
... } }
148 149

73
16/05/2018

variables locales Niveaux des variables


int nb_elements; // niveau 0
Attention ! Une variable déclarée à l’ intérieur d’un size_t taille; // niveau 0
int main()
bloc cache toutes les variables du même nom des blocs { int i, j; // niveau 1
qui l’entourent. char c; // niveau 1
{ Complexe c1, *c2; // niveau 2
int i; // niveau 2
Exemple : if ( ... )
int X ; {
char car; // niveau 3
int fonction3 (int A) ... } }
{ ... }
int ent; // niveau 0
double X; void f( void )
... {
long i; // niveau 1
} ... }
150

74
16/05/2018

Les fonctions récursives Conversion automatique

Les fonctions définies en C ont la propriété de récursivité,


c’est à dire la capacité de s’appeler elle-même.
double fonction4 (double x, double y);
long fac (int n) …
{ int A, B;
if (n>1) return (fac(n-1)*n) ; ...
else return(1) ; A = fonction4 (B, 2);
}

152 153

75
16/05/2018

#include <stdio.h>
Nombre variable d'arguments #include <stdarg.h>
void test(int nbpar, ...)
#include <stdarg.h> { va_list adpar ;
int parv, i ;
void ma_fonction(type1 arg1, type2 arg2, ...) printf ("nombre de valeurs : %d\n", nbpar) ;
{... } va_start (adpar, nbpar) ;
<stdio.h> for (i=1 ; i<=nbpar ; i++)
va_start va_arg { parv = va_arg (adpar, int) ;
printf ("argument variable : %d\n", parv) ;
va_list va_end }} premier test
main() nombre de valeurs : 3
{ printf ("premier test\n") ; argument variable : 15
Ce code contient une erreur volontaire ! test (3, 15, 30, 40) ; argument variable : 30
printf ("\ndeuxième test\n") ; argument variable : 40
void ma_fonction(...); test (0) ; } deuxième test
nombre de valeurs : 0
154 155

76
16/05/2018

La fonction main Valeur de retour

Exemple: Voici un petit programme très simple qui


affiche la liste des paramètres passés au programme
test.exe hello world !
int main (void) { /* ... */ } lorsqu'il est appelé:
paramètre 0 : ./test
Test.c paramètre 1 : hello
#include <stdio.h> paramètre 2 : world
int main(int argc, char * argv[]) paramètre 3 : !
int main(int argc, char * argv[]) { /* ... */ } {
int i;
for (i = 0; i < argc; i++)
printf("paramètre %d: %s\n", i, argv[i]);
Par convention :
EXIT_FAILURE
✓ argc désigne le nombre d’arguments transmis au moment du return 0;
lancement de l’exécutable ;
✓ argv désigne le vecteur contenant les différents arguments ;
} retourne 0
(ou EXIT_SUCCESS)
156 157

77
16/05/2018

Contrôle des acquis Contrôle des acquis

Écrire une fonction, nommée f2, qui affiche


Écrire une fonction, nommée f1, se contentant
d’afficher « bonjour« (elle ne possèdera aucun « bonjour» un nombre de fois égal à la

argument ni valeur de retour)? valeur reçue en argument (int) et qui ne


renvoie aucune valeur

158 159

78
16/05/2018

Contrôle des acquis Contrôle des acquis

Qu’affiche le programme suivant ?


int n=5 ;
Écrire une fonction, nommée f3, qui fait main()
{
la même chose que f2, mais qui, de plus, void fct (int p) ;
int n=3 ;
renvoie la valeur (int) 0 fct(n) ;
}
void fct(int p)
{
printf("%d %d", n, p) ;
}
160 161

79
16/05/2018

La gestion dynamique de la mémoire La gestion dynamique de la mémoire

Les types des données dans la RAM :


✓ Les données statiques occupent un emplacement bien Int x;
défini lors de la compilation. x=20 ;
✓ Les données dynamiques n’ont pas non plus de taille x
définie a priori. Leur création ou leur libération dépend, Int x[3]; 20 x[0]
cette fois, de demandes explicites .

&x x[1]

Chaque case de 4octet


162 x[2] 163

80
16/05/2018

La gestion dynamique de la mémoire La gestion dynamique de la mémoire

D’une manière générale, l’emploi de données statiques


int n; int x[?];
présente certains défauts intrinsèques. à titre d’exemple :
scanf("%d", &n);
✓ Les données statiques ne permettent pas de définir
int x[n];
des tableaux de dimensions variables;
✓ La gestion statique ne se prête pas aisément à la
mise en œuvre de listes chaînées, d’arbres binaires,...

164

81
16/05/2018

La gestion dynamique de la mémoire La fonction malloc

#include <stdlib.h>
D’une manière générale, le prototype de malloc
.....
est présenté comme suit : char * adr ;
.....
void * malloc (size_t taille)
adr = malloc (50) ;
.....
for (i=0 ; i<50 ; i++) *(adr+i) = 'x' ;
stdlib.h

166 167

82
16/05/2018

La fonction malloc free: libération de mémoire

#include <stdio.h>
allocation de 100 octets en 06AC
#include <stdlib.h>
Second exemple allocation de 50 octets en 0714
main() libération de 100 octets en 06AC
{ allocation de 40 octets en 06E8
int* adr ; char * adr1, * adr2, * adr3 ;
..... adr1 = malloc (100) ;
printf ("allocation de 100 octets en %p\n", adr1) ;
adr = malloc (100 * sizeof(int)) ; adr2 = malloc (50) ;
..... printf ("allocation de 50 octets en %p\n", adr2) ;
for (i=0 ; i<100 ; i++) *(adr+i) = 1 ; free (adr1) ;
printf ("libération de 100 octets en %p\n", adr1) ;
adr3 = malloc (40) ;
printf ("allocation de 40 octets en %p\n", adr3) ;
}
168 169

83
16/05/2018

Autres outils de gestion dynamique : calloc et realloc Autres outils de gestion dynamique : calloc et realloc

La fonction calloc Exemple :


void * calloc ( size_t nb_blocs, size_t taille ) (stdlib.h) int* ptr = calloc ( 5, sizeof(int) );
*ptr = 3; /* premier entier : 3 */

ptr[0] = 3; /* équivaut à *ptr = 3; */


ptr[1] = 1; /* équivaut à *(ptr+1) = 1; */
Contrairement à ce qui se passait avec
malloc, où le contenu de l’espace ptr[2] = 4; /* équivaut à *(ptr+2) = 4; */
mémoire alloué était imprévisible, calloc
remet à zéro chacun des octets de la zone
ainsi allouée.
170 171

84
16/05/2018

Autres outils de gestion dynamique : calloc et realloc Autres outils de gestion dynamique : calloc et realloc

Ce code contient une erreur volontaire !


La fonction realloc
void f(void)
void * realloc (void * pointeur, size_t taille ) {
int tab[10];
/* ... */
int *ptr = realloc(tab, 20 * sizeof(int));
permet de modifier la taille d’une zone préalablement /* ... */
}
allouée (par malloc, calloc ou realloc).

172

85
16/05/2018

Contrôle des acquis Contrôle des acquis

1. Que se passe-t-il en mémoire avec le code suivant : 2. Comment initialiser un pointeur sur un
malloc(sizeof(int) * 25); ? tableau de 10 char ?
A. Cela réserve de la mémoire pour un entier de 25 octets A. p = malloc (10);
B. Cela réserve de la mémoire pour un tableau de 25 entiers B. p = (char *) malloc(10,1);
C. Cela réserve de la mémoire pour un tableau de 25 octets
C. p = (char *) malloc (sizeof(10*char));
D. Cela réserve de la mémoire pour un tableau de 25 cchar
D. p = (char *) malloc(10 * sizeof(char));

86
16/05/2018

Contrôle des acquis Contrôle des acquis

3. On souhaite modifier la taille d'un tableau T P pointe sur un tableau de 10 entiers, on souhaite
d'entiers, passer de 10 à 11 entiers ? libérer la mémoire qu'il occupe. Comment faire ?
A. T = (int *) malloc (11* sizeof( int ) ); A. P = NULL;
B. T = (int *) malloc (11); B. *P = 0;
C. T= (int *) realloc (T, 11* sizeof( int ) ); C. free( P );
D. T = (char *) realloc( 11 * sizeof (int )); D. free ( *P );

87
16/05/2018

Contrôle des acquis/ Correction

1. b Les structures
2. d et les énumérations en
3. c langage C
4. c

179

88
16/05/2018

Introduction Déclaration d’une structure

Les types utilisés dans le langage C sont :


struct ma_structure {
❖ les types standards existant : int, flaot, double,… type1 champ1;
type2 champ2;
❖ les types utilisateurs ...
✓ définis par le développeur
✓ utilisés comme des types standards
typeN champN;
} var1, var2, ..., varM;

Les structures -les énumérations


180 181

89
16/05/2018

Déclaration d’une structure Déclaration d’une structure

struct enreg struct enreg art1 ;


{ int numero ; struct enreg art1, art2 ;
struct enreg art1 ;
int qte ; struct enreg
float prix ; { int numero ;
int qte ;
} ; float prix ;
} art1, art2 ;
182 183

90
16/05/2018

Utilisation d’une structure Utilisation des champs d’une structure

En C, on peut utiliser une structure de deux manières :


● en travaillant individuellement sur art1.numero = 15 ;
chacun de ses champs ; printf ("%f", art1.prix) ;
● en travaillant de manière globale sur scanf ("%f", &art2.prix) ;
l’ensemble de la structure.
art1.numero++;

184 185

91
16/05/2018

Initialisations de structures Utilisation globale d’une structure

Voici un exemple d’initialisation de notre struct enreg art1, art2 ;


structure art1, au moment de sa déclaration : art1 = art2 ;
struct enreg art1 = { 100, 285, 2000 } ; Une telle affectation globale remplace avantageusement :

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

92
16/05/2018

Définition des synonymes avec typedef Définition des synonymes avec typedef

La déclaration :
De même :
typedef int entier ; typedef int * ptr ;
signifie que entier est synonyme de int, de sorte que
signifie que ptr est synonyme de int *.
les déclarations suivantes sont équivalentes :
Les déclarations suivantes sont équivalentes :
int n, p ;
int * p1, * p2 ;
entier n, p ; ptr p1, p2 ;
188 189

93
16/05/2018

Application aux structures


Définition des synonymes avec typedef

struct enreg
{ int numero ;
typedef int vecteur [3] ;
int qte ;
les déclarations suivantes sont équivalentes : float prix ;
int v[3], w[3] ; };
typedef struct enreg s_enreg ;
vecteur v, w ;
s_enreg art1, art2 ;
190 191

94
16/05/2018

Application aux structures Application aux structures

ou encore, plus simplement : Exemple


typedef unsigned int octet;
typedef struct typedef double Matrice[4][4];
{ int numero ; typedef struct ma_structure * ma_struct;

int qte ; /* Utilisation */


octet nombre = 255;
float prix ;
Matrice identite = { {1,0,0,0}, {0,1,0,0}, {0,0,1,0},
} s_enreg ; {0,0,0,1} };
ma_struct pointeur = NULL;
s_enreg art1, art2 ;
192 193

95
16/05/2018

Application aux structures Pointeurs vers structures


int main()
{ typedef int e ; struct ma_struct * ma_variable;
struct formation{e id; int cof;};
struct formation f1,f2; ma_variable = malloc( sizeof(struct ma_struct) );

printf("donner une valeur de id de f1\n");


scanf("%d",&f1.id); (* ma_variable).champ
printf("donner une valeur de Coefficient f1\n");
scanf("%d",&f1.titre); Le raccourci pour l'accès aux champs d'un pointeur
f2=f1; vers structure :
printf(" les valeurs de f1 est %d et %d\n",f1.id,f1.titre);
printf(" les valeurs de f2 est %d et %d\n",++f2.id,--f2.titre); ma_variable->champ
return 0; }
194 195

96
16/05/2018

Pointeurs vers structures Structures et tableaux

typedef struct {
char nom[64]; Soit la déclaration suivante :
int age;
} etudiant; struct personne { char nom[30] ;
int main() { char prenom [20] ;
etudiant e;
etudiant *p = &e; float heures [31] ;
strcpy(e.nom, "ALI"); e.age = 18;
} employe, salesmen;
printf ("%s a %d ans\n", e.nom, e.age);
printf ("%s a %d ans\n", p->nom, p->age);
return 0; }
196 197

97
16/05/2018

Imbrication de structures Imbrication de structures

Les notations :
Enfin :
le cinquième élément employe.nom
employe.heures[4] représente l’adresse de ce tableau.
du tableau heures

employe.nom[0] premier caractère du


champ nom À titre indicatif, voici un exemple d’initialisation d’une
structure de type personne lors de sa déclaration :
l’adresse du struct personne emp = {"Ali", "amine", { 8, 7, 8, 6, 8, 0, 0, 8}};
&salesmen.heures[4] cinquième élément
du tableau heures
198 199

98
16/05/2018

Tableaux de structures Tableaux de structures

Voyez ces déclarations : Le trajectoire représente effectivement un tableau

struct point { char nom ; de 50 éléments du type point. Si i est un entier, la

int x ; notation :

int y ; traj[i].nom
}; représente le nom du point de rang i du tableau
struct point traj[50] ; traj. Il s’agit donc d’une valeur de type char.

200 201

99
16/05/2018

Contrôle des acquis Contrôle des acquis


Écrire un programme qui lit au clavier des main()
{ struct point { int num ;
informations dans un traj[5] de structures du float x ;
float y ; } ;
type point défini comme suit :
struct point traj[5] ; int i ;
struct point { int num ; for (i=0 ; i<5 ; i++)
{ printf ("numéro : ") ; scanf ("%d", &traj[i].num) ;
float x ; printf ("x : ") ; scanf ("%f", &traj[i].x) ;
printf ("y : ") ; scanf ("%f", &traj[i].y) ; }
float y ; }
printf (" **** structure fournie ****\n") ;
afficher à l’écran l’ensemble des informations for (i=0 ; i<5; i++)
printf ("numéro : %d x : %f y : %f\n",
précédentes. traj[i].num, traj[i].x, traj[i].y) ; }
202 203

100
16/05/2018

Contrôle des acquis Imbrication des Structures

struct date
Réaliser la même chose que dans { int jour ;
int mois ;
struct personne
l’exercice précédent, mais en prévoyant, int annee ;
{ char nom[30] ;
};
char prenom[20] ;
cette fois, un fonction pour la lecture des float heures [31] ;
struct date date_embauche ;
informations et une fonction pour struct date date_poste ;
} employe, salesmen;
l’affichage

204 205

101
16/05/2018

l’année d’embauche À propos de la portée du modèle de structure


Imbrication des Structures
correspondant à la
Les notations : structure employe. Il struct enreg
s’agit d’une valeur { int numero ; int qte ; float prix ;
employe.date_embauche.annee
de type int.
};
main ()
la date d’embauche { struct enreg x ;
employe.date_embauche correspondant à la ....
structure courant. }
fct ( ....)
affectation globale { struct enreg y, z ;
salesmen.date_embauche = employe.date_poste ; .... structure nommé enreg déclaré à un niveau global et
} accessible depuis les fonctions main et fct.
206 207

102
16/05/2018

Transmission d’une structure en argument d’une fonction Transmission d’une structure en valeur
de retour d’une fonction
#include <stdio.h>
struct enreg { int a ; float b ; } ;
main() struct enreg fct (...)
{ struct enreg x ;
void fct (struct enreg y) ; { struct enreg s ; /* structure locale à fct */
x.a = 1; x.b = 12.5;
printf ("\n avant appel fct : %d %f",x.a,x.b); .....
fct (x) ; return s ; /* dont la fonction renvoie la valeur */
printf ("\n au retour dans main : %d %f", x.a, x.b); }
void fct (struct enreg s) }
{ s.a = 0; s.b=1;
printf ("\n dans fct : %d %f", s.a, s.b);
}
208 209

103
16/05/2018

Contrôle des acquis Contrôle des acquis

1. Soient les déclarations suivantes : 2. Quelle est la différence entre un tableau et un


struct LIVRE { int nb_pages ; enregistrement ?
char langue[20], auteur[20], titre[20] ; a) Un tableau peut contenir des données de types
float prix; } L ; différents, tandis qu'un enregistrement ne le peut pas.
Comment accéder à un champ d'un enregistrement ? b) Un enregistrement peut contenir des données de types
a) auteur.L différents, tandis qu'un tableau ne le peut pas.
c) Tous deux peuvent contenir des données de types
b) L.auteur
différents, mais l'enregistrement occupe moins de
c) L : auteur place mémoire.
d) auteur.livre d) Tous deux peuvent contenir des données de types
e) livre.auteur différents, mais l'enregistrement permet un accès
mémoire plus rapide.
210 211

104
16/05/2018

Contrôle des acquis Contrôle des acquis


3. On considère la déclaration suivante :
struct photo { int prix ; char origine[20] ;int annee ; char 4. Quelle est la déclaration correcte d'un enregistrement ?
image[20] ;} ; a) struct LIVRE ( int nb_pages ; char langue[20],
struct photo COLLECTION [50]; auteur[20], titre[20] ; float prix; )
Comment accède-t-on à l'année du 3ème photo de la collection?
b) struct LIVRE { int nb_pages ; char langue[20],
a) COLLECTION [2, 2]
b) COLLECTION [2]. annee auteur[20], titre[20] ; float prix; };
c) COLLECTION [2, annee] c) struct LIVRE { int nb_pages ; char langue[20] ;
d) COLLECTION. annee [2]
auteur[20] ; titre[20] ; float prix; } ;
e) COLLECTION. annee

212 213

105
16/05/2018

Contrôle des acquis Contrôle des acquis/ Correction

5. Quelles sont les différentes affectations que l'on peut réaliser


sur ces variables structurées ?
Sachant que :
1. b
struct VOITURE { char Marque[20]; float Cylindree ; char
Couleur[20] ; char Nom[20] ; int Prix ; } ; 2. b
struct VELO { char Marque[20]; char Couleur[20] ; char
Nom[20] ; int Prix ; }; 3. b
struct VOITURE V1 ;
struct VELO V2 ; 4. c
a) V1 =V2 ;
b) V2 = V1 ; 5. e
c) V2.Marque = V2.Cylindree ;
d) V1.Cylindree := 1.5 ;
e) Aucune de celles proposées
214 215

106
16/05/2018

0 1
Propriétés du type énumération Propriétés du type énumération 2
Les énumérations sont des types définissant un ensemble
enum couleur {jaune, rouge, bleu, vert} ;
de constantes.

enum [nom] { Les constantes figurant dans les énumérations


énumérateur1, ont une valeur entière affectée de façon
énumérateur2, automatique par le compilateur en partant de 0
énumérateur3,
... par défaut et avec une progression de 1.
énumérateurn Les valeurs initiales peuvent être forcées lors de
};
la définition.
216 217

107
16/05/2018

Propriétés du type énumération Propriétés du type énumération


enum Plan {X, Y = 3, Z};
enum couleur_bis { jaune = 5, rouge, bleu, vert = 12, rose } ;
typedef enum Plan Planx;
/* jaune = 5, rouge = 6, bleu = 7, vert = 12, rose = 13 */ int main()
{
Planx var1 = X;
Les entiers négatifs sont permis comme dans :
Planx var2 = Y;
enum couleur_ter { jaune = -5, rouge, bleu, vert = 12 , rose } ; Planx var3 = Z;
/* jaune = -5, rouge = -4, bleu = -3, vert = 12, rose = 13 */
printf("var1 = %d\n", var1);
printf("var2 = %d\n", var2);
enum couleur_ter { jaune = 5, rouge, bleu, vert = 6, noir, violet } ; printf("var3 = %d", var3);
/* jaune = 5, rouge = 6, bleu = 7, vert = 6, noir = 7, violet = 8 */ return 0; }
218 219

108
16/05/2018

Programmation C/Mathématiques Racine carrée

il faut utiliser l'en-tête :


double sqrt ( double x );
#include <math.h>
#include <errno.h>//pour gérer les erreurs
Erreurs
EDOM : x est négatif.

220 221

109
16/05/2018

Exponentiations Logarithmes

double exp ( double x ); double log ( double x );


double pow ( double x, double y ); double log10 ( double x );

Erreurs
La fonction pow peut déclencher une erreur : EDOM : x est négatif ;
EDOM : x est négatif, et y n’est pas un entier. ERANGE : x est nul.

222 223

110
16/05/2018

Sinus, cosinus, tangente Arc sinus, arc cosinus

double sin ( double x ); double asin ( double x );

double cos ( double x ); double acos ( double x );

double tan ( double x );


Erreurs
EDOM : x est inférieur à -1 ou supérieur à 1

Note : les angles retournés sont en radians


224 225

111
16/05/2018

Arc tangente

double atan ( double x ); Fichier en langage C


double atan2 ( double y, double x );

226 227

112
16/05/2018

introduction introduction

Programme.exe
On distingue traditionnellement deux techniques de
gestion de fichiers :
✓ l’accès séquentiel consiste à traiter les informations
séquentiellement ;
✓ l’accès direct consiste à se placer immédiatement sur
l’information souhaitée, sans avoir à parcourir celles
qui la précèdent.

228 229

113
16/05/2018

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

#include <stdio.h>
main() sortie = fopen (nomfich, "w") ;
{ char nomfich[21] ;
int n ; Elle possède deux arguments :
FILE * sortie ;
printf ("nom du fichier à créer : ") ; ✓ Le nom du fichier; ici, nous avons prévu que ce
scanf ("%s", nomfich) ; nom ne dépassera pas 20 caractères (le chiffre 21
sortie = fopen (nomfich, "w") ;
tenant compte du caractère \0) ;
do { printf ("donnez un entier : ") ;
scanf ("%d", &n) ;
if (n) ✓ Une indication sur le mode de manipulation.
fwrite (&n, sizeof(int), 1, sortie) ; }
while (n) ;
fclose (sortie) ; }
230 231

114
16/05/2018

le nombre de blocs de cette


les modes d'ouverture possibles taille que l’on souhaite
transférer dans le fichier

modes d'ouverture description


"r" lecture seule
fwrite (&n, sizeof(int), 1, sortie) ;
"w" écriture seule
"a" mode d'ajout.
"r+" lecture et écriture.
"w+" lecture et écriture, avec adresse d’un bloc
suppression du contenu au d’informations (ici &n) l’adresse de la
structure décrivant
préalable. le fichier
la taille d’un bloc, en
octets : ici sizeof(int)
232 233

115
16/05/2018

Liste séquentielle d’un fichier Liste séquentielle d’un fichier


#include <stdio.h>
main()
{ char nomfich[21] ;
int n ;
FILE * entree ;
printf ("nom du fichier à lister : ") ;
scanf ("%s", nomfich) ;
entree = fopen (nomfich, "r") ;

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


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

fclose (entree) ;}
234 235

116
16/05/2018

Liste séquentielle d’un fichier Liste séquentielle d’un fichier

La lecture dans le fichier se fait par un appel de la On pourrait remplacer la boucle while par la
fonction fread : construction (moins concise) suivante :
fread (&n, sizeof(int), 1, entree); do
dont les arguments sont comparables à ceux de fwrite. { fread (&n, sizeof(int), 1, entree) ;
Mais, cette fois, la condition d’arrêt de la boucle est : if ( !feof(entree) ) printf ("\n%d", n) ;
}
feof (entree)
while ( !feof(entree) ) ;

236 237

117
16/05/2018

Liste séquentielle d’un fichier Liste séquentielle d’un fichier

int main(int argc, char *argv[])


Un fichier peut être placé dans un sous-dossier : {
FILE* fichier = NULL;
fichier = fopen("dossier/test.txt", "r+"); fichier = fopen("test.txt", "r+");

windows if (fichier != NULL)


fichier = fopen("C:\\Program Files\\Notepad++\\readme.txt", "r+"); {
// On lit et on écrit dans le fichier
Linux
fichier = fopen("/home/mateo/dossier/readme.txt", "r+"); // ...

fclose(fichier); // On ferme le fichier qui a été ouvert


}
return 0; }
238 239

118
16/05/2018

écrire dans un fichier écrire dans un fichier

Langage C offre trois fonctions d’ écriture: fputc

✓fputc : écrit un caractère dans le fichier ; Cette fonction écrit un caractère à la fois dans le fichier. Son
prototype est :
✓ fputs : écrit une chaîne dans le fichier ;
int fputc(int caractere, FILE* pointeurSurFichier);
✓ fprintf : écrit une chaîne « formatée » dans le fichier,
fonctionnement quasi-identique à printf.

240 241

119
16/05/2018

écrire dans un fichier écrire dans un fichier

int main(int argc, char *argv[]) fputs


{
FILE* fichier = NULL;
Prototype de la fonction :
fichier = fopen("test.txt", "w");
char* fputs(const char* chaine, FILE* pointeurSurFichier);
if (fichier != NULL)
{
fputc('A', fichier); // Écriture du caractère A
Cette fonction est très similaire à fputc, à la différence près qu'elle écrit
fclose(fichier);
tout une chaîne, ce qui est en général plus pratique que d'écrire
} caractère par caractère.
Cela dit, fputc reste utile lorsque vous devez écrire caractère par
return 0; caractère, ce qui arrive fréquemment.
}
242 243

120
16/05/2018

écrire dans un fichier écrire dans un fichier

int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
FILE* fichier = NULL; FILE* fichier = NULL;
Bonjour int age = 0;
fichier = fopen("test.txt", "w"); tout le monde fichier = fopen("test.txt", "w");

if (fichier != NULL) if (fichier != NULL)


{ {
fputs("Bonjour\n tout le monde?", fichier); printf("Quel age avez-vous ? ");
fclose(fichier); scanf("%d", &age);
} fprintf (fichier, "Le Monsieur qui utilise le programme, il a %d ans", age);
fclose(fichier);
return 0; } return 0; }
}
244 245

121
16/05/2018

Lire dans un fichier Lire dans un fichier

int main(int argc, char *argv[])


Nous pouvons utiliser quasiment les mêmes fonctions {
que pour l'écriture, le nom change juste un petit peu : FILE* fichier = NULL; int caractereActuel = 0;
fichier = fopen("test.txt", "r");
if (fichier != NULL)
✓ fgetc : lit un caractère ; {
do// Boucle de lecture des caractères un à un
{
✓ fgets : lit une chaîne ; caractereActuel = fgetc(fichier);
printf("%c", caractereActuel);
} while (caractereActuel != EOF);
✓ fscanf : lit une chaîne formatée. fclose(fichier);
}
return 0; }
246 247

122
16/05/2018

Lire dans un fichier Lire dans un fichier

int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ { FILE* fichier = NULL;
FILE* fichier = NULL; char chaine[1000] = "";
char chaine[1000] = "";
fichier = fopen("test.txt", "r"); fichier = fopen("test.txt", "r");
if (fichier != NULL)
if (fichier != NULL) {
{ while (fgets(chaine, 1000, fichier) != NULL)
fgets(chaine, 1000, fichier); {
printf("%s", chaine); printf("%s", chaine); }
fclose(fichier); fclose(fichier);
} }
return 0; return 0;
} }
248 249

123
16/05/2018

Lire dans un fichier Accès direct en lecture sur un fichier existant


SEEK_CUR
int main(int argc, char *argv[]) #include <stdio.h>
position courante
{ main()
FILE* fichier = NULL; { char nomfich[21] ; début
int score[3] = {0}; // Tableau des 3 meilleurs scores int n ; long num ; du fichier
fichier = fopen("test.txt", "r"); FILE * entree ;
if (fichier != NULL) printf ("nom du fichier à consulter : ") ;
{ scanf ("%20s", nomfich) ;
fscanf(fichier, "%d %d %d", &score[0], &score[1], entree = fopen (nomfich, "r") ;
&score[2]); while ( printf (" numéro de l'entier recherché : "),
printf("Les meilleurs scores sont : %d, %d et %d", scanf ("%ld", &num), num )
score[0], score[1], score[2]); { fseek (entree, sizeof(int)*(num-1), SEEK_SET) ;
fclose(fichier); fread (&n, sizeof(int), 1, entree) ;
} printf (" valeur : %d \n", n) ; SEEK_END
depuis la fin du
return 0; } } fichier
250 fclose (entree) ; 251

124
16/05/2018

Se déplacer dans un fichier Se déplacer dans un fichier

Il existe trois fonctions à connaître : ftell : position dans le fichier

✓ ftell : indique à quelle position vous êtes actuellement Cette fonction est très simple à utiliser. Elle renvoie la position
dans le fichier ; actuelle du curseur sous la forme d'un long :

✓ fseek : positionne le curseur à un endroit précis ; long ftell(FILE* pointeurSurFichier);


✓ rewind : remet le curseur au début du fichier (c'est Le nombre renvoyé indique donc la position du curseur dans
équivalent à demander à la fonction fseek de le fichier.
positionner le curseur au début).

252 253

125
16/05/2018

Se déplacer dans un fichier nombre de caractères à Se déplacer dans un fichier


partir de la position
fseek : se positionner dans le fichier indiquée par origine Voici quelques exemples.
Le code suivant place le curseur deux caractères après le début :
Le prototype de fseek est le suivant :
fseek(fichier, 2, SEEK_SET);
int fseek(FILE* pointeurSurFichier, long deplacement, int origine);
Le code suivant place le curseur quatre caractères avant la
position courante :

fseek(fichier, -4, SEEK_CUR);


Le nombre deplacement peut être un nombre Le code suivant place le curseur à la fin du fichier :

positif (pour se déplacer en avant), nul (= 0) ou fseek(fichier, 0, SEEK_END);


négatif (pour se déplacer en arrière).

254 255

126
16/05/2018

Renommer et supprimer un fichier Renommer et supprimer un fichier

Nous terminerons ce chapitre en douceur par


l'étude de deux fonctions très simples :
int main(int argc, char *argv[])
✓rename : renomme un fichier ;
{
rename("test.txt", "test_renomme.txt");
✓ remove : supprime un fichier.
return 0;
La particularité de ces fonctions est qu'elles ne nécessitent pas
}
de pointeur de fichier pour fonctionner. Il suffira simplement
d'indiquer le nom du fichier à renommer ou supprimer.

256 257

127
16/05/2018

Expliquez brièvement le fonctionnement du programme ?


Renommer et supprimer un fichier
void main()
{ int i,n;
int main(int argc, char *argv[])
char fich[80];
{
printf("entrez un nombre");
remove("test.txt"); scanf("%d",&n);
printf("la table de multiplication par %d\n",n);
return 0; sprintf(fich,"%s%d%s","table",n,".txt");
FILE *pf=fopen(fich,"w");
}
for(i=1;i<10;i++)
fprintf(pf,"%d x%d =%d\n", n, i, n*i);
258
fclose(pf);} 259

128
16/05/2018

Contrôle des acquis Contrôle des acquis

1. Quelle est la syntaxe correcte pour la 2. Pour ouvrir un fichier en mode lecture et
déclaration d’un fichier ? écriture, avec suppression, nous précisons ?
a) file a) a
b) Fichier b) w
c) FILE c) w+
d) File d) r+
260 261

129
16/05/2018

Contrôle des acquis Contrôle des acquis

4. Langage C offre des fonctions d’ écriture?


3. fwrite (&n, sizeof(int), 1, sortie) ;
a) fputc
la valeur 1 désigne:
b) printf
a) le nombre des caractères de type int
c) fputs
b) la position d’un entier d) fprintf
c) sans signification e) puts
f) fclose
262 263

130
16/05/2018

Contrôle des acquis Contrôle des acquis/ Correction

5. fseek(fichier, 2, SEEK_END);
a) Le code place le curseur à la fin du 1. c
fichier ;
2. c
3. a
b) Le code place le curseur à deux caractères
4. a c d
avant la fin du fichier ;
5. c
c) Le code est erroné ;
264 265

131
16/05/2018

Les fichiers prédéfinis

Un certain nombre de fichiers sont connus du langage C, sans


qu’il soit nécessaire ni de les ouvrir ni de les fermer :
✓ stdin : unité d’entrée (par défaut, le clavier) ;
Le préprocesseur
✓ stdout : unité de sortie (par défaut, l’écran) ; en langage C
✓ stderr : unité d’affichage des messages d’erreurs (par
défaut, l’écran).
On trouve parfois également :
✓ stdaux : unité auxiliaire ;
✓ stdprt : imprimante

266 267

132
16/05/2018

Les directives du préprocesseur Les directives du préprocesseur

Les ordres du préprocesseur :


Le préprocesseur est un programme ✓ l’incorporation de fichiers source (#include);
exécuté lors de la première phase de la ✓ la définition de variables de pré-compilation :
#define NOM valeur
compilation, il est identifié par le caractère
#undef NOM
✓ définition de macro-fonction ou macro-
# expression :
#define m(x) (128*(x)+342*(x)*(x))
# include <errno.h>
✓ la compilation conditionnelle (#if, #ifdef,...).
268 269

133
16/05/2018

La directive #include La directive # define

La directive #include possède deux syntaxes :


La directive #define permet de définir des
#include <nom-de-fichier>
constantes symboliques (on parle aussi de macros
#include "nom-de-fichier"
sans paramètres) ou des macros avec paramétrer.
À noter aussi, qu'il est possible d'annuler la
pour les fichiers en-tête
fichiers crées par l’utilisateur de la librairie standard définition d'une macro avec la directive "#undef":

270 271

134
16/05/2018

La directive #define La directive #define

#define max 100 on peut expliciter facilement les relations entre constantes.

#define BEGIN { Exemple :


#define END }
#define NB_LIGNES 24
#define NB_COLONNES 100
#define NB_COLONNES 80

#define TAILLE_MATRICE NB_LIGNES * NB_COLONNES

272 273

135
16/05/2018

La directive #define Définition de macro-expressions

Sans constante de précompilation


#define add(x1,x2) ((x1) += (x2))
int tab[20]
for ( i = 0; i < 20; i++ )

Lorsque le préprocesseur rencontre une expression


Avec constante de pré-compilation
du type add(a,b), il génère ((a) += (b))
#define LG 20
int tab[LG]
for ( i = 0; i < LG; i++ )

274 275

136
16/05/2018

#define add(x1,x2) ((x1) += (x2))


#define m(x) 2*x+3*x*x La compilation conditionnelle
#define y(x) (8*(x)+2*(x)*(x)) Sa syntaxe la plus générale est :
int main()
{ int i;
int a, b, c, e, f, d; #ifdef symbole Toute condition de sélection de
code commence par un
a = b = c = 1;
..... #if[n[def]], et se termine par
d = e = f = 2; #endif, avec éventuellement une
add(a,b); #else partie #else.
add(a,b+1);
d = m(a); .....
e = y(a); #endif
d = y(a+b);
f = m(add(a,b));
printf("a=%d, b=%d, c=%d, e=%d, f=%d\n", a b, c, e, f);
276 277
return 0;}

137
16/05/2018

La compilation conditionnelle Les directives du préprocesseur

#define CODE 1
#define MAX(a,b) a>b?a:b
.....
#if CODE == 1
Cette macro peut être appelée comme n'importe
instructions 1 quelle fonction C.
#elif CODE == 2 Ainsi, après passage du préprocesseur, z = MAX(x,y);

instructions 2 sera remplacé par z = x>y?x:y;

#endif
278 279

138
16/05/2018

Les directives du préprocesseur Les directives du préprocesseur

Définir la macro fonction suivante : Définir la macro fonction suivante :


– valeur absolue d’une expression, – minimum de deux expressions,

#define abs(a) ((a) < 0 ? (-(a)) : (a)) #define min(a1,a2) ((a1) < (a2) ? (a1) : (a2))

280 281

139
16/05/2018

Les directives du préprocesseur Les directives du préprocesseur

Définir la macro fonction suivante : Définir la macro fonction suivante :


– maximum de deux expressions, – minimum de trois expressions,

#define max(a1,a2) ((a1) > (a2) ? (a1) : (a2))


#define min3(a1,a2,a3) ((a1) < (a2) ? (a1) < (a3) ? (a1)
: (a3) : \ (a2) < (a3) ? (a2) : (a3))

282 283

140
16/05/2018

Les directives du préprocesseur

Définir la macro fonction suivante :


– maximum de trois expressions,

#define min3(a1,a2,a3) ((a1) < (a2) ? (a1) < (a3) ? (a1)


: (a3) : \ (a2) < (a3) ? (a2) : (a3))
Travaillons ensemble

284 285

141
16/05/2018

Gestion des nombres complexes <complex.h>

z = a + i ∗ b,
où a, b ∈ R.
Les listes chaînées
On rappelle que a est la partie réelle de z,
en langage C b sa partie imaginaire et i le nombre
imaginaire:
i =√−1 (i2= −1).

creal cimag
286 287

142
16/05/2018

Gestion des nombres complexes <complex.h> La généricité en langage C

#include <stdio.h>
#include <stdlib.h> Le langage C dispose d'un pointeur
#include <complex.h> particulier appelé pointeur générique qui
int main() est un pointeur compatible avec tous les
{ double complex z1 = 1.0 + 3.0 * I; autres pointeurs, c'est-à-dire que ce
double complex z2 = 1.0 - 4.0 * I; pointeur est à même de pointer vers
double complex somme = z1 + z2; n'importe quel type d'objet.
printf("Z1 + Z2 = %.2f %+.2fi\n", creal(somme), cimag(somme));
double complex diff = z1 - z2;
printf("Z1 - Z2 = %.2f %+.2fi\n", creal(diff), cimag(diff)); void *
return 0; }
288 289

143
16/05/2018

La généricité en langage C Les limites du pointeur générique

#include <stdio.h> void echange ( void * a , void * b)


{
#include <stdlib.h> void * tmp;
int main ( void ) tmp = a;
{ a = b; a=3,b=2
b = tmp;
void * ptr = NULL; }
int a = 2;
ptr = &a; int a = 3;
printf("%d\n",ptr); int b = 2; *(void **)
return 0; echange ( &a, &b );
} printf( "a = %d , b = %d" , a , b );

290 291

144
16/05/2018

Les limites du pointeur générique La compilation séparée en C

void echange( void * d1 , void * d2 )


Filen.c
{ C
void * tmp; a=2,b=3
tmp = *(void **)d1;
*(void **)d1 = *(void **)d2; File1.c
File2.c File3.c
*(void **)d2 = tmp;
}

292 293

145
16/05/2018

La compilation séparée en C La compilation séparée en C

#include <stdio.h>
int somme(int a, int b);
int produit(int a, int b);
Fichier : exemple.c
int main()
{
int a = 2, b = 5;
printf("%d + %d = %d\n", a, b, somme(a, b));
printf("%d * %d = %d\n", a, b, produit(a, b));

return 0;
}
294 295

146
16/05/2018

La compilation séparée en C Compilation sous Code::Blocks

int somme(int a, int b)


{
return a + b;
}
int produit(int a, int b)
{ Fichier : somme.c
int prod = 0;

while (b-- > 0)


prod += a;
return prod;
}
296 297

147
16/05/2018

Le mot-clé extern Le mot-clé static

#include <stdio.h>
static int id(int x); /* Déclaration de la fonction "privee" */
il permet d'indiquer que la variable ou la
int main()
fonction est définie dans un autre fichier {
int x = 0;
(source ou objet). Placé devant une printf("id(%d) = %d\n", x, id(x));
return 0;
définition, il permet d'indiquer que la }
int id(int x)
variable ou la fonction est visible dans {
return x;
tout le projet. }

298 299

148
16/05/2018

Les listes chaînées Les listes chaînées

Int T[5];

suivant

suivant

suivant
Int a; Int a; Int a;
T[0] T[1] T[2] T[3] T[4]

Null

suivant
T[0] T[1] T[i] T[2] T[3] T[4] Int a;

Nb: Contrairement aux tableaux, les


éléments d'une liste chaînée ne sont
pas placés côte à côte dans la mémoire.
il n'est pas possible d'y insérer une case au milieu
300

149
16/05/2018

Les listes chaînées Construction d'une liste chaînée

Int a; Int a; struct Element


suivant

Int a;
suivant

suivant
Flaot b; Flaot b; Flaot b;
char c;
{
char c; char c;
int val;
struct Element * suivant;
Null };
Int a; typedef struct Element* Element;
suivant

Flaot b;
char c;

Un pointeur vers un élément du même


Les méthodes concernant les listes:
type appelé suivant.: chaque élément «
Creation , Remplissage, Affichage,
sait » où se trouve l'élément suivant en
Compteur, Suppression, Liberation, etc.
mémoire.
303

150
16/05/2018

Les fonctions de gestion de la liste Les listes chaînées- Ajouter un élément

À première vue, on aura besoin de fonctions pour :

suivant
suivant
Int val; Int val;
✓ Initialiser la liste ;

✓ Ajouter un élément ;
Null
struct Element inserer(int info)
✓ Supprimer un élément ;
{struct Element liste=malloc(sizeof(struct Element));
✓ Afficher le contenu de la liste ; liste->val=info;
liste->suivant=NULL;
✓ Supprimer la liste entière. return liste;};
304

151
16/05/2018

Les listes chaînées- Ajouter un élément Les listes chaînées- supprimer un élément

suivant
suivant
Int val; Int val;

suivant
Int val; suivant Int val;

void suppression(struct Element *liste) Null


Null {
void afficher(struct Element liste){ if (liste == NULL)
{ exit(EXIT_FAILURE); }
If (!liste) return ;
if (liste->premier != NULL)
printf("%d>",liste->val); {
Element *aSupprimer = liste->val;
afficher(liste->suivant); liste->val = liste->suivant->val;
free(aSupprimer); }}
}

152
16/05/2018

Autre implantation des listes Liste doublement chaînée Les piles


Précédant

suivant

Précédant

suivant

Précédant

suivant
a1 a3 a4
Vous pouvez ajouter des pièces une
à une en haut de la pile, mais aussi

Null en enlever depuis le haut de la pile.


Null
Précédant

suivant

a2

Chaque cellule permet l’accès à


la cellule précédente et à la cellule
suivante.
LIFO
308 309

153
16/05/2018

Fonctionnement des piles


Empilage d’une pile

Par exemple, imaginons une pile de nombres entiers de type int void empiler(Pile *pile, int nvNombre)
typedef struct Element Element; {
struct Element Element *nouveau = malloc(sizeof(*nouveau));
if (pile == NULL || nouveau == NULL) 21
{
int nombre; {
Element *suivant; 2 exit(EXIT_FAILURE); 2
}; }

typedef struct Pile Pile; 7 nouveau->nombre = nvNombre; 7


struct Pile nouveau->suivant = pile->premier;
{ Element *premier; }; 23 pile->premier = nouveau; 23
}
310 311

154
16/05/2018

Dépilage d’une pile Affichage d’une pile

int depiler(Pile *pile) void afficherPile(Pile *pile)


{ {
if (pile == NULL) if (pile == NULL)
{ exit(EXIT_FAILURE); }
int nombreDepile = 0; 21 { exit(EXIT_FAILURE); }
Element *elementDepile = pile->premier; Element *actuel = pile->premier;
while (actuel != NULL)
if (pile != NULL && pile->premier != NULL)
2 {
{ printf("%d\n", actuel->nombre);
nombreDepile = elementDepile->nombre; 7 actuel = actuel->suivant;
pile->premier = elementDepile->suivant;
}
free(elementDepile); }
printf("\n");
return nombreDepile; 23 }
}
312 313

155
16/05/2018

Tester une pile Les files


int main()
{ Pile *maPile = initialiser(); les éléments s'entassent les uns à la suite des autres.
empiler(maPile, 4); empiler(maPile, 8); Le premier qu'on fait sortir de la file est le premier à
empiler(maPile, 15); empiler(maPile, 16);
être arrivé. On parle ici d'algorithme FIFO (First In
empiler(maPile, 23); empiler(maPile, 42);
printf("\nEtat de la pile :\n"); First Out), c'est-à-dire « Le premier qui arrive est le
afficherPile(maPile); premier à sortir ».
printf("Je depile %d\n", depiler(maPile));
printf("Je depile %d\n", depiler(maPile));
printf("\nEtat de la pile :\n");
afficherPile(maPile); return 0; }
314 315

156
16/05/2018

void enfiler(File *file, int nvNombre)


Création d'un système de file { Element *nouveau = malloc(sizeof(*nouveau));
if (file == NULL || nouveau == NULL)
typedef struct Element Element;
{ exit(EXIT_FAILURE); }
struct Element
nouveau->nombre = nvNombre;
{
nouveau->suivant = NULL;
int nombre;
if (file->premier != NULL) /* La file n'est pas vide */
Element *suivant;
{ /* On se positionne à la fin de la file */
};
Element *elementActuel = file->premier;
typedef struct File File; while (elementActuel->suivant != NULL)
struct File { elementActuel = elementActuel->suivant; }
{ elementActuel->suivant = nouveau;
Element *premier; }
}; else /* La file est vide, notre élément est le premier */
316
{ file->premier = nouveau; }} 317

157
16/05/2018

int defiler(File *file)


{ if (file == NULL)
{ exit(EXIT_FAILURE); }
int nombreDefile = 0;
/* On vérifie s'il y a quelque chose à défiler */
if (file->premier != NULL)
{ Element *elementDefile = file->premier;
nombreDefile = elementDefile->nombre;
file->premier = elementDefile->suivant; Travaillons ensemble
free(elementDefile); }
return nombreDefile; }
318 319

158