Vous êtes sur la page 1sur 52

Algorithmique et

Programmation

PARTIE 2
1- RAPPEL ET COMPLEMENTS
2- LES FONCTIONS
3- LES STRUCTURES
4- LES ALGORITHMES DE TRI
4- LES POINTEURS
5- LES FICHIERS

2
RAPPEL ET
COMPLEMENTS

3
Rappel

Un programme C est une fonction de nom


main() qui prend des arguments textuels en
paramètre et renvoie un code de retour
d’erreur entier
Quelques conventions
◮ Une déclaration de variable par ligne
◮ Une instruction élémentaire (pas bloc)
par ligne
◮ Structure de contrôle : début de ligne
◮ Accolade ouvrante : fin de ligne
◮ Accolade fermante : seule sur une ligne
◮ Étiquette : seule sur une ligne
Types d’objet
◮ Types scalaires : objets élémentaires proches
du matériel
Types arithmétiques : pour faire des calculs au
sens classique
Pointeurs : référence à d’autres objets ou fonctions
◮ Types structurés
Vecteurs : répétition ordonnée d’un même type
Structures : rassemble éléments hétérogènes
Union : fait coexister plusieurs types au même
endroit mémoire
• Types de fonction : précise à la fois type valeur
de retour et type des arguments
• Types incomplets
◮ Incomplétude totale void
◮ Vecteur de taille non précisée
RAPPEL ET
COMPLEMENTS

Visibilité des variables -


Les classes d’allocation
des variables

6
Déclaration et définition

Une déclaration : une association de type


avec un nom de variable ou de fonction (dans
ce cas la déclaration contient aussi le type
des arguments de la fonction, les noms des
arguments peuvent être omis),
Une définition c’est une déclaration et si
c’est une variable, une demande d’allocation
d’espace pour cette variable, si c’est une
fonction la définition du corps de fonction
contenant les instructions associées à cette
fonction.
De manière simpliste, une déclaration fait
référence à une définition dans une autre
partie du programme.
Visibilité d’une variable
La visibilité d’une variable concerne l’endroit
du source où la variable est accessible
( lisible ou modifiable)

a)Variable locale :
Une variable locale est une variable qui a été
déclarée dans un bloc d’instructions. Une
variable locale n’est accessible que depuis
le bloc où elle a été déclarée et tous ses
sous blocs éventuels.

b)Variable globale :
Une variable globale est déclarée en dehors
de tout bloc d’instructions. Elle sera visible
depuis sa déclaration jusqu’à la fin du
fichier source.
8
Règle fondamentale de
visibité
Toute variable ou fonction
doit être déclarée avant
d’être utilisée.

9
Exemple
int a; /*variable globale*/
void f1(){
long a ; /*variable locale à f1*/
a = 50; /*modification locale à f1*/
}
void f2(void){
a= 10; /*modification globale*/
}
void f3(float a ){/*paramètre de f3*/
a = 10; /*modification paramètre local à f3*/
}
les règles de visibilité de noms nous permettent de
dire :
1. la fonction f3 peut appeler les fonctions f3, f2, et
f1 ;
2. la fonction f2 peut appeler la fonction f2, et f1 ;
3. la fonction f1 ne peut que s’appeler elle-même ;
Les classes d’allocation
mémoire
La classe d’allocation d’une variable concerne la
façon dont sera stockée la variable dans la
mémoire. Ce qui influe sur sa durée de vie.
La classe mémoire sert à expliciter la visibilité
d’une variable et son implantation en machine.
Les classes mémoire sont :
automatique : dans la pile
static : local au fichier ou garde une vie
après la mort
extern : définie ailleurs
register : essaye de garder en registre
(très rapide mais rare, donc chère...)

11
La classe d’allocation
Automatique
Cette classe comprend l’ensemble des
variables définies dans un bloc. C’est le
cas de toute variable définie à l’intérieur
d’une fonction.

L’espace mémoire réservé pour ce type de


variable est alloué dans la pile d’exécution.
C’est pourquoi elles sont appelées aussi
auto c.a.d automatique car l’espace
mémoire associé est créé lors de l’entrée
dans la fonction et il est détruit lors de la
sortie de la fonction.

