PROG S1 Algo + C
PROG S1 Algo + C
PROG S1 Algo + C
Département Licence
Parcours
Licence 1 – Analyse et programmation
Enseignants
Equipe pédagogique
TITRE DE L’UE : ALGORITHME ET STRUCTURE DES DONNÉES
UE1 Elément constitutif (EC) : Algorithme et structure des données sous langage C
TPE estimé : 90 H
Cours : TD : TP :
20H 40H
Objectif général :
Cet enseignement vise à mettre à la disposition de l’étudiant les outils d’analyse algorithmique, de structure
des données et de structuration de la programmation en C.
Objectifs spécifiques :
A l’issue de cet enseignement, l’étudiant doit être capable :
• d’analyser un problème donné ;
• de définir l’algorithme traduisant la solution du problème d’une manière rigoureuse ;
• de l’interpréter structurellement ;
• de l’interpréter schématiquement (ordinogramme) ;
• de maîtriser la structure d’un programme en langage C ;
• de traduire un algorithme en langage C.
Méthodes pédagogiques : Cours magistral, petite révision en classe, exercices à faire à domicile, exposés à préparer,
recherche documentaire, lecture d’ouvrages et d’articles.
Evaluation :
Contenu pédagogique :
Bibliographie :
Sommaire
Chapitre1 : Introduction à l’algorithmique ............................................................................................. 5
Section 1 : Environnement algorithmique .......................................................................................... 5
Section 2 : Types de données ............................................................................................................ 10
Section 3 : Structure conditionnelle.................................................................................................. 12
Section 4 : Structure interactive ou boucle ou instruction répétitive ou instruction itérative......... 17
Section 5 : Algorithmiques de tri....................................................................................................... 22
Section 6 : Algorithmique de recherche (Dichotomie)...................................................................... 22
Section 7 : Procédures et fonctions.................................................................................................. 24
Section 8 : Mode de passage des paramètres................................................................................... 25
Section 9 : Récursivité ....................................................................................................................... 26
Chapitre 2 : Notion de pointeur ............................................................................................................ 30
Section 1 : Mémoire et importance dynamique ............................................................................... 30
Section 2 : Listes chainées ................................................................................................................. 30
Section 3 : Opérations sur les listes chainées................................................................................... 31
Section 4 : Listes circulaires............................................................................................................... 32
Section 5 : Listes bidirectionnelles .................................................................................................... 34
Chapitre 3 : Structure d’arbre : arbre binaire de recherche ................................................................. 36
Section 1 : Opération sur les arbres (Parcours en profondeur) ........................................................ 36
Section 2 : Piles et files ...................................................................................................................... 38
Section 3 : Recherche ........................................................................................................................ 45
Chapitre 4 : Fichiers............................................................................................................................... 47
Section 1 : Notion des fichiers........................................................................................................... 47
Section 2 : Différents types de fichiers............................................................................................. 47
Section 3 : Organisation et accès aux fichiers ................................................................................... 48
Section 4 : Opérations sur les fichiers ............................................................................................... 48
Chapitre 5 : Notion de complexité ........................................................................................................ 50
Section 1 : Notion de complexité ...................................................................................................... 50
Section 2 : Calcul de la complexité ................................................................................................... 51
Chapitre 6 : Présentation de langage C ................................................................................................. 56
Section 1 : Structure d’un langage C ................................................................................................. 56
Section 2 : Structure d’un programme C.......................................................................................... 56
Section 3 : Types de variables ........................................................................................................... 58
Section 4 : Déclaration des variables, instruction d’affectation et opérations d’E/S....................... 59
Chapitre 7 : Instructions de contrôle..................................................................................................... 67
Section 1 : Instructions conditionnelles ............................................................................................ 67
4
Syntaxe :
→ Action de répétition.
La partie principale est délimitée par les mots clefs Début et Fin
1.3. AFFECTATION :
1.4. OPERATEURS
Opérateurs
Il est à noter qu'il n'existe pas de véritable standard sur la forme d'écriture
des opérateurs algorithmiques, mais seulement une tendance très prononce
pour les symboles mentionnés.
Dès lors, aussitôt que la touche Entrée (Enter) a été frappée, l’exécution reprend.
Dans le sens inverse, pour écrire quelque chose à l’écran, c’est aussi simple que :
Avant de Lire une variable, il est très fortement conseillé d’écrire des libellés à
l’écran, afin de prévenir l’utilisateur de ce qu’il doit frapper (sinon, le pauvre
utilisateur passe son temps à se demander ce que l’ordinateur attend de lui… et
c’est très désagréable !) :
Lire NomFamille
- entiers : valeur numériques entières pouvant être signées ou non signées (codées
sur un ou plusieurs octets).
Exercice 1.1 :
Ecrire un algorithme qui lit le prix HT d’un article, le nombre d’articles et le taux
de TVA, et qui fournit le prix total TTC correspondant. Faire en sorte que des
libellés apparaissent clairement.
Solution 1.1 :
Algorithme Calcul_du_pttc
Début
Lire pht
Lire nb
11
Lire ttva
Fin
Exercice 1.2 :
Solution 1.2 :
Algorithme Calcul_du_carré
Variable
Début
Lire nb
carr ← nb * nb
Fin
Exercice 1.3 :
Solution 1.3 :
Algorithme Affichage_caractères
Début
t1 ← "belle Marquise"
t4 ← "d’amour"
Ecrire t1 & " " & t2 & " " & t3 & " " & t4
Ecrire t3 & " " & t2 & " " & t4 & " " & t1
Ecrire t2 & " " & t3 & " " & t1 & " " & t4
Ecrire t4 & " " & t1 & " " & t2 & " " & t3
Fin
Une condition est testée pour déterminer si l’action ou le groupe d’actions suivant
doit être exécuté.
Algorithme Racine_carrée
13
Variables
x: réel ~ opérande ~
Début
Saisir (x)
Si x > 0 Alors
r racine (x)
afficher(r)
FinSi
Fin
Variables
x: réel ~ opérande ~
Début
Saisir (x)
Si x < 0
Alors
Sinon
r racine (x)
afficher(r)
FinSi
Fin
Exemple 3.1:
Début
Lire Temp
Si Temp <= 0
Finsi
15
Finsi
Fin
Exemple 3.2:
Lire Temp
Finsi
Finsi
Finsi
Fin
…:…
Valeur n : Instruction n
FinCas
Boucheries en ligne
Produits Prix par kg (FCFA)
Cuisses 700
Rognons 800
Oignons 500
Solution :
Algorithme Prix_produit
Variable
Début
Lire(Produit)
Fin Cas
Fin
TantQue <Condition>
FinTantQue
Initialisation du compteur ;
18
Spécification de la condition
Changement de la valeur du compteur
Solution :
Algorithme Bonjour
Variables
n,i : Entier
Début
Lire(n)
i0
TantQue i<n
Ecrire(‶Bonjour ″)
ii+1
FinTantQue
Fin
Syntaxe :
19
FinPour
Organigramme :
Table de 7 :
7x1=7
7 x 2 = 14
7 x 3 = 21
7 x 10 = 70
Solution :
20
Algorithme Table_Multi
Variables N, i : Entier
Début
Lire N
Pour i ← 1 à 10 Pas 1
Fin
4-3. Répéter…Jusqu’à
La structure Répéter est une structure itérative, qui permet d’exécuter au moins
une itération avant de vérifier la condition.
Syntaxe :
Répéter
Jusqu’à <Condition>
Organigramme :
21
Solution :
Algorithme Division
Variables a, b, c : Réel
Début
Lire a
Répéter
Lire b
Jusqu’à b<>0
ca/b
Fin
22
En résumé :
Principe :
Si val < T[milieu] alors on va chercher val dans la partie gauche du tableau
T.
Si val > T[milieu] alors on va chercher val dans la partie droite du tableau T.
23
On poursuit la recherche tant que T[milieu] est différent de val est tant que la
dimension de sous tableau reste valide.
VAR
DEBUT
pos← -1
inf← 1
sup← N
pos = mil
sup ← mil-1
sinon
inf ← mil+1
finsi
Finsi
FinTantque
INDICE←pos
FIN
24
Une fonction ou une procédure peut elle-même appeler une ou plusieurs fonctions
et procédures.
Variable
Début
Fin
Variable
Début
Fin
Début
Intermediaire Intermediaire / 2
Moyenne Intermediaire
Fin
Section 9 : Récursivité
Une des caractéristiques les plus importantes de programmation est la possibilité
pour une procédure ou une fonction de s’appeler elle-même. On parle de
récursivité. La récursivité est particulièrement utile pour traiter tous les
problèmes formalisables de façon récursive, bien qu’il soit possible de
programmer des solutions n’utilisant pas la récursivité pour ces problèmes.
Syntaxe :
N ! = N * N-1 * ………. 2 * 1
Définition récursive :
N ! = N * (N – 1) ! et 0 ! = 1
Solution itérative :
27
VAR
i, F: entier
DEBUT
Si (n = 0 ) alors
FACT← 1
Sinon F← 1
F←F * i
Finpour
FACT←F
Finsi
FIN
Solution récursive :
VAR
F : entier
DEBUT Si (n = 0 ) alors
F←1
Sinon
Finsi
28
FACT←F
FIN
/* PROGRAMME PRINCIPAL*/
DEBUT ( P.P )
Répéter
Lire ( n )
Jusqu’à (n ≥ 0 )
FIN
Interprétation
Les appels de fonction sont alors exécutés en ordre inverse, au fur et à mesure
qu’ils sont retirés de la pile.
Une pile est une structure de données de type LIFO (Last In, First Out) ou «
Dernier Entré, Premier Sorti »
30
Note: Quand une variable pointeur ne pointe sur aucun emplacement, elle doit
contenir la valeur Nil (qui est une adresse négative)
Si une structure contient une donnée avec un pointeur vers un élément de même
composition on parle lors de liste chaînée.
Une liste chaînée est donc une structure de données dans laquelle les éléments
sont rangés linéairement. Chaque élément (dit nœud) est lié à son successeur. Il
est donc impossible d'accéder directement à un élément quelconque de la liste
(sauf le premier auquel on accède via un pointeur –généralement appelé tête de
liste).
Tête est le pointeur avec l’adresse du premier élément alors que chaque nœud est
un enregistrement avec une case (ici Info) pour la valeur à manipuler (12, 25, -4
et 11) et une case (ici Suiv) de type pointeur avec l’adresse où se trouve l’élément
suivant.
31
Les listes ont l'avantage d'être réellement dynamiques, c'est dire que l'on peut à
loisir les rallonger ou les raccourcir, avec pour seule limite la mémoire disponible.
Type P = ^Element
Element = Enregistrement
Info : Type-C ;
Suiv : ^Element
Fin ;
Note: Cette déclaration est toujours valable sauf qu’il faut à chaque fois préciser
Type-C selon le type des données manipulées.
La création d’une liste revient à des ajouts (insertions) répétitifs de nœuds qui
vont la constituer. L’opération commence cependant à partir d’une liste vide
(il est donc essentiel d’affecter le Nil à la tête avant de commencer). Pour
insérer un nouveau élément il est faut d’abord réserver un espace pour ce
nœud. L’opération est possible via la procédure prédéfinie ALLOUER (p) qui
permet de repérer un espace suffisant pour le nœud (Partie donnée et pointeur
de l’élément qui va suivre). L’espace trouvé, son adresse dans la mémoire est
sauvegardée dans la variable pointeur p.
L’absence du Nil dans la liste implique des conditions d’arrêt en rapport avec la
tête de liste. Il s’avère alors nécessaire de ne pas traiter tous les "n" éléments de
la liste dans la même boucle mais plutôt de traiter "n-1" éléments ensemble et de
répéter le traitement pour le nœud qui n’a pas été traité.
Note: L’élément à traiter seul peut être le premier de liste (et avoir une boucle de
traitement du 2ème au dernier élément) ou le dernier nœud de la liste (traiter du
1er à l’avant dernier élément dans la boucle puis réécrire le traitement pour le
dernier nœud.)
Exemple : Ecrire une fonction qui calcul le nombre de zéro dans une liste
d’entiers. La liste est supposée déjà lue.
Solution :
Variable
Pt : PX ;
Co : Entier ;
Debut
Co 0 ;
PtL ;
Tantque Pt^. Suiv ≠ L Faire /* Traitement des N-1 premiers nœuds ensemble*/
Debut
Si Pt^.Info = 0 Alors
34
CoCo + 1
FinSi ;
PtPt^. Suiv
Fin
FinTantque ;
CoCo + 1
FinSi ;
Calcul Co ;
Fin ;
Insertion en début:
Precedent,
35
Suivant : VersElement;
end; { Element }
procedure Insertion
begin { InsertionDebut }
new(Nouveau);
end;
{ with }
Debut
^.Precedent := Nouveau;
- Calcul de la hauteur d’un arbre : se base sur la définition récursive un arbre vide
est de hauteur 0 et un arbre non vide a pour hauteur 1 + la hauteur maximale entre
ses fils.
- Calcul du nombre de nœuds : fait selon la règle Si l'arbre est vide : renvoyer 0 ;
Sinon renvoyer 1 plus la somme du nombre de nœuds des sous arbres.
- Calcul du nombre de feuilles : sachant qu’un arbre vide n'a pas de feuille et qu’un
arbre non vide à son nombre de feuille défini de la façon suivante : si le nœud est
une feuille alors on renvoie 1, si c'est un nœud interne alors le nombre de feuille
est la somme du nombre de feuille de chacun de ses fils.
- Calcul du nombre de nœuds internes : selon la règle récursive : un arbre vide n'a
pas de nœud interne ; si le nœud en cours n'a pas de fils alors renvoyer 0 ; si le
nœud a au moins un fils, renvoyer 1 plus la somme des nœuds interne des sous
arbres.
- Parcours d’un arbre : c’est l’opération de visiter tous les nœuds de l'arbre
Exemple :
I- Pile
Quand on vous dit pile penser directement à une pile d’assiettes qu’il faut
manipuler avec attention pour éviter les dégâts. Une pile est un ensemble de
valeurs ne permettant des insertions ou des suppressions qu’a une seule
extrémité, appelée sommet de la pile. Empiler un objet sur une pile P consiste
à insérer cet objet au sommet de P (dans la pile d’assiettes une nouvelle assiette
ne peut être ajoutée qu’au-dessus de celle qui se trouve au sommet) ; Dépiler
un objet de P consiste à supprimer de P l'objet placé au sommet (dans la pile
d’assiettes seule peut être retirée celle qui se trouve au sommet). L'objet dépilé
est retourné comme résultat du traitement.
Une propriété remarquable des piles est qu'un objet ne peut être dépilé qu'après
avoir dépilé tous les objets qui sont placés "au-dessus" de lui, ce qui fait que
les objets quittent la pile dans l'ordre inverse de leur ordre d'arrivée. Pour cette
39
raison, une pile est aussi appelée structure LIFO (Last In, First Out) ou (dernier
arrivé, premier sorti) En informatique une pile sert essentiellement à stocker
des données qui ne peuvent pas être traitées immédiatement, car le programme
a une tâche plus urgente ou préalable à accomplir auparavant. En particulier
les appels et retours de fonctions sont gérés grâce à une pile appelée pile
d'exécution.
- Une structure de données pour enregistrées les valeurs (elle peut être statique
ou dynamique)
- Pile_vide : pour vérifier si une pile est vide ou non et savoir alors s’il reste
des valeurs à traiter ou non ;
I-1-1- Déclaration
Constante
N = …. ; /* taille du tableau*/
Pile = Enregistrement
T : Tab ;
Sommet : Entier
Fin ;
Note : Les données enregistrées dans la pile peuvent être des entiers, des réels,
des caractères, des chaînes de caractères, des booléens, des tableaux, des
pointeurs de listes ou encore des piles ou files.
Debut
P. Sommet 0
41
Fin ;
Debut
Si P. Sommet = 0 Alors
Pile_videvrai
Sinon
Pile_videfaux
FinSi ;
Fin ;
Une autre façon plus compacte d’écrire cette fonction est la suivante :
Debut
Pile_videP. Sommet = 0;
Fin ;
II- File
Quand on vous dit file penser directement à une file d’attente où chacun à son
tour qu’il doit respecter.
42
Une file est un ensemble de valeurs qui a un début (Debut) et une fin (Queue).
Enfiler un objet sur une file F consiste à insérer cet objet à la fin de la file F
(dans la file d’attente un nouvel arrivant se met à la queue c.-à-d., après la
personne arrivée juste avant lui) ;
- Une structure de données pour enregistrées les valeurs (elle peut être statique
ou dynamique)
- Une variable Queue qui indique le dernier élément de la file. Comme pour
les piles, la manipulation d’une file revient à l’appel de fonctions et procédures
dites de bases définies une seule fois et utilisées autant de fois qu’il est
nécessaire. Ces sous-algorithmes sont :
43
- File_vide : pour vérifier si une file est vide ou non et savoir alors s’il reste
des valeurs à traiter ou non ;
3- une file qui vient d’être déclarée (et non encore utilisée)Debut = 1 et
Queue = 0
II-1-1- Déclaration
Type
Fin ;
Note : Les données enregistrées dans la pile peuvent être des entiers, des réels,
des caractères, des chaînes de caractères, des booléens, des tableaux, des
pointeurs de listes ou encore des piles ou files.
Debut
F. Debut 1 ;
F. Queue0
Fin ;
45
Debut
File_videvrai
Sinon File_videfaux
FinSi ;
Fin ;
Une autre façon plus compacte d’écrire cette fonction est la suivante :
Fin ;
Section 3 : Recherche
Principe
Algorithme de recherche
ABRRecherche(x,k)
Début
Si x = Nil
Sinon Si k = cle(x)
FinSi
Fin
47
Chapitre 4 : Fichiers
Section 1 : Notion des fichiers
Fichiers textes ;
Fichiers binaires ;
48
Sur ces images, nous avons deux fonctions calculant le nombre de diviseurs d’un
entier n.
que dans les deux cas on effectue deux additions, une division euclidienne et un
test. Chacune de ces opérations est effectuée n fois dans le premier cas, √ n fois
dans le second. Nous ne connaissons pas le temps τ1 nécessaire à la réalisation de
ces différents calculs, mais on peut légitimement penser que le temps total
d’exécution de diviseurs1 n’est pas éloigné de τ1n + τ2, le temps τ2 étant le temps
requis par les autres opérations. De même, le temps requis par la fonction
diviseurs2 est de l’ordre de τ’1 √ n + τ’2 . Les temps τ2 et τ’2 sont négligeable
pour de grandes valeurs de n ; de plus les valeurs de τ1 et τ’1 importent peu ; elle
dépend de conditions matérielles qui nous échappent. Nous n’allons retenir que le
taux de croissance de chacune de ces deux fonctions : proportionnel à n pour la
première (on dira plus loin qu’il s’agit d’un algorithme de coût linéaire),
proportionnel à √ n pour la seconde. Autrement dit :
Les comparaisons entre nombres (du moment que ceux-ci sont codés sur un
nombre fixe de bits) seront aussi considérées comme des opérations à coût
constant, de même que la comparaison entre deux caractères. En revanche, la
comparaison entre deux chaînes de caractères ne pourra être considérée
comme une opération élémentaire, même s’il est possible de la réaliser en une
seule instruction Python. Il en sera de même des opérations d’affectation : lire
ou modifier le contenu d’un case d’un tableau est une opération élémentaire,
mais ce n’est plus le cas s’il s’agit de recopier tout ou partie d’un tableau dans
un autre, même si la technique du slicing en Python permet de réaliser très
simplement ce type d’opération.
Cette notation indique que dans le pire des cas, la croissance de f (n) ne
dépassera pas celle de la suite (αn). L’usage de cette notation exprime
l’objectif qu’on se donne le plus souvent : déterminer le temps d’exécution
dans le cas le plus défavorable. On notera qu’un usage abusif est souvent fait
de cette notation, en sous-entendant qu’il existe des configurations de l’entrée
pour lesquelles f (n) est effectivement proportionnel à αn. On dira par exemple
que la complexité de la fonction diviseurs2 est un O(√ n) mais jamais qu’elle
est un O(n), même si mathématiquement cette assertion est vraie puisque f (n)
= O(√ n) =⇒ f (n) = O(n). D’un usage beaucoup moins fréquent, la notation Ω
exprime une minoration du meilleur des cas :
Cette notation exprime le fait que quelle que soit le configuration de l’entrée,
le temps d’exécution de l’algorithme sera grosso-modo proportionnel à αn.
Ordre de grandeur et temps d’exécution
55
Déclarations/définitions :
Déclaration : la déclaration d'un objet C donne simplement ses caractéristiques
au compilateur et ne génère aucun code.
Définition : la définition d'un objet C déclare cet objet et créée effectivement cet
objet.
Fonctions : Ce sont des sous-programmes dont les instructions vont définir un
traitement sur des variables.
Elles peuvent retourner une valeur a la fonction appelante.
Le programme principal est une fonction dont le nom doit impérativement être
main.
Les fonctions ne peuvent pas être imbriquées.
Des commentaires: éliminés par le préprocesseur, ce sont des textes compris
entre /* et */ ou // pour le C++ et certains compilateurs du C. On ne doit pas les
imbriquer et ils peuvent apparaitre en tout point d'un programme (sauf dans une
constante de type chaine de caractères ou caractère).
Pour ignorer une partie de programme il est préférable d'utiliser une directive du
préprocesseur (#if 0 ... #endif).
57
Exemple :
Créer un programme en C affichant le message suivant : « Bonjour et soyez les
bienvenus en C»
/* **************************
Programme de démonstration
**************************
*/
#include “stdio.h“
#include “stdlib.h“
int main()
{
printf(“Soyez les bienvenus en C++”); /* Affiche un message*/
system(“pause“) ;
return 0 ;
2.1.Mots-cles
Les mots-clés du langage sont strictement réservés et ne peuvent être utilisés
comme identificateurs.
Voici la liste des mots clés en C/C++ :
2.3 Identicateurs
Les identificateurs, de variables, de fonctions, obéissent à la règle habituelle
"suite de caractères alphanumériques, l’initiale devant être une lettre". Ce sont
des noms qu’on donne selon le gré du programmeur. Le caractère de
soulignement _ est autorisé. L’utilisation d’autres caractères non
alphanumériques est à éviter dans la mesure du possible.
L’utilisation de noms assez longs a l’immense avantage de mieux documenter
un programme :
float constante_de_planck; est probablement plus explicite que :
float h;
NB : il faut éviter d’utiliser le caractère de soulignement _ en début ou fin d’un
identificateur, cette notation est habituellement réservée aux mécanismes
internes des compilateurs.
À ces types fondamentaux s’ajoutent des types dérivés à l’aide des mots clés «
long » et « short ».
Ces types dérivés se distinguent des types de base par l’étendue des plages de
valeurs qu’ils peuvent stocker. Par exemple, le type long int est plus grand que
59
le type int. Inversement, le type short int est plus court que le type int. De même,
le type long double est plus grand que le type double.
Il est également possible de n’utiliser que des plages de valeurs positives pour
les types intégraux (sauf pour les booléens). Pour cela, on peut utiliser les mots
clés signed et unsigned. Les types non signés ne peuvent contenir de valeurs
négatives, mais leur valeur maximale est jusqu’à deux fois plus grande que pour
leur homologues signés.
Exemple. Types signés et non signés
unsigned short int
signed short int
unsigned int
signed int
unsigned long int
long unsigned int
Une affectation composée est une opération permettant de réaliser en une seule
étape une opération normale et l’affectation de son résultat dans la variable
servant de premier opérande. Les affectations composées utilisent la syntaxe
suivante :
Variable op_aff valeur
où op_aff est l’un des opérateurs suivants : ’+=’, ’-=’, ’*=’, etc. Cette syntaxe est
strictement équivalente à :
variable = variable op valeur
et permet donc de modifier la valeur de variable en lui appliquant l’opérateur op.
Exemple : Affectation composée
i*=2; /* Multiplie i par 2 : i = i * 2. */
4.2.2 Instruction d’affectation composée
Il est possible de créer des instructions composées, constituées d’instructions plus
simples. Les instructions composées se présentent sous la forme de blocs
d’instructions où les instructions contenues sont encadrées d’accolades ouvrantes
et fermantes (caractères ’{ et ’}’).
Exemple 6. Instruction composée
{
i=1;
j=i+3*g;
}
Note : Un bloc d’instructions est considéré comme une instruction unique. Il est
donc inutile de mettre un point-virgule pour marquer l’instruction, puisque le bloc
lui-même est une instruction.
62
Symboles Descriptions
\n Saut de ligne
\t Tabulation horizontale
\a Signal-sonnerie
− −√ −4
=
2
Solution: x=(-b-sqrt(pow(b,2)-4*a*c))/2*a ;/*Utilisez #include ‘’math.h’’ à
l’entête*/
12. Ecrivez sous la forme d'une instruction d’affectation la formule de calcul de
l’aire d'un cercle s= .r2 .
Solution : s=3.14*r*r;
13. Ecrivez sous la forme d'une instruction d’affectation la formule de calcul de
l’aire d’une surface et d’un volume du cylindre.
65
Solution :
s=2*pi*r*(h+r); avec pi=3.14 ;
v=pi*r*r*h ;
III/ Operations d’Entrée/Sortie
14. Écrire un programme qui affiche sur l’écran votre prénom(s) et votre nom(s).
15. Ecrire un programme qui affiche sur l’écran ce texte :
Triste temps ! Yeux de charme !
Agréable à moi votre radieuse beauté.
J'aime le dépérissement somptueux de la nature,
en rouge et de la forêt d'or vêtu.
16. Ecrivez une instruction qui affiche sur une seule ligne des valeurs des
variables a, b et c de type entier (int).
Solution : printf(‘’a=%i, b=%i, c=%i‘’,a,b,c);/*%i- la chaine de format des
nombres entiers*/
printf(‘’c=%i\n‘’,c);
18. Donnez une instruction qui fournit une entrée avec le clavier des valeurs des
variables radius et hauteur de type float sur la même ligne.
Solution : scanf(‘’%f %f‘’,&radius,&hauteur);/*%f- la chaine de format des
nombres décimaux*/
19. Ecrivez des instructions qui fournissent l’entrée des valeurs des variables
fractionnaires (type float) u et r. Supposé que l’utilisateur après avoir utilisé un
numéro de série de chaque nombre va appuyer sur le bouton du clavier <Entrée>.
Solution: scanf(‘’%f ‘’,&u);/*%f- la chaine de format des nombres décimaux*/
scanf(‘’%f ‘’,&r);
20. Écrire une instruction qui fournit les valeurs d'entrée des variables u et r.
Supposé que l’utilisateur choisira les nombres dans la même rangée. Voir la
solution de l’exo.18
21. Implémenter une application en mode console pour calculer le volume du
cylindre. Cette application doit demander à l’utilisateur de lire au clavier la valeur
du rayon et la valeur de la hauteur.
Voici la liste de quelques fonctions mathématiques à retenir à partir de la
bibliothèque math.h :
if (test) opération1;
else opération2;
Les opérateurs logiques applicables aux expressions booléennes sont les suivants
:
Opérateurs logiques
switch (valeur)
{
case cas1:
[instruction;
[break;]
]
case cas2:
[instruction;
[break;]
]...
case casN:
[instruction;
[break;]
]
[default:
[instruction;
[break;]
]
]
}
valeur est évaluée en premier. Son type doit être un entier. Selon le résultat de
l’évaluation, l’exécution du programme se poursuit au cas de même valeur. Si
aucun des cas ne correspond et si default est présent, l’exécution se poursuit après
default. Si en revanche default n’est pas présent, on sort du switch.
Les instructions qui suivent le case approprié ou default sont exécutées. Puis, les
instructions du cas suivant sont également exécutées (on ne sort donc pas du
switch). Pour forcer la sortie du switch, on doit utiliser le mot clé break.
Les boucles sont des instructions de contrôle qui permettent de réaliser une
opération plusieurs fois (répétitions), tant qu’une condition est vérifiée.
Note : En C++, il est possible que la partie initialisation déclare une variable.
Dans ce cas, la variable déclarée n’est définie qu’à l’intérieur de l’instruction for.
Par exemple:
for (int i=0; i<10; ++i); est strictement équivalent à :
{
int i;
for(i=0; i<10; ++i)
}
2.2. Le while
Le while permet d’exécuter des instructions en boucle tant qu’une condition est
vraie. Sa syntaxe est la suivante :
while(test) opération;
où opération est effectuée tant que test est vérifié. Comme pour if, les parenthèses
autour du test sont nécessaires. L’ordre d’exécution est :
test
si vrai :
opération
retour au test
70
Exemple: Boucle do
p = i = 1;
do
{
p = p * i;
i = i + 1;
} while (i != 10);
Exercices du chapitre
A) Instruction if
1. Ecrire un programme en mode console pour calculer le prix d'achat (pantalons
et chaussures avec leurs quantités), en tenant compte des réductions. 10% de
réduction disponible si le montant de l'achat est plus de 9000 FCFA, 15% - si le
montant est plus de 19000 FCFA.
B) Boucle for
3. Écrire un programme qui affiche une table des carrés des dix premiers nombres
entiers positifs. Le programme doit travailler de la manière suivante :
C) do... while
72
D) while
7. Ecrire un programme qui affiche sur l’écran un tableau des valeurs de fonction
y = 2x2 -5x-8 de l’intervalle -4 à 4. Incrément à 0,5 argument.
73
} Procédure
Fonction n’attendant pas de paramètres et ne renvoyant pas de valeur.
return 0; //Cette ligne est facultative.
74
9.3 Utilisation
On accède à un tableau en l’appelant par son nom et son numéro de case.
Exemple :
76
Exercice 1 :
Ecrire un programme, qui saisit à l’aide du clavier un tableau de 1-ère dimension
de 5 éléments. Apres cela, le programme doit afficher le nombre des éléments
non-nuls.
Saisissez le tableau des nombres entiers
Apres chaque saisie des nombres, appuyer sur Entrée
Section 2 : Fichiers
2-1 - La notion de flux
Les entrées/sorties (E/S) ne font pas partie du langage C car ces opérations sont
dépendantes du système. Néanmoins puisqu'il s'agit de tâches habituelles, sa
bibliothèque standard est fournie avec des fonctions permettant de réaliser ces
opérations de manière portable. Ces fonctions sont principalement déclarées dans
le fichier stdio.h. Les entrées/sorties en langage C se font par l'intermédiaire
d'entités logiques, appelés flux, qui représentent des objets externes au
programme, appelés fichiers. En langage C, un fichier n'est donc pas
nécessairement un fichier sur disque (ou périphérique de stockage pour être plus
précis). Un fichier désigne en fait aussi bien un fichier sur disque (évidemment)
qu'un périphérique physique ou un tube par exemple. Selon la manière dont on
veut réaliser les opérations d'E/S sur le fichier, qui se font à travers un flux, on
distingue deux grandes catégories de flux à savoir les flux de texte et les flux
binaires. Les flux de texte sont parfaits pour manipuler des données présentées
sous forme de texte. Un flux de texte est organisé en lignes. En langage C, une
ligne est une suite de caractères terminée par le caractère de fin de ligne (inclus) :
'\n'. Malheureusement, ce n'est pas forcément le cas pour le système sous-jacent.
Sous Windows par exemple, la marque de fin de ligne est par défaut la
combinaison de deux caractères : CR (Carriage Return) et LF (Line Feed) soit '\r'
77
et '\n' (notez bien que c'est CR/LF c'est-à-dire CR suivi de LF pas LF suivi de CR).
Sous UNIX, c'est tout simplement '\n'. On se demande alors comment on va
pouvoir lire ou écrire dans un fichier, à travers un flux de texte, de manière
portable. Et bien c'est beaucoup plus simple que ce à quoi vous-vous attendiez :
lorsqu'on effectue une opération d'entrée/sortie sur un flux de texte, les données
seront lues/écrites de façon à ce qu'elles correspondent à la manière dont elles
doivent être représentées et non caractère pour caractère. C'est-à-dire par exemple
que, dans une implémentation où la fin de ligne est provoquée par la combinaison
des caractères CR et LF, l'écriture de '\n' sur un flux de texte va provoquer
l'écriture effective des caractères '\r' et '\n' dans le fichier associé. Sur un flux
binaire les données sont lues ou écrites dans le fichier caractère pour caractère.
La communication avec une ressource externe (un modem, une imprimante, une
console, un périphérique de stockage, etc.) nécessite un protocole de
communication (qui peut être texte ou binaire, simple ou complexe, ...) spécifique
de cette ressource et qui n'a donc rien à voir le langage C. La norme définit tout
simplement les fonctions permettant d'effectuer les entrées/sorties vers un fichier
sans pour autant définir la notion de matériel ou même de fichier sur disque afin
de garantir la portabilité du langage (ou plus précisément de la bibliothèque).
Cependant, afin de nous fixer les idées, nous n'hésiterons pas à faire appel à ces
notions dans les explications. Les fichiers sur disque servent à stocker des
informations. On peut « naviguer » à l'intérieur d'un tel fichier à l'aide de fonctions
de positionnement (que nous verrons un peu plus loin). A chaque instant, un «
pointeur » indique la position courante dans le fichier. Ce pointeur se déplace, à
quelques exceptions près, après chaque opération de lecture, d'écriture ou appel
d'une fonction de positionnement par exemple. Bien entendu, cette notion de
position n'est pas une spécificité exclusive des fichiers sur disque. D'autres types
de fichiers peuvent très bien avoir une structure similaire.
78
perror(msg);
Si nous n'avons pas parlé de ces fonctions auparavant, c'est parce que nous n'en
avions pas vraiment jusqu'ici besoin. A partir de maintenant, elles vont être très
utiles car les fonctions d'entrées/sorties sont sujettes à de très nombreuses sortes
d'erreurs : fichier non trouvé, espace sur disque insuffisant, on n'a pas les
permissions nécessaires pour lire ou écrire dans le fichier, ...
• "w" : ouvrir le fichier en écriture. S'il n'existe pas, il sera créé. S'il existe déjà,
son ancien contenu sera effacé.
• "a" : ouvrir le fichier en mode ajout, qui est un mode dans lequel toutes les
opérations d'écriture dans le fichier se feront à la fin du fichier. S'il n'existe pas, il
sera créé.
Quel que soit le cas, le fichier sera associé à un flux de texte. Pour spécifier qu'on
veut ouvrir le fichier en tant que fichier binaire, il suffit d'ajouter le suffixe 'b'
(c'est-à-dire "rb", "wb" ou "ab"). Sauf dans le cas du mode "ab" et dérivés, dans
80
• avant d'effectuer une opération de lecture juste après une opération d'écriture, il
faut tout d'abord appeler fflush ou une fonction de positionnement
• avant d'effectuer une opération d'écriture juste après une opération de lecture, il
faut d'abord appeler une fonction de positionnement, à moins d'avoir atteint la fin
du fichier
Le programme suivant crée un fichier, hello.txt, pour y écrire ensuite une et une
seule ligne : Hello, world.
#include <stdio.h>
int main() {
FILE * f;
f = fopen("hello.txt", "w");
81
if (f != NULL) {
fclose(f); }
else perror("hello.txt");
return 0;
#include <stdio.h>
int main() {
FILE * f;
f = fopen("hello.txt", "wb");
if (f != NULL) {
fclose(f);
else
perror("hello.txt");
return 0;
}
82
#include <stdio.h>
#include <string.h>
int main()
{ char src[FILENAME_MAX];
FILE * fsrc;
printf("source : ");
saisir_chaine(src, sizeof(src));
if (fsrc == NULL)
perror(src);
saisir_chaine(dest, sizeof(dest));
if (strcmp(src, dest) == 0)
if (fdest == NULL)
perror(dest);
else { int c;
printf("Copie terminee.\n"); } }
fclose(fsrc); }
return 0;
if (p != NULL) *p = '\0';
return ret;
Une erreur d'E/S est erreur qui peut se produire lors d'une tentative d'opération
d'E/S, par exemple : fin de fichier atteinte, tentative d'écriture dans un fichier
84
La fonction feof :
peut être appelé à n'importe quel moment pour connaître si l'on a atteint la fin du
fichier. Je rappelle qu'un programme (du moins d'après les fonctions du C) ne peut
affirmer que la fin d'un fichier a été atteinte qu'après avoir tenté de lire dans le
fichier alors qu'on se trouve déjà à la fin c'est-à-dire derrière le dernier octet, pas
juste après avoir lu le dernier octet, donc faites gaffe. Evidemment, une telle
fonction ne sera utilisée que sur un fichier ouvert en lecture. Elle retourne VRAI
si la fin de fichier a été atteinte et FAUX dans le cas contraire. Cette information
est en fait maintenue par un indicateur de fin de fichier qui indique à tout moment
si on a oui ou non déjà atteint la fin du fichier. Après un appel fructueux à une
fonction de positionnement, l'indicateur de fin de fichier est remis à zéro. La
fonction ferror :
Bibliographie