Vous êtes sur la page 1sur 166

Programmation structure

et Langage C
Linformatique
Phelma/PET
1re anne : les objectifs
Matriser le dveloppement de logiciels
Apprendre la Programmation structure
Connaitre quelques Structures de donnes et Algorithmes

Semestre 1 : 14 sances de 2h de C/TD papier et machine


Environ 1 cours/TD et 1 sujet de TP pour 2 sances
TP prpars lavance, individuellement
Contrle des prparations papier chaque TP
Terminer les TP en dehors des seances encadres si ncessaire
Conseil : taper le code lavance
Semestre 2: 18 sances de 2h de C/TD papier et machine

Tous les documents sur le site tdinfo-pet.phelma.grenoble-inp.fr/1APET


1 mini projet en fin de semestre et danne
1 examen crit + contrle continu (20%) chaque semestre
2
Premire sance
Prsentation gnrale Dveloppement logiciel
Le rseau MINATEC Sur machine
Le matriel mis disposition Connexion
Les ressources Webmail
Les adresses et liens utiles Mon premier programme
Environnement Unix Un autre programme
Le systme de fichiers
Les commandes de bases

3
Le matriel
350 K de matriel rseau
Rseau entirement redondant
Cur de rseau et quipements principaux onduls
800 PCs : 1M de serveurs et PCs
1 Petaoctet de stockage
Stockage accessible depuis tous les postes clients
12 Serveurs :
Messagerie
Web
Authentification centralis (Ldap, radius)
Base de donnes
NFS (partage de disque)
Monitoring 24/24 7/7 des serveurs et quipements rseaux

4
Les ressources par
etudiants

Quotas espace disque :


150 Mo pour le stockage du mail
1 Go dans votre Home Dir

Quotas dimpression : Pensez nos arbres !!


50 pages recto/verso par mois cumulables
Non limit en salle de TDs

5
Les sites utiles
http://tdinfo-pet.phelma.grenoble-inp.fr
Infos sur les TDs dinformatique (sujet, docs, etc)
Help@phelma.grenoble-inp.fr
Pour tout problme li linformatique

Les autres sites :


http://webmail.minatec.grenoble-inp.fr
Accs votre messagerie via un navigateur web
http://login.minatec. grenoble-inp.fr
Informations sur vos quota mail et impression, changement de votre mot de passe
http://prism.minatec. grenoble-inp.fr
Site dinformations et de support du service informatique
http://intranet.phelma.grenoble-inp.fr
Information scolarits, cole
http://etudiants.phelma.grenoble-inp.fr
Site des tudiants
6
Lancer un explorateur de
fichiers:

7
Un explorateur de fichiers:

8
Lancer un explorateur
internet :

9
Un explorateur internet :

10
Le mail

11
Le mail

12
Lancer un terminal

13
Le shell
Le shell est linterprteur de vos commandes.

Le shell dispose dastuces vous facilitant la vie :


Le rappel de commande :
Les touches flche vers le haut et flches vers le bas permettent de se dplacer
dans les dernires commandes dj tapes
La compltion automatique
Lorsque vous saisissez des chemins, lappui sur la touche tabulation permet de
complter automatiquement votre chemin avec le nom du fichier ou du rpertoire
disponible.
En cas dincertitudes (plusieurs chemins possibles), appuyez deux fois sur la touche
tabulation , la liste des chemins possibles saffiche.

Le copier/coller : Sous Xwindows, le copier coller est possible via la souris


Le copier se fait automatiquement via une slection du texte (clic gauche)
Le coller se fait grce au bouton du milieu de la souris

14
Systme de fichiers
Le systme de fichiers est une arborescence de dossiers o vous
stockez tous vos fichiers et dossiers
Le dossier racine est le dossier root : /
Dans chaque dossier on peut crer dautres dossiers ou des fichiers
Les dossiers sont protgs contre les autres utilisateurs

/ __ users ____ phelma ____ phelma2009 __ user1 : /users/phelma/phelma2009/user1


| | | |___user2 : /users/phelma/phelma2009/user2
| | | |___tdinfo : /users/phelma/phelma2009/tdinfo
| | |
| | |____ phelma2010 ____user1 : /users/phelma/phelma2010/user1
| |____ erg2007 : /users/erg2007
|____ etc : /etc
|____ lib : /lib
|____ bin : /bin