La durée de vie des variables de type


local est celle de la fonction (ou du bloc)
dans laquelle elles sont définies.

12
La classe d’allocation
statique
static ce qualificatif modifie la visibilité de la
variable, ou son implantation :
VARIABLE LOCALE :
 implantée dans une partie de l’espace de
mémoire globale.
 nom local mais une durée de vie égale à
celle du programme en cours d’exécution.
VARIABLE GLOBALE
 visibilité restreinte à l’unité de
compilation.
 Une variable globale de type statique ne peut
pas être utilisée par un autre fichier source
Exemple sur l’utilisation de
static
int a; /*variable globale*/
void f1(void){
static long a = 1;/*variable statique locale à
f1*/
a + = 10;/*modification locale à f1*/
}
void f2(void){
for(a = 1;a<10;a++) /*modification
globale*/
f1();
} A chaque appel, la fonction f1 retrouve la valeur de a
(locale) qu’elle a modifiée lors des appels précédents.
main()
{ L’initialisation d’une variable statique interne à une
fonction est faite à la compilation, et non à l’entrée
f2(); dans la fonction.
}
a (global) = 1 2 3 4 5 6 7 8 9 a ( locale) = 1 11 21 31 41 51 61 71 81 91.
Les classes extern et
registre
extern non pas une définition mais une
déclaration .
variable globale (ou fonction)
utilisée dans ce fichier source(noms
et types) mais définie dans un autre
fichier source.

register pour des variables locales


utilisées souvent.
Le prédicat demande de les
mettre si possible dans des registres
disponibles du processeur de manière
à accélérer le temps d’exécution.
Exemple
Fichier 1: main.c
#include <stdio.h>
int count ;
extern void write_extern();
main() {
count = 5;
write_extern();
}
Fchier 2: support.c
#include <stdio.h>
extern int count;
void write_extern(void) {
printf("count is %d\n", count);
}
Qualificatifs d’aide au
compilateur const et
volatile
 le qualificatif const : la variable est
considérée comme constante (ne doit pas figurer
dans la partie gauche d’une affectation).
La variable est placée dans une zone mémoire
accessible en lecture seulement à l’exécution.
Ceci n'est utile que pour les paramètres d'une
fonction, lorsqu'on désire protéger les paramètres
effectifs de la fonction en les mettant en << lecture
seulement >>.
 Le qualificatif volatile : la variable est
placée dans une zone mémoire qui peut être
modifiée par un moyen extérieur au programme.
Les deux qualificatifs peuvent être utilisés sur la
même variable, spécifiant que la variable n’est
pas modifiée par la partie correspondante du
programme mais par l’extérieur.
RAPPEL ET
COMPLEMENTS

L ES INSTRUCTIONS DE
BRANCHEMENT

18
Branchement multiple
switch
switch (expression ){
case constante-1: liste d’instructions 1 ;
break;
case constante-2: liste d'instructions 2 ;
break;
...
case constante-n: liste d'instructions n;
break;
default: liste d'instructions ;
break;
}
Si la valeur de expression est égale à l'une des constantes,
la liste d'instructions correspondant est exécutée. Sinon la
liste d'instructions correspondant à default est exécutée.
L'instruction default est facultative

19
Branchement non
conditionnel break
L'instruction break peut être employée à
l'intérieur de n'importe quelle boucle. Elle
permet d'interrompre le déroulement de la
boucle, et passe à la première instruction qui suit
la boucle. En cas de boucles imbriquées, break
fait sortir de la boucle la plus interne:

main()
{ int i;
for (i = 0; i < 5; i++) {
printf("i = %d\n",i);
if (i == 3) break;
}
printf(" i a la sortie de la boucle= %d\n",i);
}//i = 3

