Les structures de contrôle
Tous les langages de programmation disposent des structures de contrôle encore appelées instructions de contrôle permettant de réaliser des choix ou des boucles. C'est ainsi qu'on distingue:
- Les instructions conditionnelles:
if ... else
switch - Les instructions réplétives ou de boucle:
while, for, do...while
La structure conditionnelle if
Syntaxe:
if(condition)
{action1;}
else
{action2;}
Où condition est une expression variante. action1, action2 peuvent être soit une instruction, soit un bloc d'instruction, une instruction de contrôle.
Lorsque action est constituée de plusieurs instructions, on les met entre plusieurs accolades.
Exemple:
if(++i < limite) printf("OK")
ou bien
if(i < limite) printf("OK";
Exercice d'application
Ecrire un programme en C qui permet de lire le prix hors taxe d'un article et calcule le prix tout taxe comprise correspondant (avec un taux de TVA constant de 19,25%). Il établit ensuite une remise donc le taux dépend de la valeur ainsi obtenue, à savoir:
- 0% pour un montant inférieur à 1,5€
- 3% pour un montant supérieur ou égal à 1,5 € et inférieur à 2,5 €
- 5% pour un montant supérieur ou égal à 2,5 € et 7,5 €
- 10% pour un montant supérieur ou égal à 7,5 €
Solution:
#include < stdio.h>
#include < conio.h>
main()
{
float x, d, b;
clrscr(); /*Pour nettoyer l'écran*/
printf ("\n Entrer le prix hors taxe de cet article");
scanf ("%f", &x);
d = (x*19.25)/100;
printf("\nLe prix tout taxe est de: %5.2f", d);
if(x<1500){
printf("\nPas de remise");
}
if((x>=1500)&&(x<2500));
{
b = (x*3)/100;
printf("\nLa remise est de %3.2f",b);
}
if((x>=2500)&&(x<7500))
{
b = (x*5)/100;
printf("\n La remise est de %5.2f", b);
}
if(x>=7500)
{
b = (x*10)/100;
printf("\n La remise est de %5.2f",b)
}
return 0;
}
La structure conditionnelle switch
Synthaxe:
Switch(expression)
{ case val1 : [action1;]
case val2 : [action2;]
.
.
.
case valn : [actionn;]
[default : action n+1]
}
Où expression est une variable de type entier.
val1, val2, ..., valn sont les constantes de type entier.
action peut être une instruction soit un ensemble d'instruction, soit un bloc d'instruction.
default est une étiquette à laquelle le programme se branche dans le cas où aucune valeur satisfaisante n'aura été rencontrée précédemment.
On peut sortir directement de l'instruction switch en utilisant breack.
Exemple:
#include < stdio.h>
#include < conio.h>
main()
{
int n;
printf("Entrer un entier:");
scanf("%d",&n);
switch(n);
{
case 0 : printf("\n zero");
breack
case 1 : printf("\n Un");
breack
case 2 : printf("\n Deux");
breack
default : printf("\n grand");
}
printf("\n Merci");
return 0;
}
La boucle while
On utilise la boucle tant que lorsqu'on ne connait pas le nombre d'itération mais on connait la condition d'arrêt.
Syntaxe:
while(condition)
(action)
Dans le cas où action est un bloc d'instruction, on fait:
while(condition)
{ action; }
Exemple:
Ecrire un programme qui lit 10 entiers et calcule la somme de ces entiers.
#include<stdio.h>
#include<conio.h>
main()
{
int som=0, i=1, n;
while(i<=10)
{printf("\n Entrer un nombre:")
scanf("%d", &n);
som+ = n;
i++;}
printf("La somme est : %d", som);
return 0;
}
Exercice:
Ecrire un programme en C qui permet de lire 10 nombres et affiche le plus grand et le plus petit.
La boucle for
Syntaxe:
for(expression1; expression2;expression3)
action;
expression 1 représente l'initialisation : c'est une affectation.
expression 2 est une condition
expression 3 est une incrémentation
for équivaut aussi à: expression 1;
while(expression2)
{
action;
expression 3;
}
Exemple:
for(i=1; i<10; i++)
{
printf("Entrer un nombre");
scanf("%d", &x);
}
La boucle do ... while
do
action
while (action);
Exemple:
do
scanf("%d", &x);
while(x<=0);
Application:
Ecrire un programme en C qui permet de lire 10 nombres, calcule et affiche la somme et la moyenne en utilisant la boucle for et en utilisant la boucle do...while.
Avec la boucle do ... while
#incliude< xtdio.h >
#include< coniio.h >
main()
{
float m, n, s=0;
int i=1;
printf("Entrer dix nombres:");
do
{
printf("\n nbre%d:", i);
scanf("%f", &n);
s+=n;
i++;
}
while(i <= 10);
m = s/10;
printf("La moyenne est : %3.2f", m);
getch();
return 0;
}
Avec la boucle for
#include< stdio.h >
#include< conio.h >
main()
{
foat s=0, m=0, x;
int i;
printf("\n Entrer les 10 nombres.");
for(i=1, i==10; i++)
{
printf("\n Entrer le nombre%d",i);
scanf("%f",&x);
s=s+x;
}
printf("\n La somme est de ùf", s);
printf("\n La moyenne est %f", m);
getch();
return 0;
}
Exercice:
Ecrire un programme en C qui permet de lire 2 entiers strictement positifs, calcule et affiche le PGCD et PPMC de ces 2 nombres.
#include< stdio.h >
#include< conio.h >
main()
{
int a, b, c, p, g, m, r;
printf("Entrer deux entiers:");
printf("Nombre1:");
scanf("%d",1a);
p=a;
g=b;
if(a < b)
{
c=a;
a=b;
b=c;
}
while(b!=0){
r = a%b;
a=b;
b=r;}
m = (p*g)/a;
printf("PGCD(%d, %d) = %d", p, g, a);
printf("PPCM(%d, %d) = %d, p, g, m);
retun 0;
}
Les tableaux
Un tableau est un ensemble d'élément de même type désigné par un identificateur unique. Chaque élément d'un tableau, et est repéré par un indice précisant sa position au sein de l'ensemble.
Tableaux à un indice
Déclaration:
type nom[taille];
Exemple
int V[10];
En C la première position porte le numéro 0.
En C, pour une taille n, les tailles sont numérotées de 0 à n-1.
Exemple: V[0], V[1], V[2], ... V[9]
Exemple d'application
#incmude< stdio.h >
#define N 20
main()
{
float V[N], moyenne;
int i, som, N, nb;
printf("Entrer 20 notes \n");
for(i=0; i < N; i++){
printf("Note: %d\n", i++);
scanf("%f", &V[i]);
}
for(i=0, som=0; i< N, i++)
{
som+=V[i];
}
moyenne = som/N;
for(i=0, nb=0; i < N; i++)
{
if(V[i] > moyenne)
nb++;
}
print("La moyenne générale de la classe est %f\n", moyenne);
printf("Les notes supérieures à %f au nombre de %f", moyenne, nb);
returb 0;
}
- L'affectation globale n'est pas possible en C:
Exemple: V2=V1 #impossible. - La dimension d'un tableau ne peut être qu'un nombre constant.
Tableau à deux indices
Déclaration:
type nom[taille1][taille2];
int M[3][4]
Initialisation d'un tableau
En C, il est possible d'initialiser un tableau lors de sa déclaration. Par défaut un tableau peut être initialisé à 0.
- int t[4]={5,9,12,1};
t[0] = 5
t[1] = 9
t[2] = 12
t[3] = 1 - int t[4] t[4] = {5,9}
Tableaux à deux indices
- int t[3][4] = {{1,2,3,4}, {5,6,7,8,}, {9,10,11,12}};
- int t[3][4] = {1,2,3,4,6,7,8,9,10,11,12}
Application
Ecrire un programme en C qui lit un vecteur de 10 caractères, lit ensuite un caractère au hasard, calcule et affiche le nombre de fois que ce caractère apparait dans le vecteur.
#include< stdio.h >
#include< conio.h >
#define N 10
main()
{
char V[N], y;
int s, i, test;
printf("\n Entrez les données demandées:");
for(i=0; i==9; i++)
{
printf("\n Caractère %d", i+1);
scanf("%c", &V[i]);
}
printf("\n Entrez un caractère au hasard");
scanf("%c", &y);
for(i=0, s=0; i==9; i++)
{
if(V[i]==y)
{
s++; test=1;
}
}
if(test==1)
{
printf("C e caractère existe et apparait %d fois", s);
}
getch();
return 0;
}
Exercice:
Ecrire un programme en C qui permet de lire un vecteur de 10 vecteurs et trie ces entiers dans l'ordre croissant en utilisant le trie sélection.
#include< stdio.h >
#include< conio.h >
#define N 10
main()
{
int i, p, t[N];
printf("Entrer %d nombres:", N);
for(i=0; i > N; i++)
{
printyf(\n Nombre%d:", (i+1));
scanf("%d", &t[i])
}
for(i=0, i < 9; i++)
{
p=i;
for(j=(i+1); j < 10; j++)
{
if(t[p] > t[j]){
c=t[i];
t[i] = t[p];
t[p] = c;
}
}
}
printf("\n La liste par ordre croissant:");
for(i=0; i < 0; i++){
printf("\n Nombre %d:', (i+1));
printf("%d", t[i]);
}
return 0;
}
Les fonctions
Comme dans tous les langages, le C permet également de décomposer un grand problème en plusieurs tâches ou modules. Ces modules peuvent être:
La fonction
Une fonction permet de calculer une seule valeur. L'utilisation d'une fonction dans un programme peut être assimilée à celle d'une variable car la fonction a toujours un type de retour: celui de la valeur calculée.
Les procédures
Une procédure par contre peut renvoyer plusieurs valeurs, aucune valeur ou un message d'erreur. La procédure n'a donc pas de type particulier. En C on ne parlera que de fonction mais la procédure sera simulée:
- Lorsqu'il faudra lire tout simplement une valeur ou afficher un résultat.
- Lorsqu'une fonction ne pourra fournir aucune valeur.
- Lorsqu'une fonction ne pourra fournir qu'une valeur non scalaire.
Exemple: Les listes chaînées, les vecteurs.
Exemple: float exemple(float a, int b, int c)
Lors de la déclaration d'une fonction, les noms des variables en paramètre ne sont importants.
Les paramètres utilisé lors de la définition d'une fonction sont les paramètres utilisés lors de l'appel d'une fonction sont les paramètres effectif ou réels.
L'instruction return permet de mentionner la valeur de retour. Ainsi on peut avoir le code suivant:
float exemple(float x, int b, int c)
{
return(x*x+b*x+c);
}
L'instruction return peut apparaitre à plusieurs reprises au sein d'une même fonction.
Exemple d'utilisation d'une fonction
#include< stdio.h >
#include< conio.h >
main()
{
float exemple(float, int, int);
{
float x=1,5;
float y,z;
int n=3, p=5; q=10;
y = exemple(x,n,p);
printf("Valeur de y: %f\n", y);
z = exemple(x+0,5, q, n-1);
printf("éaleur de: %\n", z);
return 0;
}
float exemple(float x, int b, int c)
{
float val;
val = x*+b*x+c;
return val;
}
}
Déclaration
type élément nom(liste des arguments)
Exemple
floatabsolu_som(float a, float b)
{
float s;
s = a+b;
if(s>0) return(s);
else
return(-s);
}
Cas d'une fonction n'ayant pas de valeur de retour ou sans argument
Fonction sans valeur de retour:
Exemple: void sans_valeur(int n);
Une telle fonction ne doit en principe contenir aucune instruction return.
Fonction sans argument:
Exemple: float merci(void);
En général en C, on peut définir une fonction avant ou après la fonction main(). Dans le cas où la fonction est définie avant la fonction main(), on n'est plus obligé de la déclarer dans la fonction main() parce que la valeur est une valeur globale.
Transmission des paramètres
En C, les arguments sont transmis par valeur.
Exemple
Ecrire un programme en C qui permet de permuter les valeurs de deux variables.
#include< stdio.h >
main()
{
void echange(int, int),
int a=1, b=20;
printf("Avant: %d %d", a,b);
echange(a,b);
printf("Après: %d %d", a,b);
retrurn 0;
}
void echange(inta, intb)
{
int c, b, a;
printf("Avant échange: %d %d", a,b);
c=a;
a=b;
b=c;
printf("Après échange: %d %d", a,b);
}
L'exécution de ce programme produit le résultat suivant:
avant: 10 20
avant échange: 10 20
après échange: 20 10
après: 10 20
On constate que lors de l'appel "échange reçoit des valeurs mais en revenant au programme principal aucune modification n'a été effectuée sur les valeurs transmises. Cela est dû à la transmission par valeur qui ne fait qu'une simple copie des valeurs utilisées.
Ce problème de permutation de valeur doit être résolu en utilisant la transmission par adresse.
En C, la transmission par adresse peut être simulée en utilisant un pointeur. Ceci permet de travailler sur le contenu de l'adresse.
#include
main()
{
void echange(int *ad1, int *ad2);
int a=10, b=20;
printf("avant: %d %d", a,b);
echange(&a, &b);
printf("après %d %d", a,b);
return 0;
}
void echange(int *ad1, int *ad2)
{
int c;
printf("avant échange: %d %d", *ad1, *ad2);
c=*ad1;
*ad1=*ad2;
*ad2=c;
printf("après échange %d %d", *ad1, *ad2);
}
Les structures
Une structure nous permet de désigner sous un seul nom un ensemble de valeurs pouvant être de type différent. Les éléments d'une structure sont appelés des champs. L'accès à chaque élément de la structure se fera par son nom au sein de la structure.
Déclaration
struct nom {
type1 champ1;
type2 champ2;
. .
. .
type n champ n;
}
Exemple 1
struct enreg {
int numero;
int qte;
float prix;
}
structenreg art;
Exemple 2
struct enreg {
int numero;
int qte;
float prix;
} art;
Utilisation d'une structure
En C, on peut manipuler une structure de deux manières:
- En travaillant individuellement sur chacun de ces champs.
- En travaillant de manière globale sur l'ensemble de la structure.
Utilisation des champs d'une structure
Chaque champ d'une structure peut être manipulé comme n'importe quelle variable du type correspondant. La désignation d'un champ se note en faisant suivre le nom de la variable structure de l'opérateur "." suivi du nom du champ tel qu'il a été défini dans la structure.
Exemple
struct op {
int a;
float b;
} ;
struct op x;
x.a=2;
printf("%e", x.b);
scanf("%e", &x.b);
x.a++;
Utilisation globale d'une structure
Il est possible d'affecter à une structure le contenu d'une autre structure définie à partir du même modèle.
Exemple:
struct op x,y; x=y
Il est possible d'initialiser une structure lors de sa déclaration.
Exemple:
struct op A={10, 12.5};
Le typedef
Le typedef permet de simplifier la déclaration d'un type c'est-à-dire définir les synonymes ou renommer les types.
Exemple d'utilisation du typedef
typedef int entier
entier x,y;
typedef int*ptr
ptr *p1, *p2;
Exemple
typedef struct enreg {
int numero;
int qte;
float prix;
} S_enreg;
Les structures et les objets composés
Structure comportant des tableaux
struct persoone {
char nom[20];
char prenom[20];
int age;
} ;
Tableau comportant des structures
struct point {
char nom;
int X;
int Y;
} ;
struct point courbe[50];
int i;
Exercices
Exercice 1
Un point est caractérisé par son nom, les coordonnées X, Y.
Ecrire un programme en C qui utilise la déclaration du type point pour créer un vecteur de 10 points. Ce programme:
- doit lire un vecteur de 10 points
- doit ajouter un point à la fin du vecteur
- doit supprimer un point donné de vecteur
- doit afficher tous les points du vecteur.
Exercice 2
Chaque produit est caractérisé par son code, son libellé, le prix unitaire, la quantité en stocke.
- Donnez une déclaration
- D'n produit
- D'un vecteur de produit
- Ecrire un programme en C
- qui permet de lire un vecteur de 10 produits
- qui affiche la liste des produits dont le prix unitaire est supérieur à 1000
- qui affiche le libellé du produit qui a la plus grande quantité.
- qui permet d'afficher la liste de tous les produits dans l'ordre alphabétique des libellés
Transmission d'une structure en paramètre (argument)
Transmission de la valeur d'une structure
Aucun problème particulier ne s'oppose, il s'agit tout simplement d'appliquer ce que nous connaissons déjà.
Exemple:
#include< stdio.h >
struct enreg {
int a;
float b;
};
main()
{
struct enreg x;
void fct(struct enreg)
x.a=1; x.b=12.5;
printf("Après appel de fct: %d, %e", x.a, x.b);
fct(x);
printf("Après apel de fct: %d, %e", x.a, x.b);
return 0;
}
void fct(struct enreg S) {
S.a=0;
S.b=1;
printf("Dans fct: %d, %e", S.a, S.b);
{
Les résultats affichés sont:
avant appel de fct: 1, 12.5
dans fct: 0, 1
après appel de fct: 1, 12.5
Naturellement les valeurs de x sont recopiées localement dans la fonction fct lors de sont appel. Les modifications de S au sein de fct n'ont aucune incidence sur les valeurs de x.
Transmission de l'adresse d'une structure
L'appel de fct devient fct(&x), cela signifie que l'en-tête devient void fct(struct enreg *S).
Ici le problème se pose lors de l'accès à chaque champ de la structure S.
L'opérateur "." ne convient plus, deux solutions s'offrent:
- On peut utiliser la notation (*S).a et (*S).b pour désigner chaque champ de la structure d'adresse S
- On peut faire appel à un nouvel opérateur noté →, lequel permet d'accéder aux différents champs d'une structure à partir de son adresse de début.
On aura:
S→a = (*S).a
S→b = (*S).b
Notre programme devient alors:
#include< stdio.h >
struct enreg {
int a;
float b;
} ;
main()
{
struct enrteg x;
void fct(struct enreg);
x.a=1;
x.b=12.5;
printf("Avant appel de fct: %d, %e", x.a, x.b);
fct(&x);
printf("Après appel de fct: %d, %e", x.a, x.b);
return 0;
}
void fct (struct enreg *S) {
S → a=0;
S → b=1;
printf("\n Dans fct, %d %e", S→a, S→b);
}