15
Unix : commandes
man : permet de comprendre le fonctionnement dune commande
Donne accs galement aux informations des fonctions C standard. Appuyer sur q pour
quitter man
pwd : Permet de savoir dans quel rpertoire on se situe
(pas dargument)
cd : Permet de se dplacer dans un autre rpertoire
(ex : de tdinfo, cd ~/../tdinfo/user1
ls : Permet de lister le contenu dun rpertoire
(ex., ls, ls l, ls la, pour les options voir le man)
mkdir : permet de crer un rpertoire
(ex., mkdir td0, mkdir ~/tdinfo)
rmdir : permet de supprimer un rpertoire (il doit tre vide)
(ex., rmdir td0, rmdir /users/phelma/phelma2008/users1/tdinfo/td0)
cp : permet de copier un ou plusieurs fichiers
(ex., cp file1.txt ../../test, cp ../tdinfo/td0/file1.txt .)
mv : permet de dplacer ou renommer un ou plusieurs fichiers
(ex., mv file1.txt file1Old.txt, mv file1.txt ../../tdinfo/td1)
rm : permet deffacer un ou plusieurs fichiers ou rpertoires
(ex., rm file1.txt, rm r dir1, rm rf dir1)
quota : permet de connatre son utilisation despace disque 16
Unix : tester cette liste
pwd
ls l
cd tdinfo
mkdir td0
ls -l
cd td0
ls -l
cp /users/prog1a/C/librairie/td0.c td0.c
ls -l
less td0.c
cd ..
pwd
ls -l
rmdir td0
cd td0
ls -l
rm *
ls -l
cd ..
rmdir td0
17
Rpertoires
Chaque utilisateur dispose dun espace de travail ou home directory
Grce des protocoles de partage de fichiers rseaux, ce rpertoire est
accessible de tous les postes clients.
Par dfaut la connexion on tombe dans sa home dir
Pour retourner dans sa home dir, on peut utiliser la commande : cd ~

Tout rpertoire ou fichier peut tre dsign par rapport sa home dir :
~/tdinfo/td0
~/../users1/projet/td0
Tout rpertoire ou fichier peut tre dsign par rapport la racine: cest le
chemin absolu
/users/phelma/phelma2011/monlogin/tdinfo/td0
Tout rpertoire ou fichier peut tre dsign par rapport lendroit o lon
est : cest le chemin relatif
/users/phelma/phelma2011/monlogin/tdinfo/td0

18
Chemin relatif
Exemples :
Si on est dans le rpertoire absolu : /users/phelma/phelma2008/user1
Pour dsigner le rpertoire : /users/phelma/phelma2008/user1/tdinfo/td0

On doit utiliser le chemin :


./tdinfo/td0
ou plus simplement :
tdinfo/td0

Si on se trouve maintenant dans : /users/phelma/phelma2008/user2


Le rpertoire prcdent sera accessible via :
../user1/tdinfo/td0

19
Comment crer un
programme
Un programme
indique la machine ce quelle doit faire
succession doctets (8 bits) qui sont des commandes
reconnues par le processeur

Il faut
Un cahier des charges
Analyse du problme
Codage en langage informatique : Matlab, Java, C, assembleur
Traduction en langage binaire : compilation et edition des liens

20
Exemple
Cahier des charges
Faire un programme qui calcule linverse dun nombre

Analyse : il faut 2 nombres rels


Rentrer le nombre dont on veut linverse

Calculer linverse du nombre et le mettre dans un autre nombre

Afficher lecran ce nombre

crer le fichier contenant le programme C et le sauvegarder :


bash-3.00$ gedit prog1.c
#include <stdio.h>
main(){ double x,y; /* Crer deux nombres rels appele x et y */
printf("Entrer un nombre au clavier\n"); /*Affiche un message lecran*/
scanf("%lf", &x); /* Entrer un nombre au clavier, le mettre dans x */
y = 1/x; /* Calculer linverse, le mettre dans y */
printf("Linverse de %lf est : %lf \n ",x,y); /* Afficher le resultat */
}

21
Exemple

22
Exemple

Crer le fichier executable


contenant le programme :
bash-3.00$ gcc prog1.c o prog1

Executer le programme
bash-3.00$ ./prog1
Entrer un nombre au clavier
3
Linverse de 3 est : 0.333333

23
Un diteur de texte
Un editeur est un programme qui sert taper, modifier, sauver du
texte dans un fichier

De nombreux editeurs existent : vi , gedit, kate, xemacs.


Le plus facile : gedit
Le plus geek : kate
Le prfr des programmeurs libres : xemacs
Le plus vieux : vim

24
Un diteur de texte : gedit
Espace o vous
tapez votre
programme

ZONE o on crit son programme

25
Un diteur de texte : gedit

26
pouilly:~/Documents/ens/1AERG/2008/ex desvignes$ od -A n -t x
p1

Pourquoi compiler
feedface 00000012 00000000 00000002
0000000b 00000530 00000085 00000001
00000038 5f5f5041 47455a45 524f0000
00000000 00000000 00001000 00000000
00000000 00000000 00000000 00000000
00000004 00000001 0000018c 5f5f5445
58540000 00000000 00000000 00001000
00002000 00000000 00002000 00000007
Voici le code binaire de laddition de deux 00000005 00000005 00000000 5f5f7465
78740000 00000000 00000000 5f5f5445
nombres. 58540000 00000000 00000000 000023ac
00000988 000013ac 00000002 00000000
Cest un programme qui met 5 dans i, 8 dans j 00000000 80000400 00000000 00000000
et i+j dans k. 5f5f7069 6373796d 626f6c5f 73747562
5f5f5445 58540000 00000000 00000000
Taille du programme binaire : 16904 octets 00002d34 00000000 00001d34 00000002
Facile, non !!!! 00000000
00000024
00000000
5f5f7379
80000008
6d626f6c
00000000
5f737475
62000000 5f5f5445 58540000 00000000
00000000 00002d34 00000000 00001d34
On utilise des langages plus proches de nous 00000002 00000000 00000000 80000008
00000000 00000014 5f5f7069 6373796d
626f6c73 74756231 5f5f5445 58540000
00000000 00000000 00002d40 00000160
00001d40 00000005 00000000 00000000
80000408 00000000 00000020 5f5f6373
7472696e 67000000 00000000 5f5f5445
58540000 00000000 00000000 00002ea0
00000130 00001ea0 00000002 00000000
00000000 00000002 00000000 00000000
00000001 0000018c 5f5f4441 54410000
00000000 00000000 00003000 00001000
00002000 00001000 00000007 00000003
00000005 00000000 5f5f6461 74610000
00000000 00000000 5f5f4441 54410000
00000000 00000000 00003000 00000014
00002000 00000002 00000000 00000000

27
Assembleur
.section __TEXT,__text,regular,pure_instructions
.section __TEXT,__picsymbolstub1,symbol_stubs,pure_instructions,32
.machine ppc
.text
.align 2
.globl _main
_main:
stmw r30,-8(r1)
stwu r1,-64(r1)
mr r30,r1
li r0,5 // Mettre 5 dans le registre r0
stw r0,32(r30) // stocker r0 dans i (adresse r30+32)
li r0,8 // Mettre 8 dans le registre r0
stw r0,28(r30) // stocker r0 dans j (adresse r30+28)
lwz r2,32(r30) // Charger i (adresse r30+32) dans r2
lwz r0,28(r30) // Charger j (adresse r30+28) dans r0
add r0,r2,r0 // Additionner r0 et r2 dans r0
stw r0,24(r30) // stocker r0 dans k (adresse r30+24)
lwz r1,0(r1)
lmw r30,-8(r1)
blr
.subsections_via_symbols
28
En C
#include <stdio.h>

main()
{ int i,j,k;

i=5;
j=8;
k = i+j;
}
Question 1: Quest ce que vous prfrez crire ?

Question 2: Pourquoi ? Quels avantages ? Quels inconvnients ?

29
La chaine de compilation
Dans la pratique, un programme peut etre constitu de plusieurs millions de
lignes de code et de plusieurs centaines de fichiers
Comment construit-on un programme dans ce cas ?
Exemple : un programme ralisant le produit de (i+2) par la racine carr de
j.
La somme i+2 est ralise par une fonction f, qui est crite dans le fichier
f1.c
La racine carr de j est ralise par une fonction g, qui est crite dans le
fichier f2.c
Le programme principal, qui calcule f(i)*g(j) se trouve dans le fichier p1.c
On veut construire le programme qui affiche le rsultat.

2 tapes : compilation puis dition des liens

30
La chane de compilation
p1.c f1.c f2.c
main() {int i,j,k; int f(int a) {int x; int g(int a) { int y;
i=5; j=8; x=a+2; y= sqrt(a);
k=f(i)*g(j); return x; return y;
printf("%d",k); } }
}
Etape 1 :Traduction du C
gcc -c p1.c gcc -c f1.c gcc -c f2.c en langage machine
binaire par Preprocesseur
+Compilation
p1.o f1.o f2.o
_main... _f... _g...

libC.a
gcc -o monprog p1.o f1.o f2.o -lm _printf

Etape 2 : Edition des liens : Bibliothques


rassembler les diffrentes a.out libm.a
parties de code binaire dans Executable _sqrt
un fichier unique 31
Compilation
Pour crer le programme, il faut faire
toutes les commandes suivantes :
gcc -c p1.c
gcc -c f1.c
gcc -c f2.c
gcc o monprog p1.o f1.o f2.o -lm

Lutilitaire make et le fichier Makefile


permettent de simplifier cette tache.
Vous lutiliserez plus tard chaque fois
que possible, nous fournissons la
plupart du temps le fichier Makefile
utile

32
Dveloppement logiciel
Cahier des charges

Analyse papier du projet raliser

Dfinition des besoins (structures, fonctions, prototypes)

Cycle
Saisie du code l'aide d'un diteur (gnration des fichiers .c et .h)
Compilation :
correction des erreurs de syntaxe
Excution, tests unitaires et dbogage :
correction des erreurs de logique en modifiant le code

Tests de validation

33
A vous de jouer

Connexion votre login


Aller dans le rpertoire tdinfo

Voir le site tdinfo-pet.phelma.grenoble-inp.fr et rcuprer le premier TD

34
Programme, E/S, variables
Structures de controle
Structure dun programme
Le programme excute les instructions squentiellement, les unes apres les autres en commenant
la fonction main

Une instruction est un ordre/commande que le processeur sait executer : par exemple, faire une
addition, aller un autre endroit dans le programme, etc

On commence par dclarer quels sont les variables et les types de donnes utiles: on peut
manipuler des entiers, des rels, etc

Un programme est compos dun ou plusieurs fichiers de la forme :


< Commandes du prprocesseur >
< Dfinition de types >
< Variables globales >
< Fonctions >

Structures des fonctions :


<type de retour> nom_de_fonction(<Dclaration des arguments >)
{ <Dclaration locales>
<instructions>
}
Structure dun programme
Nom de la fonction
Dbut de fonction ou bloc
/* Exemple : prog2.c */
#include <stdio.h>

int max(int a, int b)


{ Une fonction qui
if (a>b) calcule et renvoi le
plus grand des 2
return a; nombres quon lui donne
else
return b;
}
Programme principal :
main() Cre 3 variables
i,j,k qui peuvent
{ int i,j,k; contenir des entiers,
Met 10 dans i,
i=10; Met 20 dans j
Fin de bloc j=20; Met le max de i et j
k = max(i,j); dans k
printf("Le max de %d et de %d est Affiche le rsultat
sur lecran ensuite.
%d\n",i,j,k);
}

37
Exemple

38
Lessentiel

Quest ce quun programme informatique manipule ?


Des nombres, des mots

Pour manipuler des nombres, il faut pouvoir les stocker dans des
variables.

Il faut pouvoir introduire les nombres dans le programme et le


programme doit pouvoir les afficher

Le programme doit excuter les ordres : instructions

39
Types de nombre
Entier
char : Octet : 1 octet compris entre -128 et +127
int : Entier (1 mot machine)
short : entier Court
long : entier Long
long long : entier Long
unsigned int : entier Non Signe
unsigned long : entier Long Non Signe
short int <= int <= long int
Rels
float : Rel flottant Simple Prcision (4 octets) :
double : Rel flottant Double Prcision (8 octets)
long double : Rel flottant quadruple Prcision (16 octets)
PAS de booleens
FAUX = 0 VRAI = NON ZERO

40
Notion de variable
Adresse Mmoire
Objet informatique permettant de conserver et de
modifier sa valeur 0
Un type : entier, rel, etc
1
Un nom
2
Une adresse : o est elle ? un entier qui est le numro
de la case mmoire o elle se trouve
Sa dure de vie (ou porte) : de lendroit o elle est
dclare la fin du bloc : } &a= 0xbffff26c a=5
Exemple : var1.c
La variable a est cre ladresse 3221221990 en
dcimal, soit 0xbffff26c en hexadcimal
#include <stdio.h>
main() { Cration de a
int a;
a=5;
&a: adresse de a
printf("Bonjour\n");
printf("La valeur de a est %d\n",a);
printf("Ladresse de a est %p\n",&a);
Destruction de a
} 41
Entres/Sorties
Entres/sorties
Oprations permettant la communication
entre le programme et l'extrieur
Unit centrale : egocentrique
Sortie
Exportation d'une valeur vers l'extrieur
(criture) travers un priphrique de
sortie : cran, rseau , fichier, port srie
ou parallle, pipe..
Entre
introduction d'une valeur l'intrieur du
Unit centrale
programme (lecture) travers un
priphrique d'entre : clavier, rseau,
fichier, port srie ou parallle, pipe..

43
Comment afficher : printf
On utilise des fonctions dj crites : il faut inclure un fichier d'entte au
dbut du fichier
#include <stdio.h> Aller la
ligne

Afficher un message :
printf("Mon message\n");

Afficher un nombre :
printf("Mon entier i : %d\n", i );

Un message optionel

%d : le symbole % Le nombre
indique que la lettre afficher
suivante est le type du
nombre afficher 44
printf : exemple
Syntaxe : Affichage d un type de base
int printf(const char * format, variable1, variable2, ...);

format : %[*][largeur] [.precision] [modif type] type_carac


spcifier le type du nombre afficher (type_carac) par
%d : nombre entier
%c : un caractre
%lf : un rel double prcision
%f : un rel simple prcision
En option, on peut prciser le nombre de chiffres que lon souhaite pour laffichage par le nombre largeur
et le nombre de chiffre apres la virgule pour un rel par le nombre prcision

45
printf : exemples
Exemple : affiche0.c
#include <stdio.h>
main() { double x; int a;
x = 3.1415927;
a=6;
/* Afficher un message */
printf("Bonjour.\n");
/* Afficher un reel avec 6 chiffres dont 2 apres la virgule */
printf("Pi vaut %6.2lf\n",x);
/* Afficher plusieurs nombres entier ou reels */

printf("La somme de a et x: %d + %lf vaut %lf\n",a, x, a+x);


}

Un message Le premier nombre Le deuxime nombre


facultatif affich est lentier a affich est le reel x

46
printf : le pige
Erreur sur le type des
nombres afficher
Exemple : affiche0a.c
a est un entier, le
#include <stdio.h>
format demand (%lf)
main() { double x; int a;
est celui des rels
x = 3.1415927;
idem pour x
a=6;
==>
/* Afficher un message */
le programme est
printf("Bonjour.\n");
syntaxiquement correct,
printf("Le nombre a : %lf \n", a);
la compilation est correcte,
printf("Le nombre x : %d \n", x);
mais lexecution du
}
programme, lAFFICHAGE sera
incohrent

47
Lire au clavier: scanf
On utilise des fonctions dj crites : il faut inclure un fichier d'entte au
dbut du fichier
#include "stdio.h" ATTENTION au
symbole &

Lire un nombre au clavier :


scanf("%d", &i); Ladresse de la
Aucun message variable lire
spcifier le type du nombre lire dans le format
%d : nombre entier
%c : un caractre
%lf : un rel double prcision %d : le type de i
%f : un rel simple prcision
Spcifier ensuite le nombre lire
Par ladresse dune variable

48
scanf : exemple
Syntaxe : lecture d un type de base
int scanf(const char * format, adresse_variable1, ...);
format : %[*][largeur] [.precision] [modif type] type_carac

Exemple : lecture0.c
#include <stdio.h>
main() { double x; int a;
/* Afficher un message pour demander les nombres a lutilisateur*/
printf("Entrer un nombre reel \n");
/* Il faut taper un reel au clavier */
scanf("%lf", &x);
/* Afficher un reel avec 6 chiffres dont 2 apres la virgule */
printf("La variable x vaut : %6.2lf\n",x);
printf("Entrer un nombre entier \n");
/* Il faut taper un entier au clavier */
scanf("%d", &a);
/* Afficher un entier */
printf("La variable a vaut : %d\n",a);
}
49
scanf : lire plusieurs
nombres en une fois
Exemple : lecture1.c
#include <stdio.h>
main() { double x,y; int a;
/* Afficher un message pour demander les nombres a lutilisateur*/
printf("Entrer un nombre entier puis 2 reel\n");
/* lire un nombre entier puis 2 reels */

deuxime nombre : le rel x


scanf("%d %lf %lf", &a, &x, &y);

Le premier nombre tap


au clavier sera stock dans
la variable entiere a
printf("Le nombre a vaut : %d\n",a);
printf("Le nombre x vaut : %lf\n",x);
printf("Le nombre y vaut : %lf\n",y);
}
50
scanf: les piges
Exemple : lecture0a.c Erreur sur le type des
#include <stdio.h> nombres lire ==> Valeur
main() { double x; int a; incohrente
printf("Entrer un nombre reel \n");
scanf("%d", &x);
Oubli de ladresse ==>
printf("Entrer un nombre entier \n"); Valeur incohrente ou
scanf("%d", a); arret du programme
/* Afficher un entier */
printf("La variable a vaut : %d\n",a);
}

51
Exos:

Exo 1 : Calculer et afficher la somme de 3 nombres rels lus au


clavier
Exo 2 : Calculer et afficher la moyenne de 3 nombres entiers lus
au clavier
Exo 3 : Calculer et afficher le quotient de 2 nombres rels lus au
clavier. Pourquoi, en utilisant uniquement ce qui vient detre vu, ce
programme nest-il pas correct ?
Les structures de
contrles
Les structures de
contrles
Structures de contrle
Ruptures au sein du droulement squentiel du programme
Deux types
Conditionnelles : faire une action si un test est vrifi
Rptitives : rpter une action un certain nombre de fois
Mots cls :
if, else, switch, case, do..while, while, for

54
Conditionnelle : if
Une instruction conditionnelle simple
permet de raliser une ou plusieurs
actions selon un test sur une expression

Syntaxe
if ( expression ) instruction1;
[ else instruction2; ]

Signification
SI expression est vraie ( != 0 ) , instruction1 est excute
sinon instruction2 est excute

La clause else instructions2; est optionnelle


Clauses if et else
Une clause comporte une seule instruction ou plusieurs instructions encadres par {.} qui dfinissent
un bloc

Imbrication de plusieurs if else


clause else se rapporte au if le plus proche 55
Exemple
Exemple : if1.c : on affiche le plus grand des 2 nombres
Les 2 clauses if et else comportent chacune une seule instruction

#include <stdio.h>
main() { int a,b;
printf("Entrer 2 entiers\n");
scanf("%d %d",&a,&b);
if (a>b)
printf("a:%d est plus grand que b%d\n",a,b);
else
printf("b:%d est plus grand que a%d\n",b,a);
printf( "Fin du programme\n");
}

56
Exemple

57
Exemple 2
Exemple : if2.c : on calcule en plus la diffrence absolue entre les 2 nombres
Les clauses if et else comportent plusieurs instructions DANS un bloc
#include <math.h>
#include <stdio.h>
main() { int a,b,c;
printf("Entrer 2 entiers\n"); scanf("%d %d",&a,&b);
if (a>b) {
c=a-b; Plusieurs instructions :
printf("a:%d est plus grand que b:%d\n",a,b); il faut un bloc entre { }
}
else {
c=b-a;
printf("b:%d est plus grand que a:%d\n",b,a);
}
printf("la racine carree de la difference absolue vaut %lf\n",sqrt(c));
}

58
Un pige
Exemple : if3.c : on teste si 2 nombres sont gaux

Attention :
loprateur = affecte la valeur de droite dans la variable de gauche
loprateur == teste si les 2 expressions sont gales

#include <stdio.h> Ici, on met la valeur de


main() { int a,b; b dans a, puis on teste
printf("Entrer 2 entiers\n"); si ce rsultat est vrai
scanf("%d %d",&a,&b); (non nul) ou faux (nul)
if (a=b)
printf("a:%d est egal a b%d\n",a,b);
else Si on veut simplement
printf("b:%d nest pas egal a%d\n",b,a); tester si a et b sont
printf( "Fin du programme\n"); gaux, il faut utiliser
} if (a == b)

59
Structure conditionnelle
multiple
Une instruction conditionnelle multiple
permet de raliser une ou plusieurs
actions selon un ou plusieurs tests
squentiels sur une expression
positionner d'abord les cas les plus
courants (raliss le plus rapidement)

Syntaxe
switch ( expression ) {
case constante1 : instructionS1;
case constante2 : instructionS2;
..
[ default : instructionS; ]
}
/* Fin du switch */

60
Menu
Exemple 2 : switch2.c
main() { char i; int cout;
printf ( "Au menu : \n") ;
printf ( "\t 1 : Vin rouge\n ") ;
printf ( "\t 2 : Vin blanc \n ") ;
printf ( "\t 3 : Biere \n ") ;
printf ( "\t 4 : Eau\n ") ;
printf ( "\t 5 : Rien \n ") ;
printf ( "Tapez votre choix ") ;
i= getchar(); /* Lecture clavier de la reponse = scanf("%c",&i);*/
printf("Vous avez choisi :");
switch ( i) {
case 1' : printf("un rouge"); cout=100; break;
case 2' : printf("un blanc"); cout=60; break; Quitte le cas 1 et
case 3' : printf("une biere"); cout=80; break; passe la fin du
case 4' : printf("de leau"); cout=10; break; switch
case 5' : printf("pas soif"); cout=0; break;
default : printf("Choix non valide"); cout=0; break;
}
printf(" pour un cout de %d\n",cout);
} 61
Structure rptitive
Une instruction rptitive est une construction permettant de rpter en
squence une ou plusieurs actions selon un test d'arrt donn.

2 instructions
tant que test_vrai rpter instructions;
On vrifie dabord quon a le droit de faire les instructions, et on execute instructions
tant que le test est vrai.

rpter instructions tant que test_vrai ;


On fait dabord les instructions puis on vrifie la condition. Si elle est vraie, on
recommence, sinon, on arrete.

62
Structure rptitive : do ..
while
Faire au moins une fois qqchose
Syntaxe
do {instructions;} while (expression);
instruction est excute tant que lexpression est vraie ( != 0 ) ,

Exemple1 : do1.c : vrife les valeurs dun utilisateur


main() { int i;
printf ( "Au menu : ") ;
do {
printf ( "1 : Vin rouge\n ") ;
printf ( "2 : Vin blanc\n ") ;
printf ( "3 : Biere \n ") ;
printf ( "4 : Eau\n ") ;
printf ( "5 : Rien \n ") ;
OU printf ( "Tapez votre choix ") ;
logique scanf("%d",&i); /* Lecture au clavier */
} while (i<=0 || i>=6);
printf(Mon choix est: %d \n",i);
}
Rponses de
lutilisateur 63
Structure rptitive : while
Faire plusieurs fois qqchose
Syntaxe
while (expression) {instructions;}
tant que expression est vraie ( != 0 ) , instruction est excute

Exemple1 : while1.c : Compte de 2 en 2 jusqu 100 et affiche le nombre


main() { int i=0;
while (i<100) {
i = i + 2; /* On peut crire i += 2; en C */
printf("%d ",i); /* On affiche i */
}
puts("");
}
Quels sont le premier et le dernier nombre affichs ?

64
Structure rptitive : for
Boucle FOR Que font ces deux exemples ?
instruction rptitive la plus courante
Exemple1 : for1.c
localise les parties en les dissociant du
main() {
reste du code :
initialisation (expr1),
int i;
test d'arrt de la boucle (expr2) for (i=0; i < 100; i++)
passage l'itration suivante (expr3) printf("%d ",i);
ne ncessite pas de connatre l'avance printf("\n");
le nombre d itrations }
Syntaxe
for(exp1; exp2; exp3;) instruction;
Exemple2 : for2.c
main() { int i; char c=a;
Identique puts("taper votre texte, finir par q");
expr1; for (i=0; c!=q'; i++) {
while ( expr2 ) { /* Lecture dun caractre */
instruction; c=getchar();
(expr3);
printf("caractere lu : %c\n",c);
}
}
printf("La valeur de i est %d\n",i);
65
}
Rupture de squence
Instruction continue
Passe litration suivante dune boucle

Instruction break
Quitte une boucle ou un switch

Instruction exit ( n )
Sortie d'un programme et retour au systme d'exploitation. La valeur de retour est n

66
Exo

Exo 1: Faire un programme qui affiche la valeur absolue dun rel


lu au clavier.
Exo 2: Calculer la somme des N premiers entiers et vrifier quelle
fait N*(N+1)/2. N est lu au clavier.
Exo 3: Calculer et afficher les 100 premiers termes de la suite Un =
Un-1 + 2
p 1 1 1 1 1
Exo 4 : Calculer Pi par la limite de = 1- + - + - +...
4 3 5 7 9 11
Les nombres
Reprsentation des
nombres entiers
Notion de bit, octet, mot machine
bit : 1 unit d information : 1 ou 0
octet : 8 bits
27 26 25 24 23 22 21 20
b7 b6 b5 b4 b3 b2 b1 b0

A = b7*27+ b6*26+ b5*25+ b4*24+ b3*23+ b2*22+ b1*21+ b0*20

Nombres positifs : dcomposition en Nombres ngatifs : complment 2


puissance de 2 Complmenter le nombre positif ( 0 =>1
et 1=> 0) et Ajouter 1

Nombre Reprsentation binaire


0 00000000
1 00000001
2 00000010
3 00000011
127 01111111

69
Nombres entiers
1 octet : 8 bits
unsigned char : Nombres non signs : 0.. 255=28-1
char : Nombres signs : bit 7 = bit de signe : -128=-27..127=27-1
2 octets : 16 bits
unsigned short : Nombres non signs : 0.. 65535=216-1
short : Nombres signs : bit 15 = bit de signe : -32768=-215..32767=215-1
4 octets : 32 bits
unsigned long : Nombres non signs : 0.. 4294967296=232-1
long : Nombres signs : bit 31 = bit de signe
: -21474836488=-231..21474836487=231-1
8 octets : 64 bits
unsigned long long : Nombres non signs : 0.. 18446744073709551615 =264-1
long : Nombres signs : bit 63 = bit de signe
: -9223372036854775808=-263.. 9223372036854775808 =263-1

Consquences sur lArithmtique entire


Pas d'erreur de calcul : i+1 est toujours exact sauf quand on dpasse les limites
Domaine de validit limit :
70
Exemple en char : 127 + 1 = -128; 127+2=-127; 127+3=-126.
Nombres rels
Norme IEEE 754 : Spcifie un modle arithmtique complet pour les rels
Format gnral
Signe : s Exposant : e Mantise : m

X plus proche suivant Diffrence


Reprsentation binaire finie : 1.0 1.0000001 1.19 10-7
Nombres de rels FINI !!! 2.0 2.0000002 2.38 10-7
Linfini nexiste pas
16.0 16.000002 1.9 10-6
L cart entre 2 rels conscutifs est relatif
128.0 128.00002 1,52 10-5

Consquences : la Troncature : il existe toujours une erreur de calcul


Laddition et la multiplication ne sont plus exactement associatives
(3.11 * 2.30) * 1.50 = 10.729500000000000
3.11 * (2.30 * 1.50) = 10.729499999999998
La multiplication nest plus distributive
Attention : les erreurs se cumulent
71
Prcision et limites des
rels
Rels simple prcision : 32 bits : float
Mantisse sur 23 bits, exposant sur 8 bits
Max : +/- 2128 soit +/- 3x1038 Min : +/- 2-150 soit +/- 1x10-45
Prcision : 2-23 soit +/- 1x10-7
Rels double prcision : 64 bits : double
Mantisse sur 52 bits, exposant sur 11 bits
Max : +/- 21024 soit +/- 1x10308 Min : +/- 2-1075 soit +/- 1x10-324
Prcision : 2-52 soit +/- 1x10-16
Rels quadruple prcision : 128 bits (80 bits sur intel) : long double
Mantisse sur 112 bits (64 bits sur intel), exposant sur 15 bits
Max : +/- 216383 soit +/- 3x104932 Min : +/- 1x10-4966
Prcision : 2-112 soit +/- 1x10-34 (2-64 soit +/- 1x10-19 sur intel)

Conclusion sur larithmtique relle


Les rels ont un domaine de variation limits (mais plus grand que les entiers)
Les calculs en rel ont une prcision trs limite, mais suffisante dans la plupart des cas

72
Calcul flottant : exemple
Exemple : /* Fichier cunu2.c*/
Ajouter un reel 1 pour visualiser lerreur de calcul
#include <stdio.h>
main() { float x,y;
printf("Entrer le nombre reel a ajouter a 1 "); scanf("%f",&x);
y = 1/ ( (1+x) - 1);
printf("Valeur de x:%.15f et de 1+x:%.15f\n",x,1+x);
printf("Valeur de 1+x-1:%.15f et de y:%.15f\n",(1+x)-1,y);
}
Valeur de y exacte 10-5 pres

Plus proche rel de


0.0001. Ce nest
pas exactement 10-4

Troncature car x
est trop petit Valeur de y inexacte 73
Calcul flottant : exemple
Cumul des erreurs et non associativit

Exemple : /* Fichier cunu2c.c et cunu2d.c*/


Calcul des 80 premiers termes de Xn = (R+1)Xn-1-R*Xn-1*Xn-1
par X = (R+1)*X - (R*X)*X; dans cunu2c avec R=3 et X0=0,5
Par X = (R+1)*X - R*(X*X); dans cunu2d

Affichage des termes 0, 10, 20 ,30 40, 50,60,70 et 80

74
Reprsentation des
Caractres : code skis

75
Code ascii
units
Dizaines

76
Caractres : code ascii
char : 1 octet main() { char x;
x =65;
La valeur stocke est toujours 8 bits printf(decimal:%d ,x);printf(char %c \n,x);
binaire putchar(x); puts();
Seule la manire dont le
programmeur regarde cet octet x = x + 2;
printf(decimal: %d ,x);printf(char %c \n,x);
modifie la perception dont nous la
voyon
x = A;
printf(decimal: %d ,x);printf(char %c \n,x);
puts("Entrer un caractre");

x = getchar(); /* ou scanf((%c,&x);*/
printf(decimal: %d ,x);printf(char %c \n,x);
putchar(x); puts();
}

.
Adresse de x : oxbffff24f 67
65
65
101
77
Oprateurs
Oprateurs Associativit
() [] -> . gauche droite
! ~ ++ -- + - * & (type) sizeof droite gauche
* / %(modulo) gauche droite
+- gauche droite
<< >> : dcalage de bits gauche droite
< <= > >= gauche droite
== != gauche droite
& : ET bit bit gauche droite
^ : Et exclusif bit bit gauche droite
| : OU bit bit gauche droite
&& : ET logique gauche droite
|| : OU logique gauche droite
?: droite gauche
= += -= *= /= %= ^= |= <<= >>= droite gauche
, gauche droite

78
Tableaux
Tableaux
Adresse 0
Tableaux
Collection de variables de mme type, ranges continment
en mmoire
Dclaration : spcifier
le type des lments
le nom du tableau tab tab[0]: 0 &tab[0]
le nombre des lments
Exemples : tab[1]: 2 &tab[1]
float c[100]; /* tableau de 100 rels */
tab[2]: 4 &tab[2]
int tab[10]; /* tableau de 10 entiers*/

Exemple : tab1.c
main() { int i; tab[9]: 18 &tab[9]
int tab[10]; /* Tableau de 10 entiers */
float c[20]; /* Tableau de 20 rels */
for (i=0; i<10; i++) tab[i]= 2*i;
/*Mettre 0,2,4,6..dans les elements*/

for (i=0; i<10; i++) printf("%d ",tab[i]);
/* afficher les lments de t */
} 80
Tableaux

81
Tableaux 2
Adresse
0
Remarques
Nombre dlments constant, non modifiable
Le nom du tableau est son adresse (ie lendroit o il se trouve &tab[-2]
en mmoire

Accs un lment du tableau : tab 0 &tab[0]


nom_du_tableau[expression entiere] tab+1 2 &tab[1]
Exemple : tab[i] tab+2 4 tab[2]

Comment fait le compilateur : on part du dbut du tableau, on


ajoute i : cest lendroit o se trouve notre lment
tab+9 18 &tab[9]
Attention : Pas de vrification sur les indices. Si on
demande un lment avant ou aprs la fin du tableau,
cest une erreur lexecution du programme mais pas
derreurs la compilation &tab[900]

82
Tableaux 3
Adresse 0
Exemple 2 : tab2.c
main() { int i; int tab[10];
for (i=0; i<10; i++) tab[i]= 2*i;
puts("Voici les elements : ");
0xbffff37c &tab[-2]
/* afficher les lments de t */
for (i=0; i<5; i++) printf("%d ",tab[i]);
puts(""); puts("Voici les adresses : "); 0xbffff384 0 &tab[0]
/* afficher les adresses */ 2 &tab[1]
0xbffff388
for (i=0; i<5; i++) printf("%p ",tab+i);
puts(""); 0xbffff38c 4 &tab[2]
tab[-2]= 18952;
printf("%d ",tab[900]);
} 18 &tab[9]
0xbffff3a8

0xc0000194 &tab[900]

83
Tableaux 4
Attention : AUCUNE opration globale sur un tableau
les oprations et les E/S doivent se faire lment par lment
En particulier
T1==T2 ne teste pas lgalit de 2 tableaux
T1=T2 ne recopie pas les lments de T1 dans T2

Exemples : tab3.c
main() {int i; double t1[10], t2[10];
/* t1 et t2 sont 2 tableaux de 10 rels */
for (i=0; i<10; i++) {t1[i]=2*i; t2[i]=log(100*i+1); }
printf("Emplacement de t1:%p de t2:%p\n",t1,t2);
printf("Emplacement de t1[1]:%p de t2[1]:%p\n",t1+1,t2+1);
printf("Valeur de t1[0]:%lf de t2[0]:%lf\n",t1[0],t2[0]);
if (t1==t2) printf("t1 et t2 sont au meme endroit\n");
else printf("t1 et t2 ne sont pas au meme endroit\n");
for (i=0; i<10; i++) t2[i]= t1[i];
/*Copie de t2 dans t1: on peut remplacer cette ligne par:
memcpy(t2,t1,sizeof(t1));
Mais on ne peut pas utiliser t1=t2; */
for (i=0; i<10; i++) printf(Valeur de t2[%d] : %lf\n,i,t1[i]);
} 84
Tableaux 5
Adresse
0

0xbffff328 0 &t2[0]

0xbffff330 2
4.6 &t2[1]

4
5.3 &t2[2]

0xbffff370 18
6.8 &t2[9]

0xbffff378 0 &t1[0]

0xbffff380 2 &t1[1]

4 &t1[2]

0xbffff3c0 18 &t1[9]
85
Tableaux 6
Les fonctions travaillant sur les zones mmoires : comme un tableau est
une zone mmoire continue, on peut utiliser ces fonctions avec les tableaux
#include <string.h>

void * memmove(void *s1, const void *s2, size_t n);


Copie n octets de la zone de mmoire src vers la zone dest. Les deux zones peuvent se
chevaucher.

void *memcpy (void *dest, const void *src, size_t n);


idem, mais les zones ne peuvent pas se chevaucher

int memcmp (const void *s1, const void *s2, size_t n);
compare les n premiers octets des zones mmoire s1 et s2.

void *memset (void *s, int c, size_t n);


remplit les n premiers octets de la zone mmoire pointe par s avec loctet c.

void swab (const void * from, void * to, ssize_t n);


copie n octets de la zone from dans la zone to, en changeant les octets adjacents
86
Exos
Faire un programme qui lit les lments d'un tableau de 5 rels au clavier

Faire un programme qui cre 3 tableaux de 10 rels, ajoute les 2 premiers tableaux dans le
troisime et affiche ce dernier tableau

Faire un programme qui recherche la valeur la plus petite dun tableau et qui laffiche

Faire un programme qui fait la somme de tous les lments dun tableau
Fonctions

Fonctions
Fonctions
Une fonction est une unit de traitement dans un programme

Une fonction est utilise pour :


Structurer le programme
Dcomposer un problme en sous problmes
Spcifier les dpendances entre ces sous problmes
Meilleure lisibilit des tapes de rsolution
Rutiliser le code
une meme fonction peut etre utilise plusieurs fois
Sparer et rendre tanche diffrentes parties d'un programme.
limite les propagations d'erreurs
Offrir une maintenance du code plus aise

Une fonction prend en entre des donnes et renvoie des rsultats aprs avoir ralis
diffrentes actions

89
Utiliser une fonction
Dclarer le prototype
Le prototype dune fonction indique comment doit tre utilise une fonction. Il comporte le nom, la
liste des paramtres et la valeur de retour suivi dun ";"
L 'appel ou lexecution de la fonction se fait avec les paramtres effectifs par
nom_fonction(paramtres);
Exemple

int max( int a, int b);


/* Prototype dune fonction appele max,qui prend 2 entiers en paramtres et
qui retourne un entier. */

main() {int i,j,k,l,m,n; /* 6 entiers */


i=10; j=20; k=-8; l=12; i et j sont les paramtres effectifs
m=max(i,j); /* On appelle max avec i et j, le resultat est mis dans m*/
printf("Le max de %d et de %d est %d\n",i,j,m);
n=max(k,l); /* On appelle max avec k et l, le resultat est mis dans n*/
printf("Le max de %d et de %d est %d\n",k,l,n);
}
k et l sont les paramtres effectifs

90
Ecrire une fonction
Une fonction est constitue de
Son nom
Sa liste de paramtres sils existent
Son type de valeur de retour
Des instructions indiquant ce quelle doit faire

Le code de la fonction scrit en utilisant les paramtres "formels

La valeur de retour
Est unique et scalaire : par exemple, une fonction ne peut pas renvoyer 2 rels
est renvoye laide de linstruction " return " : on quitte la fonction IMMEDIATEMENT, on
revient la fonction qui a appele

Exemples : f2.c a et b sont les paramtres formels


int max(int a, int b) { int c;
if (a>b) c=a;
else c = b;
c est la valeur retourne la
return c;
} Fonction appelant max
91
Executer une fonction
Lors de lappel max(i,j) : Les parametres sont copis sur Adresse 0
la pile (zone mmoire particulire) en commencant par le
plus droite, soit j en premier.
On execute alors max
j et i sont recopis dans b et a
La fonction max utilise alors a et b et fait son travail
a et b sont dtruites quand la fonction se termine en executant
return
On revient ensuite la fonction appelante (ici main) 0xbffff3b0 10 a

0xbffff3b4 20 b
int max(int a, int b) {
if (a>b) return a;
else return b;
0xbffff3d8 10 i
}
0xbffff3dc 20 j
main() {int i,j,k; i=10; j=20; k=0;
20
0 k
printf("i:%d j:%d\n",i,j);
k=max(i,j);

printf("i:%d j:%d \n",i,j,);
}
92
Passage par valeur
Lorsquune fonction est appele, elle travaille avec une copie des paramtres effectifs
: une fonction ne peut jamais modifier les paramtres quon lui donne
i (a est une copie de i) ne peut etre modifi
Exemples : f3.c : fonction qui calcule le produit de 2 nombres
void mult1(int a, int b) {
printf("Valeur de a:%d et b:%d au debut de la fonction\n",a,b);
printf("Adresse de a:%p et b:%d au debut de la fonction\n",&a,&b);
a = a * b;
printf("Valeur de a:%d et b:%d en fin de fonction\n",a,b);
}/* Erreur, car a ne sera pas modifi */

main() {int i,j,k,l,m,n,c; /* 7 entiers */


i=10; j=20; k=-8; l=12; m=n=c=0;
printf("Valeur de i:%d j:%d m:%d avant lappel de mult1\n",i,j,m);
printf("Adresse de i:%p et j:%p avant lappel de mult1 \n",&i,&j);
mult1(i,j); /* On appelle max avec i et j, mais i et j ne peuvent pas etre
modifies*/
printf("Valeur de i:%d j:%d m:%d apres lappel de mult1\n",i,j,m);
printf("Adresse de i:%p et j:%p apres lappel de mult1 \n",&i,&j);
/* ICI, i vaut toujours 10 /
} 93
Paramtres des fonctions
Lors de lappel mult1(i,j) : Les parametres sont copis sur Adresse 0
la pile (zone mmoire particulire) en commencant par le
plus droite, soit j en premier.
On execute alors mult1
j et i sont recopis dans b et a
La fonction mult utilise alors a et b
a et b sont dtruites quand la fonction se termine
On revient ensuite la fonction appelante (ici main)
i et j ne sont pas modifies, car ce sont les copies a et b 0xbffff3b0 10
200 a
qui ont t modifies b
0xbffff3b4 20

void mult1(int a, int b) {


a = a * b;
0xbffff3d8 10 i
}
0xbffff3dc 20 j
main() {int i,j,k; i=10; j=20; k=-8;
printf("i:%d j:%d\n",i,j);
mult1(i,j);
printf("i:%d j:%d
k:%d\n",i,j,k);
}
94
Variables locales
Les variables locales la fonction (la variable c) sont cres au moment o elles
sont dclares, et dtruites la fin du bloc, au moment o la fonction se termine

Les paramtres de la fonction (les parametres a et b) sont cres au moment o la


fonction est excute, et dtruites au moment o la fonction se termine

Exemples : f4.c
int mult2(int a, int b) { int c;
c = a * b;
return c;
}

main() {int k,l,n,c; /* 4 entiers */


k=10; l=20; n=0; c=15;
printf("Valeur de k:%d l:%d n:%d c:%d avant lappel de mult2\n",k,l,n,c);
n=mult2(k,l); /* On appelle mult2 avec k et l, le resultat est mis dans n*/
printf("Valeur de k:%d l:%d n:%d c:%d apres lappel de mult2\n",k,l,n,c);
/* ICI, c vaut toujours 0, la variable c de mult2 nexiste plus */
}

95
Variable locales
Lors de lappel mult2(i,j) : Les parametres sont copis sur Adresse 0
la pile (zone mmoire particulire) en commencant par le
plus droite, soit j en premier.
On execute alors mult
a et b sont des copies de k et l
la variable c est cre sur la pile 0xbffff3b0 10 a
La fonction mult utilise alors a et b b
la variable c est dtruite lorsque la fonction se termine 0xbffff3b4 20
a et b sont dtruites quand la fonction se termine
On revient ensuite la fonction appelante (ici main)
1852
200
i et j ne sont pas modifies c de mult2

int mult2(int a, int b) {int c=1852;


c = a * b;
return c; c de main
} 0xbffff3c0 -8 &c

main() {int k,l,n,c; k=10; l=20; c=-8; 0xbffff3c4 200


??????? &n

printf("k:%d l:%d\n",k,l); 0xbffff3c8 20 &l


n=mult2(k,l); 0xbffff3cc 10 &k
printf("k:%d l:%d n:%d c:%d
\n",k,l,n,c);
96
}
Passer un tableau 0
Adresse

int min1(int tab[], int dim) {


int i,vmin; ???
10 vmin
for(vmin=tab[0], i=1; i<dim; i++)
if(vmin>tab[i]) vmin=tab[i]; 4
???? i
return vmin; 0xbffff3d8 tab
0xbffff3b0
}
main() {int res,i,n=4, t1[4]; 0xbffff3b4 4 dim
for(i=0;i<4;i++) t1[i]=10+i;
res=min1(t1,n);
printf("minimum:%d \n",res);
}
0xbffff3d8 10 t1
Pour passer un tableau, on dclare un paramtre de type tableau
0xbffff3dc
Souvent, on ajoute un parametre donnant le nombre dlments du tableau 11
Lors de lappel min1(t1,n) : Les parametres sont copis sur la pile 12
13
ATTENTION; tab est ladresse du tableau !!!!
0xbffff3e8 4 n
On execute alors min1 0xbffff3ec 4 i
n et t1 sont recopis dans dim et tab
La fonction min1utilise alors tab et dim 0xbffff3f0 10
??? res
dim et tab sont dtruites quand la fonction se termine

On revient ensuite la fonction appelante (ici main)
97
En pratique
Pour ecrire une fonction, vous devez
Dfinir son rle, ses paramtres
Pour savoir quels sont les paramtres dune fonction, dfinisez clairement le role de cette fonction
Par exemple :
Une fonction retourne la racine carre dun rel implique que la fonction a un seul paramtre
rel; Son prototype est donc : double sqrt(double);
Une fonction retourne le plus petit lment dun tableau de n rels implique que la fonction a 2
paramtres : un tableau de rel et un entier indiquant la taille du tableau. Son prototype est
donc : double min(double t[], int n);
Faire Un fichier dentete (extension .h : fonction.h) contenant le prototype de la fonction
Faire Un fichier source C (extension .c : fonction.c) contenant le code de la fonction
Editer le fichier f.h
int max(int a, int b);

Editer le fichier f.c


int max(int a, int b) { int c;
if (a>b) c=a; else c=b;
return c;
}
98
En pratique
Pour utiliser une fonction, vous devez
Inclure le fichier dentete au dbut de votre code par #include "fonction.h
Utiliser votre fonction dans votre programme, ecrit dans le fichier p.c
Compiler le fichier contenant la fonction : gcc c f.c
Compiler le fichier utilisant la fonction : gcc c p.c
Crer un executable en ralisant ldition de liens : gcc p.o f.o o p

Editer le fichier p.c


#include <stdio.h>
#include "f.h"
main() {int i,j,m; /* 7 entiers */
i=10; j=20;
m=max(i,j);
printf("Valeur de i:%d j:%d m:%d \n",i,j,m);
}

99
Exos

Faire une fonction qui renvoie la valeur absolue dun entier.

Faire une fonction qui renvoie le produit de 3 nombres rels passs en paramtres

Faire une fonction qui calcule la factorielle dun nombre pass en un paramtre
Pointeurs

Pointeurs
Pointeurs
Variable contenant ladresse dun autre objet (variable ou fonction)
Adresse : numro dune case mmoire

Dclaration : type_point* identificateur;


Exemples :
int* p1; /* p1 contient ladresse dun entier */
double* p2; /* p2 contient ladresse dun rel */

ATTENTION : un pointeur doit toujours tre initialis avant dtre utilis = Il doit contenir
une adresse lgale :
soit celle dun objet existant
soit celle obtenu par une demande dallocation dynamique
soit NULL, qui est la valeur 0. Il est interdit de lire et crire l'adresse 0

Remarque : on affiche la valeur dun pointeur en hexadecimal par


printf("Voici la valeur du pointeur %p\n",p);
102
Pointeurs Pointeurs
Exemple : p1.c Adresse 0
main() {
int i=0;
int* p1=NULL; /* p1: pointeur sur un entier */
p1 = &i; /*p1 pointe i, ie contient ladresse de i*/
/* ICI, i ou *p1 sont une seule et meme chose */
*p1 = 5; /* identique i=5; */
printf("Valeur de i:%d, Adresse de i:%p\n",i,&i);
printf("Valeur de p:%p, Valeur pointe:%d\n",p1,*p1);
printf("Adresse de p:%p\n", &p1);
0xbffff388 p1=0xbffff38c
p= 0 &p
}
0xbffff38c i= 0
5 &i

103
Oprations sur pointeurs
Affectation : donner une valeur au pointeur, celle dune adresse lgitime.
p1=&i; /* &i : l'adresse de i */

Indirection : trouver la valeur pointe par p.


j = *p1; /* *p1 : ce qu'il y a l'adresse p1 */

Comparaison :
== et != : p1==p2; p1 et p2 regardent ils la meme adresse ?
<, >, <=, >= : par exemple, p1<p2 sur un meme tableau, p1 est il avant p2
Arithmtique
Adresse + entier ==> adresse : p1 +1 est ladresse de llment suivant p1
Adresse - Adresse ==> entier : p2 -p1 est donc le nombre dlments entre les adresses contenues dans
p2 et p1. Valide uniquement si p1 et p2 sont de meme type.

ATTENTION : les pointeurs tant typs, les oprations se font en nombre dlments et
non en nombre doctets
104
Adresse et tableaux
Nom du tableau : adresse du tableau

Accs un lment t[i] :


on part de ladresse de dbut du tableau, on ajoute i et on obtient ladresse du
ime lment.
Llment est obtenu par loprateur dindirection *

Consquences
Llment t[i] s crit aussi *(t+i)
Ladresse de t[i] scrit &t[i] ou bien (t+i)

105
Adresses et tableaux
Adresse 0
Exemple : p3.c
main() { int tab[10]; int i;
for (i=0; i<10; i++) tab[i]= 2*i;
puts("Voici lelement dindice 2 : ");
printf("%d %d",tab[2],*(tab+2));
puts(""); puts("Voici les adresses : ");
for (i=0; i<5; i++) 0xbffff364 0 &tab[0]
printf("%p %p",tab+i, &tab[i]); 0xbffff368 2 &tab[1]
}
0xbffff36c 4 &tab[2]
2 manires diffrentes d'ecrire l'adresse de t[i]

0xbffff388 18 &tab[9]

106
Parcourir un tableau avec
un pointeur
Adresse 0
Exemple : p4.c
main() {int* p=NULL; int i; int tab[5];
for (i=0; i<5; i++) tab[i]=2*i+1; 0xbffff384 1
tab[0]=234 &tab[0]
p=tab; 3 &tab[1]
0xbffff388 tab[1]=234
while (p<tab+5) {
printf(" Pointeur: %p ",,p); 0xbffff38c tab[2]=234
5 &tab[2]
printf(" Valeur %d",*p); 7
tab[3]=234 &tab[3]
0xbffff390
*p=234;
0xbffff394 tab[4]=234
9 &tab[4]
printf("Valeur modifiee %d\n",*p);
p++; 0xbffff398 i= 5 &i
} &p
0xbffff39c 0xbffff394
0xbffff384
0xbffff388
p=
0xbffff38c
0xbffff390
0

107
Les chaines de caractres
Les chanes de caractres
En C, les chanes de caractres ne sont pas un type particulier
mais sont :
Des tableaux de char, exemple : char t[256];
Termins par \0. Adresse
0

"Ceci est une chaine" est une chaine de caractre constante


0xbffff2e0 u &s[0]
Pour utiliser une chane de caractre, 2 solutions
Crer un tableau et utiliser les fonctions dE/S sur les chanes 0xbffff3e1 n &s[1]
(scanf, gets) qui ajoutent un \0 en fin de chaine.
Crer un tableau et le remplir lment/lment, y compris le \0 e &s[2]
terminal.
\0 &s[3]
les autres valeurs
Exemple : chaine0.c sont alatoires ????
main() {char s[256];
car on ne les a
s[0]=u; s[1]=n;
s[2]=e; s[3]=\0;
pas entres
/* Affichage de s */
puts(s); /* ou printf("%s\n",s);
0xbffff3df ???? &s[255]
}

109
Les chanes de caractres
Exemple : chaine1.c : cre et lit 2 chaines au clavier avec 2 methodes
main() { int i;
char s1[256], s2[256];
puts("Entrer une chaine");

/* Lecture dune chaine. Gets positionne la marque de fin de chaine*/


gets(s1); /* On peut aussi utiliser scanf("%s",s1); */
/* Affichage dune chaine. Utilise la marque de fin de chaine pour afficher
les lments du tableau rellement utilise*/
puts(s1); /* ou printf(%s",s1); */

/* Lecture caractres/caractres de 10 caractres */


for (i=0; i< 10; i++) s2[i]=getchar();
/* Ajout de la marque de fin de chaine */
s2[i]='\0';
/* Affichage de s2 */
puts(s2);
/* Affichage de s2 element/element*/
for (i=0; s2[i]!= '\0'; i++) printf("%c", s2[i]);
}

110
Les chanes de caractres
Les chanes de caractres sont des tableaux

==> AUCUNE opration globale nest possible :


s1==s2 ne compare pas 2 chanes
s1=s2 ne copie pas s2 dans s1

Il faut utiliser les fonctions spcifiques


Concatnation : strcat
Copie : strcpy, strncpy
Comparaison : strcmp, strncmp, strcasecmp, strncasecmp, strcoll
Recherche : strstr, strchr
Longueur : strlen
Decoupage de la chaine en sous chaine : strtok

Toutes ces fonctions mettent le resultat dans une chane de caractres


Attention : la chane recevant le rsultat doit exister et doit avoir une taille
suffisante
111
Chanes de caractres
Copie d'une chane Duplication (allocation et copie) d'une chane
char* strcpy (char* destin, char* source); Cbaine4.c
char* strdup (char* source);
main() { char t1[256], t2[256];
printf("tapez une caine"); gets(t1); main() { char t1[256], t2[256];
strcpy(t2,t1); puts(t2); char* s1; :/* Pas de taille: pointeur
*/
strcpy("chaine", t1); gets(t1);
} s1 = strdup(t1); puts(s1);
Concatnation de 2 chanes :
t2=strdup(t1);
char* strcat (char* destin, char * source);
}
main() { char t1[256], t2[256];
printf("tapez 2 chaines");
gets(t1); gets(t2); Autre exemple
strcat(t1,t2); puts(t1); main() { char t1[256], t2[256], t3[256];
gets(t1);
strcat(strcpy(t2,t1),".obj");
strcat ("ceci est une chaine", t2); strcat(strcpy(t3,t1),".exe");
} puts(t1); puts(t2); puts(t3);
}

112
Chanes de caractres
Comparaison de 2 chanes Formation/extraction dans des chaines
int strcmp (char* chain1, char* chain2) de caractres
int sprintf(char* s, char* format, valeurs)
Retourne : int sscanf(char* s, char* format, adresses)
un entier ngatif si chain1 infrieure
chain2 main() { char t1[256], t2[256];
0 si chain1 identique chain2 int i; float x; double y;
un entier positif si chain1 suprieure
chain2
sprintf(t1,"Valeurs %d et %f et %lf", i,x,y);
ordre lexicographique. puts(t1);

int strcasecmp (char* chain1, char* chain2) strcpy(t1,"1000 10.3 truc 3.14259");
sscanf(t1,"%d %f %s %lf ",&i,&x,t2,&y);
majuscules et minuscules indiffrentes

Comparaison de 2 chanes sur n octets sscanf(t1, "%d %f %lf ",i,x,y) ;


int strncmp(char* chain1, char* chain2, int n) }
/*n= Nombre de caractres comparer */

113
Chanes de caractres
Longueur d'une chane
unsigned strlen ( char* chaine)

Recherche d'une chane


char* strstr (char* chain1, char* chain2)
Recherche de la chaine chain2 dans chaine1.
Retourne l'adresse de la premire occurrence de chaine2 dans chaine1

Recherche d'un caractre


char* strchr (char* chain1, int n)
Recherche du caractre n dans chaine1.
Retourne l'adresse de la premire occurrence du caractre n dans chaine1

114
Chanes de caractres
Dcoupage dune chaine en mots
Char* strtok(char* str, char* separateur)
Dcoupe la chaine str en mots.
Les sparateurs sont dfinis par les caractres de la chaine separateur.
#include <stdio.h>
#include <string.h>
main() { char t1[256], t2[256];
char* p; int i =0;
/* Les separateurs sont espace, virgule, point et point virgule et d'interrogation */
strcpy(t2, " ;.,.");
strcpy(t1,"Voici une chaine. Vide? Non");
/*Iniitalisation du decoupage */
p=strtok(t1, " ;.,.");
while (p!=NULL) {
printf("mot numero %d : %s \n",i,p);
i++;
/* On cherche le mot suivant */
p= strtok(NULL, " ;.,.");
}
}

115
Exos

Ex1 : faire un programme qui calcule la somme des lments d'un tableau
en utilisant uniquement des indices pointeurs (et pas entiers)
Ex2 : faire un programme qui copie un tableau de N entiers (N=10) dans un
autre tableau en utilisant uniquement des indices pointeurs
Ex3 : faire un programme qui lit les lments d'un tableau au clavier en
utilisant uniquement des indices pointeurs (et pas entiers)
Ex4: faire un programme qui lit une chaine de caractres au clavier, puis
calcule la longueur de la chaine (le dernier caractre est \0)

116
Paramtres de fonctions
En C, passage des variables par valeur
Il y a recopie de l'objet effectif (de x et y ci dessous) sur la pile
La fonction travaille sur une copie des objets effectifs (a et b sont des copies de x et de y)
Si la fonction modifie le paramtre formel (a et b), c'est en fait la copie de l'objet effectif qui est modifie
L'objet initial n'est pas modifi (x et y ne change pas)

Exemple : swap1.c
void swap(int a, int b) { int c;
printf( "Debut de swap a:%d ; b:%d . Adresses de a:%p et b:%p\n",a,b,&a,&b);
c=a; a=b; b=c; /* On echange a et b en utilisant c */
printf( "Fin de swap a:%d ; b:%d . Adresses de a:%p et b:%p\n",a,b,&a,&b);
}
main() { int x,y;
x=1; y=2;
printf("Avant swap x:%d de y:%d et des adresses de x:%p et y:%p\n",x,y,&x,&y);
swap(x,y);
printf("Apres swap : x:%d et y:%d . Adresses de x:%p et y:%p\n",x,y,&x,&y);
}

Que fait ce programme ?

117
Paramtres de fonctions
Adresse 0

Appel de la fonction swap : cration des 0xbffff35c 0


1 c
paramtres a et b et de la variable c

Execution de la fonction swap : echange


de a et b 0xbffff3b0 1
2 a
Fin de la fonction swap : suppression des 1
2 b
0xbffff3b4
paramtres a et b et de la variable c

Que valent x et y ?

0xbffff3d8 2 y

0xbffff3dc 1 x

118
Passage par adresse
Comment une fonction peut modifier un paramtre ?
En passant son adresse
Ladresse nest pas modifie
Mais le contenu (obtenu par loprateur *) peut tre modifi
pa et pb sont des adresses de
Exemple : swap2.c variables existantes changer.
Ici, ce seront les adresses de x et y.
void swap2(int* pa, int* pb) { int c; Donc,*pa est la meme chose que x
printf("Debut de swap2: pa:%p ; pb:%p ", pa,pb);
printf("Contenu de pa :%d et pb:%d\n",*pa,*pb);
printf("Adresse de pa :%p et pb:%p\n",&pa,&pb);
c=*pa; *pa=*pb; *pb=c; /* On echange a et b en utilisant c */
printf("Fin de swap2: pa:%p ; pb:%p ", pa,pb);
printf("Contenu de pa :%d et pb:%d\n",*pa,*pb);
}
main() { int x,y;
x=1; y=2;
printf("Avant swap2 x:%d de y:%d et des adresses de x:%p et y:%p\n",x,y,&x,&y);
swap2(&x,&y);
printf("Apres swap2 : x:%d et y:%d . Adresses de x:%p et y:%p\n",x,y,&x,&y);
}
On passe les adresses de x et y

119
Passage par adresse
Adresse 0

0xbffff35c 0
1 c

Appel de la fonction swap2 : cration des 0xbffff3b0 0xbffff3dc pa


paramtres pa et pb et de la variable c
0xbffff3b4 0xbffff3d8 pb

Fin de la fonction swap2 : suppression des


paramtres pa et pb et de la variable c
0xbffff3d8 2
1 y

0xbffff3dc 1
2 x

120
En pratique
Comment sait on quune fonction doit modifier ses paramtres ?
Dfinissez et crivez correctement le rle de la fonction
Exemple 1: la fonction change les valeurs de 2 entiers
==> la fonction a 2 paramtres et elle doit modifier la valeur de ces 2 paramtres
==> ces 2 paramtres doivent tre passs par adresse

Si vous avez crit une fonction avec des paramtres passs par valeur, par
exemple le paramtre a, et que vous souhaitez la transformer pour passer le
paramtre a par adresse
Il suffit de
remplacer dans la fonction a par *a, en prenant garde la priorit des oprateurs
A lappel de la fonction, remplacer la valeur du paramtre par son adresse laide de
loprateur &.

121
Exos
Ex1 : faire une fonction qui prend un double en paramtre et met ce
paramtre la valeur 3.14159. Faire le programme principal qui appelle
cette fonction.
Ex2 : faire une fonction qui prend 2 entiers en paramtres, ajoute un au
premier et soustrait un au second. Faire le programme qui appelle cette
fonction
Ex3 : Ecrire une fonction swap2 qui effectue un echange de 2 variables
Ex4: Ecrire une fonction swap3 qui effectue une permutation circulaire de
trois variables en utilisant la fonction swap2
Ex5 : faire une fonction qui recopie une chaine de caractres dans une autre
chaine.
Ex6 : Donner le prototype de la fonction qui rsoudrait lquation du second
degr dans R

122
Structures

Structures, dfinition de
types
Crer ses propres types
Pourquoi ?
Clarifier l'criture dun programme
Exemple :
jaime pas les int*
je veux indiquer clairement quune variable est un octet et pas un caractre
Dfinir un nouveau type : instruction typedef

typedef ancien_type nouveau_type;

124
Crer ses propres types
typedef unsigned char OCTET;
typedef int* POINTEUR;

void swap(POINTEUR p1, POINTEUR p2) {


int c=*p1;
*p1=*p2;
*p2=c;
} POINTEUR peut remplacer
main() { OCTET a; int i,j; int* partout
POINTEUR p;
a=156; i=32546; p=&i; j=-5;
printf("Valeur de loctet a :%d\n",a);
printf("Valeur de i et de *p :%d %d\n",i,*p);
swap(&i,&j);
}

125
Les structures
Regroupement dinformations de types identiques
ou diffrents struct complex {
Relatif une mme entit abstraite. double im,re;
permet de manipuler sous un mme nom plusieurs };
lments d'informations
struct complex a1;
Exemple :
Un point : une structure comportant les deux
coordonnes X et Y du point
Nom du
Un complexe : les parties relle et imaginaire du
type
complexe.
un etat civil : une structure regroupant le nom, Nom de la
prnom, nSS, age.... variable

Dclaration de type
a1 a1.re
struct ident1 {
type nom_du_champ; a1.im
....
} /* fin de structure */

Dfinition de variable :
struct nomdestructure identif_var; 126
Structures (2)
Un lment chimique avec les informations de type diffrent:
X x.nom
struct element_atomique {
char nom[20] ;
char symbole[4] ;
int nummeroatomique;
double masseatomique;
double densite ;
double fusion ; /* Temperature de fusion en */ x.symbole
double vap; /* Temperature de vaporisation en */
double rayon; /* rayon atomique en A */
x.numeroat
double rayon_cov; /* rayon de covalence en A */
char rayonionique[24] ; /* Rayon ionique */ x.masseato
} x;
x.densit
Le type sappelle
struct element_atomique

127
Structure (3)
Accs un champ
Pour une variable structure :oprateur .
Pour une structure pointe : oprateur ->
0xbffff38c a2.x 0 a2
Oprations sur les structures : aucune sauf
Affectation de structures meme type a2.y -
1
Passage et retour de structures par valeur dans les fonctions 0xbffff394 0xbffff398 pa1
Les lments de la structure sont des variables part
0xbffff398 a1.x 1
0
entire : ils ont une adresse
a1.y - a1

typedef struct { int x,y} T_POINT; 1

void aff(T_POINT a) { On dfinit une structure


printf("%d %d\n",a.x,a.y);
anonyme et un nouveau yype
}
main() { T_POINT a1, *pa1, a2; aff est une fonction qui utilise un
a1.x=1; a1.y=-1; T_POINT : elle a accs aux 2 coordonnes
pa1=&a1; pa1->x=0; de a, a.x et a.y
a2 = a1;
aff(a2); pa1 est un pointeur. Donc, pa1->x
aff(*pa1); est la partie x de a1
} 128
Structures (4)
Aucune autre action globale, sauf la copie
en particulier
Comparaison de structure a1==a2
Lecture/ecriture de structure : printf("%lf",a1);
Il faut tout faire champ par champ Lecture clavier des
2 champs
Exemple : struct3.c
main() { T_POINT a3,a1,a2={1,-1};

scanf("%lf %lf",&a1.x, &a1.y);


a3 = a2; /* Cope a2 dans a3 : a3.x=1 et a3.y=-1 */
puts("Point a1"); aff(a1); /* affiche un point */
puts("Point a2"); aff(a2); /* affiche un point */

/* Ce code est impossible


if (a1==a2)
puts("a1 et a2 identiques");
else puts("a1 et a2 different"); */

if(a1.x==a3.x && a1.y==a3.y)


puts("a1 et a3 identiques");
else puts("a1 et a3 different");
129
}
Structure (5)
Une structure est un type utilisable pour construire dautres types
On peut faire
des tableaux de structures
des structures de structures

130
Champ de bits
Dcouper les octets en tranche de bits
Gestion des bits sur un octet ou un mot
machine Fichier : champbit.c
utilis en particulier en SE, les tables de #include <stdio.h>
drapeaux (flag), etc...
main() {
chaque groupe de bits a un rle diffrent
struct{unsigned char
alignement et champ cheval sur des mots:
dpend des compilateurs (options)
i:2,j:1,k:4,l:1;} x; /* X est sur
un octet */
Acces aux adresses des champs interdit
Syntaxe :
struct { x.i=2; x.j=1; x.k=10; x.l=0;
type ident:nombre de bits du champ; } /* x=10110100 en binaire ou b4 en hexa
*/
i i j k k k k l
printf("Acces aux champs i=%d j=%d
k=%d l=%d\n",x.i,x.j,x.k,x.l);
struct{unsigned char i:2,j:1,k:4,l:1} x;
x.i {0..3}, x.j {0..1}, printf("acces a l'octet complet : %d
%x \n",x,x);
x.k {0..15}, x.l {0..1}

x=127;
}
131
Union
Unions : accs une mme zone Exemple : union.c : Un short et un
mmoire selon des types diffrents tableau de 2 octet et 2 octet
Exemple : voir un entier 16 bits comme main() { int i;
2x8 bits union REG {
unsigned short ax;
unsigned char t[2];
union ident { struct {unsigned char ah,al; } x; };
type1 identificateur1; union REG r;
type2 identificateur2; };
r.ax= 0x5621;
printf("AX: %x\n",r.ax);
gestion par le programmeur printf("t[0]:%x t[1]:%x\n",r.t[0],r.t[1]);
printf("AH:%x AL:%x\n",r.x.ah,r.x.al);
taille de l'union : taille du plus grand type
r.t[0]= r.t[1]=0;
printf("AX: %x\n",r.ax);
r.t[0] printf("t[0]:%x t[1]:%x\n",r.t[0],r.t[1]);
r.x.al printf("AH: %x AL: %x\n",r.x.ah,r.x.al);
r.x r.x.al=1; r.x.ah=1;
r
printf("AX: %x\n",r.ax);
r.t[1] r.x.al=0x0f; r.x.ah=0xf0;
r.x.al printf("AX: %x\n",r.ax);
}
132
Structure (Exos)
Dfinir une structure reprsentant une matire (Math, physique). Une matire est dfinie par son
nom (mathematique), son coeffficient, son volume horaire et son code (bijection entre une
matire et son code)
Dfinir une structure reprsentant une note, qui contient une valeur et le code correspondant une
matire
Comment dfinir une variable qui est un tableau de notes, une variable qui est le tableau des
matires disponibles.
Faire une fonction qui affiche les noms des matires et la note correspondante partir du tableau de
notes dun lve et du tableau des matires
Faire une fonction qui calcule la moyenne des notes dun lve partir dun tableau de notes et du
tableau des matires

133
Fichiers et Entres / Sortie
Fichiers, Flots
Qu'est ce qu'un fichier : un ensemble d'informations stocks sur un support permanent
(disque dur, cl usb, bande ...)
fichiers sources en C, document word, programmes, DLL, etc...
A quoi servent les fichiers ?
Conserver des rsultats et des donnes
stocker les programmes
Appliquer un traitement toutes les donnes dun fichier
Eviter de taper toutes les donnes utiles un programme
Etc

Les entres/sorties sont les oprations de lecture/criture/contrle entre mmoire


programme et le monde extrieur (priphriques: clavier, ecran, disque, processus,
rseau)

Elles sont manipules via la notion de flot


une entit informatique abstraite qui permet dunifier et de traiter de la mme manire pour le
programmeur tous les priphriques de sortie.
On lit ou on crit avec les mmes fonctions sur lcran, le rseau, un fichier, limprimante, etc...
135
Texte ou binaire
Quand vous affichez un nombre sur l'cran avec printf("%d",i)
i est une variable entire, code sur 4 octets, en base 2.
Il y a cration dune chane de caractres contenant les chiffres du nombre (base 10)
Si i vaut 10, la chane contient les 3 caractres 1 , 0 et fin de chane
Si i vaut 256845, la chane contient les 7 caractres 2 ,5 ,6 ,8 ,4 ,5 et fin de chane.
Ensuite, le systme crit la chane l'cran.
Les nombres affichs prennent un nombre doctets diffrent, chaque chiffre est cod sur un octet
mais ils sont lisibles facilement sur nimporte quelle machine (less, more, editeur de texte, etc..)
Dans un fichier, il se passe la mme chose, ce sont alors des fichiers texte.

Lautre solution est dcrire directement les 4 octets composant le nombre


Tous les entiers sont alors crits avec 4 octets, sans aucune transformation
Ce sont des fichiers binaires,
on les lit difficilement directement. Il faut utiliser la commande od, et interprter soi-mme la sortie

136
Texte (n1.txt) ou binaire
(n1.bin)

En plus, sur INTEL, dans un entier,


les octets de poids faible sont en tete
et ceux de poids fort en queue.

Code ascii du caractre 6, puis de 5, de 5, de 3 et 137


de 6
Manipulation des flots
4 tapes
Dfinition d'une variable de type flot
pour manipuler les fichiers travers le langage utilis
Ouverture du fichier
tablit la liaison entre la variable de type flot cre et le fichier physique
alloue la mmoire ncessaire (buffer)
Oprations de lecture ou d'criture
Lecture : rcupre un nombre dans le fichier et le met dans une variable
Ecriture : crit un nombre dans le fichier
Fermeture du fichier
Vide le buffer et libre la mmoire alloue
Supprime la liaison variable-fichier physique
Remarques
3 flots prdfinis
stdout : associ par dfaut lecran
stderr : associ par dfaut lecran
stdin : associ par dfaut au clavier

138
Dfinition, ouverture,
fermeture de flots
Inclure le fichier dentete
#include <stdio.h>
Dfinition d'une variable f de type FILE* : Descripteur de flot
FILE* f;
Ouverture de fichier
FILE * fopen(char * nomdefichier, char *moded_ouverture)
cration des zones mmoire et initialisation des variables ncessaire
mode ouverture = "r","w","a", "r+","w+","a+" suivi de "t"ou"b"
r : lecture seule
w: ecriture. Ouverture en dbut de fichier ou cration "Efface" l'ancien contenu
a: ajout en fin de fichier ou cration
r+: lecture/ecriture d'un fichier existant
w+: Cration en lecture/ecriture : Efface" l'ancien contenu
a+ : ouverture en lecture/ecriture , positionnement en fin de fichier ou cration
t : fichier texte
b : fichier binaire (Attention aux caractres de contrle comme la fin de fichier si b n'est pas prcis)
Fermeture dun flot
int fclose(FILE* leflotafermer)

139
Dfinition, ouverture,
fermeture
#include <stdio.h>
#include <errno.h> /* pour utiliser la fonction perror */

int main( void ) { FILE* f1; FILE* f2;


f1 = fopen( "n1.txt", "r" ) ;
if ( f1 == NULL ) perror( "Erreur ouverture lecture n1.txt " ) ;
else {
puts("ouverture en lecture de n1.txt reussie");
if ( fclose( f1 ) != 0 ) perror( "Une erreur sest produite la fermeture" ) ;
}
f2 = fopen( "/usr/bin/less", "w" ) ;
if ( f2 == NULL ) perror("Erreur ouverture ecriture /usr/bin/less" ) ;
else {
puts("ouverture en ecriture de /usr/bin/less reussie");
if ( fclose( f2 ) != 0 ) perror( "Une erreur sest produite la fermeture" ) ;
}
}

140
Lecture de fichiers texte
int fscanf(FILE *f, char* control, adresse des arg) ;

Lecture dans un flux de nombres scalaires (entiers, rels) ou de chaines de caractres


Lit les caractres formant un nombre ('0'..'9','.') dans un fichier texte jusqu' trouver
un sparateur (' ',';','\n','\t'...)
convertit la chane de caractre en nombre selon le format prciser dans la chane control:
entier dcimal : %d
rel simple prcision : %f
rel double prcision : %lf
Retourne le nombre d'objets lus Contenu du fichier donnes.txt
Exemple : lectfic1.c 8
main() { FILE* fp; int c,d; double x;
3.1415927
fp = fopen("donnes.txt","rt");
9870
if (fp==NULL) puts("Ouverture impossible");
else { fscanf(fp,"%d %lf %d",&c,&x,&d);
printf("Premier %d, Deuxime %lf, Troisime %d\n",c,x,d);
}
}
on lit 1 entier, puis 1 reel, puis 1 entier dans le fichier
141
Ecriture de fichiers texte
int fprintf(FILE *f, char* control, arg) ;

criture dans un flux de nombres scalaires : entiers, rels, chaine


Convertit le nombre en chane de caractre selon le format prciser dans la chane control :
entier dcimal : %d
rel simple prcision : %f
rel double prcision : %lf
Ecrit les caractres formant un nombre ('0'..'9','.') dans un fichier texte
Retourne le nombre d'objets ecrits

142
Exemple
Lecture des nombres dans un fichier et ecriture des valeurs+1 dans un autre fichier
#include <stdio.h>
main() { FILE* f1; FILE* f2; double x;
/* Ouverture des deux fichiers en lecture ou ecriture */
if ( (f1=fopen("n1.txt","r")) ==NULL) return (1);
if ( (f2=fopen("n2.txt","w")) ==NULL) return (1);
while ( fscanf(f1,"%lf",&x) == 1)
/* tant que la lecture d'un nombre reel x est reussie dans n1.txt */
fprintf(f2,"%lf\n",x+1);
/* Ecriture de x+1 dans le nouveau fichier n2.txt */
fclose(f1); fclose(f2);
}

143
Fichiers binaires (1)
Fichier binaire : copie de la reprsentation mmoire de la variable dans un fichier
Tous les objets de mme type ont la mme taille
1 int = 4 octets, 1 double = 8 octets, ....
Accs direct un lment possible
Tous les objets du fichier ayant la meme taille,
on sait calculer la position du i ime objet par rapport au dbut du fichier
Dpend de la machine et du SE
Big Indian/ Little Indian pour les entiers
Norme IEEE pour les flottants (Cray)
Fichiers de donnes binaires non compatibles
Pas de marque de fin de lignes/ fichiers

Exemple : n1.txt, n1.bin : meme contenu mais en texte ou en binaire


Diffrence fichier texte/fichier binaire : 5 entiers : 1 127 65536 123456789 65537
N1.txt : contenu affich en hexadcimal
0000000 3120 3132 3720 3635 3533 3620 3132 3334
0000020 3536 3738 3920 3635 3533 370a
N1.bin 1er nombre 2 nombre 3nombre 4nombre
0000000 0100 0000 7f00 0000 0000 0100 15cd 5b07
0000020 0100 0100 144
Fichiers binaires (2)
Ouverture d'un fichier binaire
flag b dans le mode d'ouverture

lecture dans un fichier binaire


int fread(void* t, int size, int nbel, FILE *fp);
lecture de nb objets de taille size partir du flux fp
range les objets lus (nb * size octets) l'adresse de lobjet t.
Cette adresse est souvent celle d'un tableau.
Retourne le nombre d'objets lus ou 0 si erreur ou fin de fichier
Le tableau doit tre allou et contenir assez de place

Ecriture dans un fichier binaire


int fwrite(void *t, int size, int nbel, FILE *fp);
ecriture de nb objets de taille size partir du flux fp dans lobjet t.
Retourne le nombre d'objets lus ou 0 si erreur ou fin de fichier

145
Fichiers binaires (3)
Exemple : lecture de n1.bin (5 entiers) et ecriture de x+1 dans n2.bin
main() { FILE* f1, *f2; int i; On lit les 5 entiers en 1 seule opration,
int t[5];
mais il faut que t puisse contenir ces 5 entiers
f1=fopen("n1.bin","rb");
f2=fopen("n2.bin","wb");
if (fread(t,sizeof(*t),5,f1) <5) /* Lecture des 5 entiers */
printf("Impossible de lire 5 entiers");
else { for (i=0;i<5;i++) t[i]=t[i]+1; /* on ecrit aussi t[i]++; */
if (fwrite(t,sizeof(*t),5,f2) <5) /* ecriture des 5 entiers */
printf("Impossible d'ecrire 5 entiers");
} On ecrit les 5 entiers en 1 seule opration
fclose(f1); fclose(f2);
}

146
Fichiers binaires (4)
Positionnement dans un fichier binaire
int fseek(FILE *fp, int offset, int from);
Positionne la prochaine lecture/ecriture offset octets de
from (0:debut, 2:fin ou 1:position actuelle) du fichier
Debut du
Exemple : fichier5.c fichier
main() { FILE* fp; int a; int t[5];
/* Lecture ET ecriture */ 1
fp=fopen("Fichier_a_lire","r+b");
fseek(fp,2*sizeof(*t),0); 127
/* On se positionne sur le
65536
16785
3ime rel dans le file*/
a=16785; 123456789
if (fwrite(&a,sizeof(*t),1,fp) <1)
65537
printf("Impossible d'ecrire");
/* On revient au debut du fichier */
fseek(fp,0,0);
/* Lecture et affichage des nombres */
while (fread(&a,sizeof(a),1,fp) ==1)
printf("%d ",a);
puts("");
} 147
Fichiers Exos
Ecrire un programme qui affiche lecran le contenu du fichier texte f.c
Ecrire un programme qui compte les lignes dun fichier texte dont on lit le nom au
clavier
Ecrire un programme qui compte les entiers stocks dans un fichier binaire ne
contenant que des entiers
Ecrire un programme qui affiche lecran le contenu dun fichier binaire. Ce fichier
contient des lments comprenant un entier, un rel double prcision et une chane
de 32 caractres.
Ecrire un programme qui affiche lecran le contenu du ime lement du fichier
binaire prcdent.
Ecrire un programme qui remplace le contenu du ime lement du fichier binaire
prcdent par llment contenant 0,0.0,
Ecrire un programme qui transforme tous les octets dun fichier texte donnees.txt
en leur ajoutant une valeur constante a.
-

148
Allocation dynamique
Allocation dynamique ?
Exemple : le format dimage PPM contient le magic number P5 sur la premire ligne, puis
le nombre de lignes et de colonnes de limage, puis toutes les donnes de limage

Si mon programme recopie une image PPM, il doit


ouvrir le fichier
lire les tailles,
lire les donnes pour les ranger dans une matrice

Probleme : on ne sait pas quelle est la taille de la matrice utile.

Comment crer une matrice dont la taille est lue et connue quand on execute le
programme et inconnue quand on crit le code C ?

150
Allocation dynamique ?
Que faire quand on ne connat pas la dimension dun tableau que lon doit utiliser
lorsque lon crit le programme
Solution 1 : crer le plus grand tableau possible, et utiliser la partie dont on a besoin quand on
excute le programme
Le tableau est cr la compilation, il a toujours la meme taille
Solution 2 ; crer le tableau lorsque lon connat sa taille, cest dire pendant lexcution du
programme : cest lallocation dynamique
Le tableau a juste la bonne taille, cette taille est diffrente selon les excutions

Allocation dynamique : les 3 lments utiles


Crer un pointeur du type du tableau : double* p;
La fonction void* calloc(int n, int d) permet de crer un tableau de n lments, chaque lment
ayant la dimension d . Cette fonction retourne ladresse du tableau cr si lallocation est
possible, NULL sinon. Le tableau est initialis avec des octets nuls.
La fonction free(void* p) permet de librer la mmoire alloue pour le tableau p , allou par
calloc (ou malloc)

151
Exemple
Exemple : alloc0.c
main() { int i=0, dim=0; Cration dun tableau de dim rels
double* t1=NULL; double* p=NULL;
Attention : cest le type de t1 (double*)
printf("Donner la dimension voulue ");
qui dtermine la nature des lments,
scanf("%d",&dim);
et non la fonction calloc
t1=calloc(dim, sizeof(*t1));
On peut maintenant utiliser
for (i=0; i<dim; i++) t1[i]=2*i+1; indiffremment les notations
for (i=0; i<dim; i++) printf("%lf ",*(t1+i)); t[i] et *(t+i) et meme *p
for (p=t1; p<t1+dim; p++) printf("%lf ",*p);
Le tableau est devenu inutile :
free(t1);
on libre la mmoire alloue

/* ATTENTION : on ne peut plus utiliser t1 ici */


}

152
Exemple
Exemple : alloc0.c Adresse 0
main() { int i=0, dim=0;
double* t=NULL;
printf("Donner la dimension voulue ");
scanf("%d",&dim);
printf("t:%p et adresse t1%p\n",t,&t);
t=calloc(dim, sizeof(*t)); 0x100160 0
1 &t[0]
printf("t:%p et adresse t1%p\n",t,&t);
0x100168 0
3 &t[1]
for (i=0; i<dim; i++) t[i]=2*i+1;
for (i=0; i<dim; i++) printf("%lf ",t[i]);
free(t);
}

0xbffff3d4 0x100160
0 &t
0xbffff3d8 0
2 &dim
0xbffff3dc 0 &i

153
Mmoire et allocation
Intrt de lallocation dynamique
Dimension inconnue lors de la conception du
Text : code du
programme programme
Donnes de grande taille
Donnes de taille variables : tableaux, listes, Data: variables
globales
initialises

Allocation dans une zone mmoire gre par


BSS : variables
lutilisateur : le tas : heap globales non
initialises
Les variables locales sont gres par le compilateur
sur la pile : stack HEAP ou tas :
Le code est stock dans une zone mmoire appele allocation
dynamique
text
Les variables globales non initialises sont gres
dans la zone BSS
STACK ou PILE :
Les variables globales initialises sont gres dans la variables locales,
zone data sauvegarde des
contextes
154
Mmoire et allocation
(exos)
Faire une fonction qui prend en paramtres un tableau de double et sa dimension, et
qui clone (cre un nouveau tableau et recopie) ce tableau. La fonction retourne le
clone.
Faire le programme principal qui utilise cette fonction. Si le clone est modifi, le
tableau initial est il modifi ?
Quelle diffrence entre un tableau dynamique et un tableau automatique
Pourquoi le prgramme suivant est il faux ?
int * mauvais1 () { int i,tab[10];
for (i=0;i<10;i++) tab[i]=0;
return tab;
}
main() { int * p; int i;
p=mauvais1();
for (i=0;i<10;i++) printf("%d", p[i]);
}
Reprendre la fonction 1 ci dessus en utilisant le passage par variable pour le clone.
Que devient le programme principal ?

155
Matrices
Tableau multi dimensions Adresse
0

Il suffit de spcifier toutes les dimensions


type identificateur[dim1][dim2].;
Exemple : int t[2][3]; Tableau de 2 lignes et 3 colonnes
Les lments sont stocks contiguement, ligne par ligne
Exemple : tab2d1.c
main() { int i,j; int t[2][3];
0xbffff3c0 0 &t[0][0]
for (i=0; i<2; i++) for (j=0; j<3; j++)
0xbffff3c4 1 &t[0][1]
t[i][j]=i+j;
printf("Valeur du tableau "); 0xbffff3c8 2 &t[0][2]
for (i=0; i<2; i++) for (j=0; j<3; j++) 0xbffff3cc 1 &t[1][0]
printf("%d ",t[i][j]); 0xbffff3d0 0
2 &t[1][1]
printf("\nAdresses des elements du tableau "); 0xbffff3d4 3 &t[1][2]
for (i=0; i<2; i++) for (j=0; j<3; j++)
printf("%p ",&t[i][j]);
}

157
Tableau multi dimensions
Adresse
0
Comment le compilateur traduit t[i][j] dun tableau int t[2][3];
on dmarre au dbut du tableau (ladresse du premier lment) : cest
t
on saute i lignes (chaque ligne contient 3 lments), on a alors
ladresse de la ligne i : cest t+3*i 0xbffff3c0 0 &t[0][0]
on saute les j premiers lments de cette ligne : on a ladresse de
llment dindice i et j : cest t+3*i +j 0xbffff3c4 1 &t[0][1]
On utilise loprateur dindirection * 0xbffff3c8 2 &t[0][2]
Soit *( (int* )t+3*i+j) et cest t[i][j]
0xbffff3cc 1 &t[1][0]
Conclusion : on a besoin de connatre le nombre de colonnes
pour trouver un lment du tableau 0xbffff3d0 0
2 &t[1][1]
0xbffff3d4 3 &t[1][2]
Quaffiche le programme suivant
main() { int i,j; int t[2][3];
for (i=0; i<2; i++) for (j=0; j<3; j++) t[i][j]=i+j;
printf("\nAdresse du tableau %p \n",t);
printf("\nAdresse des lignes du tableau \n");
for (i=0; i<2; i++) printf("%p %p",&t[i], t+i);
printf("\nAdresse des elements du tableau \n");
for (i=0; i<2; i++) for(j=0;j<3;j++) printf("%p ",&t[i][j]);
158
}
Fonction et tableau nD
Les paramtres de fonctions qui sont des tableaux de N dimensions doivent prciser
N-1 dimensions dans le prototype et lentte de fonction
Exemple Prciser le nombre de lignes nest pas utile
#include <stdio.h> Prciser le nombre de colonnes est INDISPENSABLE
#define N_COL 5 Et cest une constante

void init_tab(int tab[][N_COL],int nl)


{ int i,j;
for (i=0; i<nl; i++) for (j=0; j<N_COL; j++) tab[i][j]=i+j;
}

int main() { int ligne,colonne;


int mon_tab[3][N_COL]; int tab2[3][N_COL+1]; OK pour mon_tab, qui a NB_COL colonnes

init_tab(mon_tab,3);
init_tab(tab2,3); INTERDIT pour tab2
for (ligne=0; ligne<3; ligne++) { qui a NB_COL+1 colonnes
for (colonne=0; colonne<N_COL; colonne++)
printf("%d ",mon_tab[ligne][colonne]);
printf("\n");
}
}

159
Tableau nD
Ces tableaux sont peu utiliss, car , pour des matrices 2D par exemple

Ils ont un nombre de colonnes fixes


les fonctions ayant des matrices en paramtres dpendent du nombre de
colonnes : il faut faire autant de fonctions que de taille de tableaux !!!

On utilise de prfrence des tableaux 1D ou les pointeurs et l'allocation dynamique

160
Matrice 2D dynamique
T[0][0]
T:adresse
de tableau T[0]:adress T[0][1]
e ligne 0
...
T[1]:adress
e ligne1 T[0][m-1]


... T[1][0]
T[i]:adresse T[1][1]
ligne i
..
Construction dynamique dune matrice d'entiers de n .
lignes et m colonnes ..

Il faut dclarer une matrice sous la forme : int** t; T[0]:adress T[i][0]


e ligne n-1
Il faut crer dynamiquement un tableau de n pointeurs qui ..
contiendront chacun ladresse dune ligne
T[i][j]
Il faut crer dynamiquement les n lignes qui contiendront
chacune m lments ..

T[n-1][m-1]

161
Matrice 2D dynamique
T[0][0]
T:adresse
Comment se retrouve un lment t[i][j] de tableau T[0]:adress T[0][1]
e ligne 0
t[i] ou bien *(t+i) contient ladresse de la ligne i ...
T[1]:adress
t[i]+j ou bien (*(t+i)+j) contient donc ladresse T[0][m-1]
e ligne1
de llment dindice i,j
*(t[i]+j) ou bien *(*(t+i)+j) est donc llment
...
t[i][j] T[1][0]

Conclusion : aucune dimension nest T[i]:adresse T[1][1]


ligne i
ncessaire pour trouver la valeur de ..
llment, les prototypes de fonctions ne .
..
doivent pas spcifier les dimensions dans
ce cas T[0]:adress T[i][0]
e ligne n-1
..

T[i][j]
..

T[n-1][m-1]

162
Matrice 2D
Exemple : alloc4.c
void aff(int **m, int nl, int nc) {
#include <stdio.h>
int i,j;
int ** alloue(int n, int m) { int i,j;
for (i=0; i<nl; i++){
int **p ;
for (j=0;j<nc;j++)
printf("%d " ,m[i][j]);
p=calloc(n,sizeof(*p));
puts("");
if (p==NULL) return NULL;
}
else
}
for (i=0 ; i<n ; i++) {
main() { int a,b,i,j ;
p[i]=calloc(m,sizeof (**p));
int** mat ;
if (p[i]== NULL) return NULL;
puts ("dimension ? ");
}
scanf("%d %d",&a,&b );
return p;
mat= alloue(a,b);
}
for (i=0; i<a; i++)
for (j=0;j<b;j++)
void destructeur(int **p, int n, int m){ mat[i][j]=i+j;
int i; aff(mat,a,b);
for (i=0; i<n; i++) free(p[i]); destructeur(mat,a,b);
free(p); }
}

163
Matrice 2D : plus fort
Toutes les lignes sont alloues en une fois et sont donc
contigues T:adresse de T[0]:adresse
T[0][0]
Il faut calculer les adresses des lignes tableau ligne 0

Exemple : alloc5.c T[1]:adresse


T[0][1]
ligne1
...
int ** alloue(int n, int m) { int i,j;
int **p ; ... T[0][m-1]
p=(int **)calloc(n,sizeof(*p)); T[1][0]
if (p==NULL) return NULL; T[i]:adresse
ligne i T[1][1]
else {
*p = (int *)calloc(n*m,sizeof(**p));
...
..
if (*p ==NULL) [ free(p); return NULL; }
else T[i][0]
for (i=1 ; i<n ; i++)p[i]=p[i-1]+m; T[0]:adresse ..
} ligne n-1
return p; T[i][j]
}
void copie1(int** m1, int** m2, int n, int m) { int i,j; ..
for (i=0;i<n;i++) for(j=0;j<m;j++) m1[i][j]=m2[i][j]; T[n-1][0]
}
void copie2(int** m1, int** m2, int n, int m) { ..
memcpy(*m1,*m2,n*m*sizeof(**m1));
} T[n-1][m-1]

164
Des lignes de taille
diffrentes
Comment rcuprer les arguments de la ligne de commande UNIX
Le premier paramtre de main (argc) est le nombre de mot, le suivant (argv) est le tableau de ces
mots
Attention :ce sont des chanes de caractres : conversion faire si vous avez des nombres
Main na que 2 versions : sans paramtres ou avec 2 paramtres
Sur le mme principe, on peut faire des matrices avec des lignes de longueur variable

main (int argc , char** argv) {


int i;
if (argc == 1)
printf("Pas d'arguments\n");
else {
printf("%d arguments\n" , argc);
for (i=1; i<argc; i++)
printf("%s\n",argv[i]);
}
} /* argv[0]: nom du programme */

165
Exercices
Comment dclarer un tableau comportant 3 dimensions (128, 256, 256)
Faire une fonction allouant dynamiquement ce tableau
Faire un programme principal utilisant cette fonction
On suppose avoir un fichier texte contenant les titres des livres de la bibliothque de lcole,
raison dun titre par ligne. Il y a 250000 livres, la longueur maximale dun titre est 256octets, la
longueur moyenne 32 octets.
Comment dclarer un tableau t1 (non allou dynamiquement) pouvant contenir ces titres ?
Comment dclarer un tableau t2 (qui sera allou dynamiquement) pouvant contenir ces titres
?
Comparer les tailles qui seront utilises par ces deux versions de tableau.
Faire une fonction ralisant la lecture des titres dans le tableau t2 Cette fonction retournera le
tableau t1.
La fonction fgets(tableau, 256, f1) permet de lire une ligne du fichier f1, et de la stocker
dans le tableau deja cr.
La fonction strcpy(s1,s2) permet la copie de s2 dans s1.
On suppose avoir une fonction int nblivres(char* fichier) qui donne le nombre de livres
contenus dans le fichier.

166

Vous aimerez peut-être aussi