20
Branchement non
conditionnel continue
L'instruction continue permet de passer
directement au tour de boucle suivant, sans
exécuter le reste des instructions du corps
de la boucle.
main()
{int i;
for (i = 0; i < 5; i++) {
if (i == 3) continue;
printf(" i = %d",i);
}
printf(" \nvaleur de i a la sortie de la boucle
= %d",i);
}
//i = 0 i = 1 i = 2 i = 4
//valeur de i a la sortie de la boucle = 5
21
LES FONCTIONS

22
LES FONCTIONS
Comme tout langage de programmation, le langage
C permet le découpage d’un programme en des
sous programmes. Ces sous programmes
s’appellent des procédures ou fonctions.

Utilité des fonctions :

Éviter la répétition d’une même suite


d’instructions

Réutiliser une même suite d’instructions dans un


autre programme

Rendre une portion d’un programme


indépendante du programme surtout avec
l’utilisation des paramètres

Avoir un programme concis et clair


LES FONCTIONS
Une fonction existe obligatoirement
dans un programme C : fonction
principale main ()

Cette fonction peut appeler d’autres


fonctions qui elles mêmes peuvent
appeler d’autres fonctions. Une règle
générale doit être respectée : toute
fonction doit être déclarée avant d’être
appelée.
Toute fonction doit être définie dans un
programme.

Une fonction peut s’appeler elle-même,


on dit que c’est une fonction récursive
Définition d’une fonction
Une fonction est définie de la manière suivante :
Type nom_fon (type par1, . . . , type parn) {
Déclaration des variables;
Liste d’instructions;
}
La liste d’instructions s’appelle corps de la
fonction.
Les paramètres par1, . . . parn sont des variables
associée chacune à un type.
Une fonction peut retourner un résultat, dans ce
cas Type est le type du résultat.
Si elle ne retourne rien, le type est le type
générique : void
Une fonction peut être déclarée par la seule
donnée de son prototype :
type nom_fon (type par1, . . . , type parn);
Si une fonction est définie au début, il est inutile
de la redéclarer.
Appel d’une fonction
L’appel d’une fonction dans un programme se fait de la
manière suivante :

nom_fon (par1, . . . , parn);

Les paramètres par1, . . . parn sont des paramètres


effectifs ( ou encore arguments), elles sont déclarées avant
l’appel de la fonction.
L’ordre et le type des paramètres effectifs de la fonction
doivent concorder avec ceux données dans l’entête de la
fonction telle qu’elle est définie.

Les paramètres effectifs peuvent être des expressions.


Exemples de fonctions
int produit (int a, int b) {

return a*b;
}
void lecture (int tab[], int n) {

int i;
for (i = 0; i < n ; i++) {
printf(" donner l’entier N° %d ", i+1);
scanf(" %d ", &tab[i]);
}
}
int puissance ( int a, int n) {

if (n == 0)
return 1;
else return ( a* puissance(a, n-1) );
}
Transmission des
paramètres d’une fonction
Les paramètres d’une fonction sont traités de la même
manière que les variables locales de classe automatique :

Lors de l’appel de la fonction, les paramètres effectifs ( ou


arguments ) sont copiés dans le segment de pile relatifs
aux paramètres figurant dans l’entête de la fonction.
La fonction travaille alors uniquement sur cette copie
laquelle disparaît lors du retour au programme appelant.
Cela implique en particulier que si la fonction modifie la
valeur d’un de ses paramètres, la variable (argument)
correspondante ne sera pas modifiée. On dit que la
transmission se fait par valeur.

Pour qu’une fonction modifie la valeur d’un de ses


arguments, il faut qu’elle ait pour paramètre l’adresse de
cet objet et non sa valeur. Dans ce cas, la transmission est
dite par adresse.
Retour sur les chaines de
caractères

29
Fonctions de chaines de
caractères
Voici quelques fonctions de la bibliothèque standard
string.h destinée à la manipulation des chaines de
caractères.
strcpy( s, sr);
Copie la chaine sr dans la chaine s ( y compris le caractère
de fin de chaine), retourn s.
Strncpy(s, sr, n);
Identique à strcpy en se limitant à n caractères.
strcat (s, sr);
Concatène la chaine sr à la suite de s et retourne s.
strncat (s, sr, n);
Identique à strcat en se limitant à n caractères.
int strcmp( cs, ct);
Compare les deux chaines cs et ct et renvoie :
une valeur négative si lexicalement cs < ct
Une valeur nulle si cs == ct
Une valeur positive si cs > ct
Fonctions de chaines de
caractères
Suite des fonctions de la bibliothèque standard string.h
destinée à la manipulation des chaines de caractères :
int strncmp( cs, ct, n);
Identique à strcmp en se limitant à n caractères.
int strlen( s);
Retourne le nombre de caractères de la chaine s sans tenir
compte du caractère de fin de chaine.
strchr(s, c);
Retourne l’adresse de la première occurrence du caractère
c dans la chaine s en partant du début de la chaine.
strrchr(s, c);
Retourne l’adresse de la première occurrence du caractère
c dans la chaine s en partant de la fin de la chaine.
strstr(s, ct);
Identique à strchr sauf qu’il s’agit de la première
occurrence de la sous chaine ct.
Tableaux de chaines de
Un
caractères
tableau de chaines de caractères correspond à un
tableau à deux dimensions de type char, où chaque ligne
contient une chaine de caractères
La déclaration : char MOTS[7][10];
réserve l’espace mémoire pour 7 mots de 10 caractères
chacun.
Lors de la déclaration, il est possible d’initialiser le tableau :
char MOTS[7][10] = {"alpha", “beta", “gamma", “theta",
"delta", "lambda", "sigma"}
L’expression MOTS[I][J] est la J-ième lettre de la ligne
MOTS[I]
Les tableaux de chaines de caractères sont mémorisés ligne
par ligne, l’espace mémoire nécessaire est ?
On peut utiliser les fonctions de manipulation des chaines de
caractères : strcpy(MOTS[3], “omega")
Pour lire et afficher les mots du tableau on écrit :
for (int I=0; I< 7; I++) scanf("%s\n", MOTS[I]);
for (int I=0;I<7;I++) printf("%s\n", MOTS[I]);

32
LES STRUCTURES

33
LES STRUCTURES
Le type structure ( ou struct en C ) définit des objets
composés de plusieurs éléments qui peuvent être de
différents types.
Un élément d’un type struct est appelé membre ou champ.
Un champ peut être de type tableau ou même d’un type
struct.
Un type structure peut être déclaré de la manière suivante :
struct nom // déclaration de structure
{ type1 champ_1;
...
typn champ_n;
};
Pour déclarer une variable d’un type struct nom, on écrit :
struct nom A;
On accède aux différents membres d'une structure grâce à
l'opérateur membre de structure, noté ``.''.
Le i-ème membre de A est désigné par l'expression :
A.champ_i
Les objets de type structure en C sont des Lvalues. Ils
possèdent une adresse, c’est l'adresse du premier élément du
premier champ de la structure.
La variable A peut donc être membre gauche d’une
affectation
Opérations sur les
structures
• Les opérations permises sur une structure
sont l’affectation (en considérant la
structure comme un tout), la récupération
de son adresse (opérateur &) et l’accès à
ses membres.
• On peut initialiser une structure au moment
de sa déclaration, par exemple :
article art1 ={15,50,12.5}
• Quelques opérations :
art1.numero = 15;
printf ("%e", art1 .prix);
art2 = art1;

35
Exemples
struct complexe {
double reel;
double image;
};
struct etudiant {
char CIN[10];
char nom [10];
char prenom [10];
char adresse [30];
char tel[12];
};
struct article {
int numero;
int qte;
double prix;
};
struct article art1; art2;
Un petit programme
#include <stdio.h>
struct article{
int numero, qte;
double prix;
};
typedef struct article Article;

int main() {
Article art1 = { 1,100,5}, art2;
art2 = art1;
printf("\narticle 1 = %d %d %f", art1.numero, art1.qte
,art1.prix);
printf("\narticle 2 = %d %d %f", art2.numero, art2.qte
,art2.prix);
printf("\ndonner la quantité et le prix de l'article
2\n");
scanf("%d%lf",&art2.qte, &art2.prix);
printf("\n %d %d %f", art2.numero, art2.qte ,art2.prix);
return 0;
}
Fonction qui renvoie un
objet de type structure.
Soit :
struct complexe {
double reel,image;
}
struct complexe conjugue(struct complexe
x);
{ struct complexe y;
y.reel = x.reel;
y.image = -x.image;
return y;
}
Appel de la fonction :
struct complexe x , z;
z = conjugue(x);
Unions

Les unions permettent l’utilisation d’un


même espace mémoire par des données de
types différents à des moments différents.

Définition
union nom_de_union {
type1 champ1 ;
type2 champ2 ;
..
...
typeN champN ;
};
Exemple

union zone {
int entier;
long entlong;
float flottant;
double flotlong;
} z;
z peut contenir soit un entier, soit un
entier long, soit un nombre avec point
décimal, soit un nombre avec point
décimal long.
le compilateur réserve l’espace mémoire
de la taille du plus grand des champs
appartenant à l’union. ( soit ici double )
Tableau de Structures
#include <stdio.h>
#include <stdlib.h>
typedef struct
{ int numero, qte;
double prix;
}article;
int main()
{ int n, i; article tab[10];
do{
printf("nombre d‘articles = ");
scanf("%d",&n);
}while (n < 0 || n> 10);
/* saisie des articles dans un tableau*/
for (i =0 ; i < n; i++) {

41
Tableau de Structures

printf("\n saisie de l’article %d\n",i);


tab[i].numero = i;
Printf("quantité = "); scanf("%d",&tab[i].qte);
printf("\n prix = ");
scanf("%lf",&tab[i].prix);
}
/*affichage des articles*/
for (i =0 ; i < n; i++) {
printf("\n article numéro %d:",i);
printf("\n prix unitaire = %.2f",tab[i].prix);
printf("\n quantité = %d\n",tab[i].qte);
}
return 0;
}
42
Les pointeurs
Pointeur

Pour obtenir l'adresse d'une variable on


fait précéder son nom par l'opérateur '&'
(adresse de) :
int x = 10;
printf("%p",&x); afficherait 62.
Pointeur - définition

Variable spéciale destinée à contenir une


adresse mémoire d’un objet. c'est à dire une
valeur identifiant un emplacement en mémoire.

On la déclare ainsi :
type *identifiant;

Cette déclaration définit identifiant


comme variable de type pointeur vers
type

type est le type de l’objet pointé


45
Illustration

int *px;
Réserve un emplacement pour
stocker une adresse mémoire.

La déclaration d’un pointeur


alloue de l’espace mémoire au
pointeur mais pas pour l’objet
pointé.
Attribuer une valeur à une
variable de type pointeur

px = NULL; //conseillé avant toute utilisation


du pointeur

px = &x;
Ecrit l'adresse de x dans cet
emplacement.
Seconde démarche

Utiliser des fonctions d’allocation


dynamique. Par exemple :

px = malloc(sizeof(int));
permet d’allouer un espace mémoire de la
taille d’un entier et affecte son adresse à
px.

Autre façon, si on déclare deux pointeurs :


int *ad1, *ad2; . . .
ad1 = ad2;
ad2 pointe alors sur le même objet que ad1
48
Qu’est ce qui se passe en
mémoire?

int *p;
p

???

200

L’instruction suivante permet de


réserver la mémoire pour l’objet qui
sera pointé par p:

p = (int*)
p
malloc(sizeof(int))

33

200 33

49
L’opérateur * pour
manipuler un objet pointé
Si ad est un pointeur, *ad désigne
l’objet pointé par ad.
int *ad, *p, n=20;
…….
ad = &n;
printf(" %d" , *ad); /*affiche la valeur
20*/

p = (int*)malloc(sizeof(int));
*p = 30; /*place la valeur 30 dans
l’emplacement préalablement alloué*/
50
Illustration

*p
Valeur de ad
Adresses mémoire

Valeur de p

33 55

55 33 30 20

ad p n

*ad valeur de n

On peut schématiser ce qui se passe en


mémoire
Objet pointé par ad

p ad 20
30
n
51
Objet pointé par p
Exemple

Si un pointeur P pointe sur une variable X,


alors *P peut être utilisé partout où on peut
écrire X.
Les expressions suivantes, sont équivalentes:
Y = *P+1 Y = X+1
*P = *P+10 X = X+10
*P += 2 X += 2
++*P ++X
(*P)++ X++
Dans le dernier cas, les parenthèses sont nécessaires:
Comme les opérateurs unaires * et ++ sont évalués de
droite à gauche, sans les parenthèses le pointeur P serait
incrémenté, non pas l'objet sur lequel P pointe.

52