Cours complet de langage C
MASTER PROFESSIONEL LASERS, MATERIAUX, MILIEUX BIOLOGIQUES
COURS D'INFORMATIQUE: LANGAGE C
NOTES DE COURS
Christine ANDRAUD 2007/08
PLAN DU COURS:
I. Introduction
II. Notions de bases
III. Types de base, opérateurs, expressions
IV. Lecture et écriture de données
V. La structure alternative
VI. La structure répétitive
VII. Les tableaux
VIII. Les chaînes de caractères
IX. Les pointeurs
X. Les fonctions
XI. Les fichiers séquentiels
XII. Les "plus"
Chapitre I – Introduction
Le langage C a connu une croissance en popularité énorme ces dernières années.
On trouve ses sources en 1972, dans les laboratoires Bell, afin de développer une version portable du système d'exploitation unix. C'est un langage de programmation structuré, mais très "près" de la machine.
Publication en 1978 de "The C programming language" par Kernighan et Ritchie: définition classique du C.
Le développement de compilateurs C par d'autres maisons ont rendu nécessaire la définition d'un standard précis: le standard ANSI-C.
1983: Développement par AT&T du C++
1988: Seconde édition du livre "The C programming language" 1990: Standard ANSI-C++
Le succès du C est dû aux faits que:
- C'est un langage universel: C n'est pas orienté vers un domaine d'applications spécifique (au contraire du FORTRAN: applications scientifiques, COBOL: applications commerciales). - C'est un langage compact: C est basé sur un noyau de fonctions et d'opérateurs limités, permettant la formulation d'expressions simples et efficaces.
- Il est près de la machine: comme il a été développé initialement pour programmer le système UNIX, il offre des opérateurs très proches de ceux du langage machine et des fonctions qui permettent un accès simple et direct aux fonctions internes de l'ordinateur (par exemple la mémoire).
- Il est rapide puisqu'il est près de la machine.
- Il est portable: en respectant le standard ANSI-C il est possible d'utiliser le même programme sur tout autre système d'exploitation en possession d'un compilateur C. C est devenu aujourd'hui le langage de programmation des micro-ordinateurs.
- Il est extensible: C ne se compose pas seulement des fonctions standard, le langage est animé par des bibliothèques de fonctions privées ou livrées par de nombreuses maisons de développement.
Désavantages:
- La possibilité d'expressions compactes entraîne le risque de se retrouver avec des programmes incompréhensibles (pour les autres, mais aussi pour nous-même), d'où la nécessité d'inclure des commentaires dans les programmes.
- C est langage proche de la machine, il est donc dangereux. Bien qu'il soit un langage de programmation structuré, il ne nous oblige pas à adopter un style de programmation (comme, par exemple le PASCAL). Le programmateur a donc beaucoup de libertés, mais aussi des responsabilités: il doit veiller à adopter un style de programmation propre, solide et compréhensible.
Chapitre II – Notions de base
1) Bibliothèques de fonctions
La pratique du C exige l'utilisation de bibliothèques de fonctions. Ces bibliothèques sont disponibles sous forme précompilées (.lib). Afin de pouvoir les utiliser, il faut inclure des fichiers en-tête (.h) dans nos programmes. Ces fichiers contiennent les prototypes des fonctions prédéfinies dans les bibliothèques et créent un lien entre les fonctions précompilées et nos programmes.
Pour inclure les fichiers en-tête:
#include <fichier.h>
Pour le compilateur que nous utiliserons, différents types de fichiers seront identifiés par leurs extensions:
.c: fichier source
.obj: fichier compilé
.exe: fichier exécutable
.lib: bibliothèque de fonctions précompilées
.h: bibliothèque en-tête
2) Composantes d'un programme en C
- La fonction main
Elle constitue le programme principal:
main()
{
déclaration des variables instructions
}
- Les fonctions
Type_du_resultat Nom_fonction (Type_param Nom_param,…)
{
déclaration des variables locales instructions
}
- Les identificateurs
Les noms des fonctions et des variables en C sont composés d'une suite de lettres et de chiffres:
- le premier caractère doit être une lettre
- L'ensemble des symboles utilisables est: {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, …., x, y, z, A, B, C, …., X, Y, Z, _}
- Le C distingue les minuscules et les majuscules
- La longueur des identificateurs n'est pas limitée, mais le C distingue des 31 premiers caractères
Remarque:
Il est déconseillé d'utiliser le symbole "_" comme premier caractère pour un identificateur, car il est souvent employé pour définir les variables globales de l'environnement C.
Exercice 1
- Les commentaires
Un commentaire commence toujours par les deux symboles /* et se termine par les deux symboles*/. Il est interdit d'utiliser des commentaires imbriqués.
Exemple:
/* ceci est un commentaire correct */
/* ceci est /* évidemment */ incorrect */
- Les variables
Type_variable Nom_variable
3) Premier programme en C
Le classique "bonjour" (affiche bonjour à l'écran). Pour le faire, il faut:
- Inclure les bibliothèques
- Inclure le main main() {
déclaration des variables: aucune instruction: écrire "bonjour" }
La fonction prédéfinie qui permet d'écrire à l'écran est printf, elle est contenue dans le fichier en-tête stdio.h; sa syntaxe est: printf("ce que l'on veut écrire");
Voici donc notre premier programme:
#include <stdio.h> main()
{
printf("bonjour\n"); /*toute instruction se termine par un point virgule*/ }
Remarque: les séquences d'échappement
La suite de symboles \n à la fin de la chaîne de caractère est la notation C signifiant le passage à la ligne (n comme new ligne). Il existe en C plusieurs couples de symboles qui contrôlent l'affichage ou l'impression du texte. Les séquences d'échappement sont toujours précédées par le caractère d'échappement "\".
\t tabulation
\n nouvelle ligne
\b batch (curseur arrière)
\r return (retour au début de ligne, sans saut de ligne)
\a attention (signal acoustique)
Si l'on veut écrire le symbole " ou \: \" et \\
Chapitre III – Types de base, opérateurs, expressions
On trouvera dans un programme des variables et des constantes, il faut fixer leurs types. Pour produire de nouvelles valeurs, les variables et les constantes peuvent être combinées à l'aide d'opérateurs dans des expressions.
1) Les types de base
En mathématiques, on distingue divers ensembles de nombres (entiers naturels, entiers relatifs, réels, complexes,…). L'ordre de grandeur des nombres est illimité, ils peuvent être exprimés sans perte de précision. Un ordinateur utilise le système binaire pour sauvegarder et calculer les nombres, il existe pour un ordinateur deux grands systèmes de nombres: les entiers et les rationnels.
- Les entiers
Définition | Description | Valeur min | Valeur max | Nombre d'octets |
char | caractère | -128 | 127 | 1 |
short | entier court | -32768 | 32767 | 2 |
int | entier standard | -32768 | 32767 | 2 |
long | Entier long | -2147483648 | 2147483647 | 4 |
Si l'on ajoute le préfixe unsigned (non signé), les domaines sont déplacés ainsi:
Définition | Valeur min | Valeur max |
unsigned char | 255 | |
unsigned short | 65535 | |
unsigned int | 65535 | |
unsigned long | 4294967295 |
Les valeurs des limites des différents types sont indiquées dans le fichier limits.h.
- Les rationnels
Définition | Précision | Mantisse* | Valeur min | Valeur max | Nb d'octets |
float | simple | 6 | 3,4.10-38 | 3,4.10+38 | 4 |
double | double | 15 | 1,7.10-308 | 1,7.10+308 | 8 |
long double | avancée | 19 | 3,4.10-4932 | 1,1.10+4932 | 10 |
* La mantisse est le nombre de chiffres significatifs après la virgule.
Exemple: types float, avec mantisse de 6
(11,00001.104 4 4 2 4 8 +4 8504 3 ) "1.108
1,00001.108 "1.108 =1000 M
(11,00001.104 4 4 2 4 8 "4 1.104 38 ) + 850
1000+850=1850 ?
- Les variables booléennes
Il n'existe pas de type spécifique pour les variables booléennes, tous les types de variables numériques peuvent être utilisés pour exprimer des opérations logiques:
La variable logique FAUX correspond à la valeur numérique 0. La variable logique VRAI correspond toute valeur différente de 0.
- Déclaration de variables Syntaxe:
type nom;
On peut déclarer plusieurs variables d'un même type: Exemple:
int a, b, c;
On peut initialiser une variable lors de sa déclaration:
Exemple:
float pi = 3.14;
2) Les opérateurs standards
- L'affectation (=)
Nom_variable=expression;
Affectation avec des valeurs constantes:
Pi = 3.1416;
Lettre = 'L';
Affectation avec des valeurs variables:
a=b;
Affectation avec des expressions: voir la suite des opérateurs
- Les opérateurs arithmétiques
+ addition
- soustraction
* multiplication
/ division
% modulo (reste de la division entière) (par exemple, 5%2=1)
- Les opérateurs logiques
&& ET
|| OU
! NON
Les résultats des opérations logiques sont de type int: la valeur 0 correspond à la valeur booléenne FAUX, la valeur 1 correspond à la valeur booléenne VRAI.
- Les opérateurs de comparaison
== EGALITE != INEGALITE
< INFERIEUR <= INFERIEUR OU EGAL
> SUPERIEUR >= SUPERIEUR OU EGAL
Les résultats des opérations de comparaison sont de type int: la valeur 0 correspond à la valeur booléenne FAUX, la valeur 1 correspond à la valeur booléenne VRAI
Les opérateurs logiques considèrent toute valeur différente de 0 comme VRAI, toute valeur nulle comme FAUX.
Exemple :
32&&2.3 ? 1
!65,43 ? 0
0||!(32>12) ? 1
Les expressions sont constituées de variable ou constantes combinées entre elles par des opérateurs.
Exemple :
aire = pi*R*R; moyenne = (A+B)/2
plus_grand = (x>y) (la variable plus_grand est une variable logique qui vaut 1 (resp. 0) si x est supérieur (resp. inférieur) à y)
- L'opérateur d'affectation i = i + 2;
En C, on peut écrire: i+ = 2;
Pour la plupart des expressions de la forme: expr1 = (expr1) Opérateur (expr2); Il existe une formulation équivalente:expr1 Opérateur = expr2; Cette formulation (i+ = 2) suit la logique humaine: on ajoute 2 à i.
L'opérateur d'affectation aide le compilateur à générer un code plus efficace car expr1 n'est évalué qu'une fois.
- L'opérateur d'incrémentation et de décrémentation
i = i + 1 s'écrit: i++ ou ++i i = i - 1 s'écrit: i-- ou --i
Les opérateurs ++ et -- sont utilisés:
- pour incrémenter ou décrémenter une variable, par exemple dans une boucle (dans ce cas, pas de différence entre la notation préfixe (++i,--i) et la notation postfixe (i++,i--).
- pour incrémenter ou décrémenter une variable et en même temps affecter sa valeur à une autre variable. Dans ce cas, on choisit entre la notation préfixe et postfixe:
X = i++; passe d'abord la valeur de i à X, puis incrémente i (le ++ est après i, on l'incrémente après)
X = i--; passe d'abord la valeur de i à X, puis décrémente i
X = ++i; incrémente d'abord i puis passe la valeur de i incrémentée à X (le ++ est avant i, on l'incrémente avant)
X = --i; décrémente d'abord i puis passe la valeur de i décrémentée à X
Exemple 1:
N = 5; | ||
X = N++;Exemple 2: N = 5; | Résultat: X = 5 et N = 6 | |
X = ++N; | Résultat: X = 6 et N = 6 |
- Priorités des opérateurs
L'ordre d'évaluation des différentes parties d'une expression correspond à celle que nous connaissons en maths.
Exemple:
A = 3;
B = 4;
X = 2 * A + 3 * B;
6 + 12
18
Ensuite, on affecte 18 à X
Comme en maths, si l'on veut forcer l'ordinateur à commencer par un opérateur de priorité plus faible, on entoure le terme par des parenthèses.
Exemple:
A = 3;
B = 4;
X = 2 *(A + 3) * B;
2 * 6
12 * 4
48
Classes de priorités: | |||
Priorité 1 (la plus élevée) | ( ) | ||
Priorité 2 | !, ++, -- | ||
Priorité 3 | *, /, % | ||
Priorité 4 | +, - | ||
Priorité 5 | <, <=, >, >= | ||
Priorité 6 | ==, != | ||
Priorité 7 | && | ||
Priorité 8 | || | ||
Priorité 9 (la plus basse) | =, +=, -=, *=, /=, %= |
Dans chaque classe, les opérateurs ont la même priorité. Si on a une suite d'opérateurs binaires de la même classe, l'évaluation se fait en passant de la gauche vers la droite.
N: pour les opérateurs unaires (!, ++, --) et pour les opérateurs d'affectation, l'évaluation se fait de la droite vers la gauche.
Exemple 1 :
10 + 20 + 30 – 40 sera évaluée comme suit:
10 + 20 ) ? 30
30 + 30 ? 60
60 – 40 ? 20
Exemple 2 : pour A = 3 et B = 4 A* = B+ = 5 sera évaluée comme suit:
B+ = 5? B = 9
A* = 9? A = 27
Exemple 3 : pour A = 1 et B = 4
!- - A == ++!B sera évaluée comme suit:
- - A? 0 !B ? 0
!0 ? 1 ++0 ? 1
1 == 1 ? 1
Exemple 4 : X* = Y + 1 équivalent à X = X*(Y + 1)
Exercice 2
3) Conversions de type
- Calculs et affectations
Si un opérateur a des opérandes de types différents, les valeurs des opérandes sont converties automatiquement dans un type commun. Cette conversion implicite s'effectue en général des types "plus petits" vers les types "plus larges", afin de ne pas perdre en précision.
Lors d'une affectation, la donnée à droite du signe "=" est convertie dans le type à gauche du signe "=". Dans ce cas, il peut y avoir perte de précision. Exemple : int a =8; float x = 10.5; double y; y = a*x;
La valeur de a est convertie en float pour pouvoir être multipliée à x. Le résultat de la multiplication est de type float, mais avant d'être affectée à y, il est converti en double, il peut donc y avoir une perte de précision.
- Appels de fonctions
Lors de l'appel d'une fonction, les paramètres sont automatiquement convertis dans les types déclarés dans la définition de la fonction.
Exemple : int A =8, Res; Res = pow(A, 2);
Appel de pow(): 2 et A sont convertis en doubles, le résultat est double, il est converti en int pour être affecté à Res.
- Règles de conversion lors d'une opération avec: - 2 entiers:
D'abord les types char et short sont convertis en int, ensuite, l'ordinateur choisit le plus large des deux types selon l'échelle: int, unsigned int, long, unsigned long.
- Un entier et un rationnel:
Le type entier est converti dans le type du rationnel - 2 rationnels:
L'ordinateur choisit le plus large des deux types selon l'échelle: float, double, long double.
- Affectation:
Lors d'une affectation, le résultat est toujours converti dans le type de la destination. N: si le type est plus faible, il peut y avoir perte de précision. Erreur classique: int A = 4, B = 3; float C;
C = A / B;
A / B est entier (A et B sont int), donc A / B = 1, converti en float, C = 1!
Exercice 3
- Conversion de type forcée
Il est possible de convertir explicitement une valeur en un type quelconque:
(type) expression
Exemple:
int A = 4, B = 3; float C;
C = (float)A / B;
Le contenu de A reste inchangé, seule la valeur utilisée dans le calcul est convertie.
Chapitre IV – Lire et écrire des données
La bibliothèque standard <stdio.h> contient un ensemble de fonctions qui assurent la communication de la machine avec le monde extérieur.
Les fonctions les plus importantes sont:
Pour la lecture: Pour l'écriture:
printf(): écriture formatée de données scanf(): lecture formatée de données putchar(): écriture d'un caractère getchar (): lecture d'un caractère
1) Ecriture formatée de données
printf(): cette fonction est utilisée pour transférer du texte, des valeurs de variables ou des résultats d'expression vers le fichier de sortie standard stdout (par défaut l'écran).
Syntaxe:
printf("format", expr_1, expr_2)
? ? ?
Format de Expressions ou variables dont les valeurs sont à représenter représentation
"format" est une chaîne de caractère qui peut contenir:
- du texte
- des séquences d'échappement
- des spécificateurs de format (un spécificateur pour chaque expression)
Les spécificateurs de format: ils commencent toujours par le symbole %
Symbole | Impression comme | Type |
%d ou %i | Entier relatif | int |
%u | Entier naturel (non signé) | int |
%o | Entier exprimé en octal | int |
%x | Entier exprimé en hexadécimal | int |
%f | Rationnel en notation décimale | float |
%e | Rationnel en notation scientifique | float |
%g | Rationnel en notation décimale/scientifique | float |
%lf | Rationnel en notation décimale | double |
%lg | Rationnel en notation décimale/scientifique | double |
%le | Rationnel en notation scientifique | double |
%c | Caractère | char |
%s | Chaîne de caractère | char* |
Arguments de type long:
Entiers: on utilise: %ld, %li, %lu, %lo, %lx
Rationnels: pour les "long double", on utilise: %Lf, %Lg ou %Le
Remarque:
%e, %le, %Le: représentation avec 1 chiffre (non nul) avant le point décimal
%g, %lg, %Lg: choisit la représentation la plus "économique" (la plus courte) entre la notation décimale et la notation scientifique
- Largeur minimale des entiers
Il est possible d'indiquer la largeur minimale de la valeur à afficher. Dans le champ ainsi réservé, les nombres sont justifiés à droite:
Affichage: | |
printf("%4d", 1); | 1 ??? |
printf("%4d", 123); | 123 ? |
printf("%4d", 1234); | 1234 |
- Largeur minimale et précision pour les rationnels La précision par défaut est de 6 décimales.
printf("%f", 12.34); La syntaxe est: "" où: n est la largeur du champ m est le nombre de décimales | Affichage:12.340000 | |
Affichage: | ||
printf("%10.3f", 100.123); | 100.123 ??? | |
printf("%10.f", 100.123); | 100.12 |
????
2) Lecture formatée de données
scanf(): fonction symétrique de printf().
Syntaxe:
scanf("format", adr_var_1, adr_var_2)
? ? ?
Format de Adresses des variables auxquelles les données sont attribuées lecture des données (adresse d'une variable= nom de la variable précédé de &)
- La fonction scanf reçoit ses données à partir du fichier standard stdin (le clavier)
- La chaîne de format détermine comment les données reçues doivent être interprétées
- Les données reçues correctement sont mémorisées aux adresses indiquées par adr_var_1, adr_var_2, …
Les spécificateurs de format pour scanf sont:
Symbole | Lecture d'un(e) | Type |
%d ou %i | Entier relatif | int |
%u | Entier naturel (non signé) | int |
%o | Entier exprimé en octal | int |
%b | Entier exprimé en hexadécimal | int |
%f | Rationnel en notation décimale | float |
%e | Rationnel en notation scientifique | float |
%g | Rationnel en notation décimale/scientifique | float |
%lf | Rationnel en notation décimale | double |
%lg | Rationnel en notation décimale/scientifique | double |
%le | Rationnel en notation scientifique | double |
%c | Caractère | char |
%s | Chaîne de caractère | char* |
Arguments de type long:
Entiers: on utilise: %ld, %li, %lu, %lo, %lx
Rationnels: pour les "long double", on utilise: %Lf, %Lg ou %Le
scanf("%d", &nombre); On entre au clavier 33, nombre = 33
Indication de la largeur maximale: il est possible de la spécifier, mais ceci est peu recommandé, si les chiffres d'une variable passent au-delà du champ spécifié, ils seront assimilés à la prochaine variable qui sera lue!
On peut traiter plusieurs variables avec une seule instruction scanf: Lors de l'entrée des données, une suite de signes d'espacement (espace, tab, interligne) est évaluée comme un seul espace (idem si dans la chaîne de format on tape les symboles \n, \t, \r =1 seul espace). Exemple
int jour, mois, annee;
scanf("%d %d %d",&jour, &mois, &annee);
Les entrées suivantes sont correctes et équivalentes
24?11?19738
24*11*19738
248
118
19738
Si la chaîne de format contient aussi d'autres caractères que des signes d'espacement, alors ces symboles doivent être introduits exactement dans l'ordre indiqué. Exemple
int jour, mois, annee;
scanf("%d/%d/%d",&jour, &mois, &annee); Entrées acceptées Entrées rejetées
24/11/19738 24 11 19738
? ?
24/011/19738 24 /11/ 19738
? ?
scanf retourne comme résultat le nombre d'arguments correctement reçus et affectés. Exemple
int jour, mois, annee; recu=scanf("%d %d %d",&j, &m, &a); si l'entrée est 24 11 19738 , alors recu = 3.
? ?
3) Ecriture d'un caractère
Syntaxe:
putchar (caractere)
putchar transfère le caractère "caractere" vers le fichier de sortie standard stdout (l'écran), les arguments de putchar sont des caractères (type char, i.e. des nombres entiers entre 0 et 255).
Exemples: Affichage putchar('x'); x putchar('?'); ?
putchar(65); | A (65 est le code ASCII de A) |
putchar('\n'); | retour à la ligne |
putchar(A); | valeur de la variable A si c'est un char |
4) Lecture d'un caractère
Syntaxe:
getchar ()
Les valeurs retournées par getchar() sont des caractères. Le type du résultat de getchar est int.
Exemple: int C;
C=getchar();
getchar lit les données de la zone tampon stdin (clavier) et fournit les données seulement après confirmation par "Enter".
Il existe dans la bibliothèque <conio.h> une fonction getch() qui fournit immédiatement le prochain caractère entré au clavier (sans validation).
Chapitre V – Structure alternative
Les structures de contrôle définissent l'ordre dans lequel les instructions sont effectuées. Particularité des instructions de contrôle en C: les "conditions" peuvent être des expressions qui fournissent un résultat numérique.
On rappelle que: valeur 0 -> FAUX et toute valeur ? 0 -> VRAI
1)if-else Structure: | |
if(condition) | si condition est vrai (?0) |
{ | on exécute |
bloc d'instructions 1;} | bloc d'instructions 1 |
else | sinon |
{ | on exécute |
bloc d'instructions 2;} | bloc d'instructions 2 |
Remarques :
- S'il n'y a qu'une seule instruction, les accolades sont inutiles.
- "condition" peut être:
- une variable de type numérique
- une expression fournissant un résultat numérique
- La partie else est facultative
- On peut imbriquer plusieurs if-else
Exemple 1 :
if(a>b) | si a est plus grand que b |
max=a; | on affecte à max la valeur de a |
else | sinon |
max=b; Exemple 2 : | on affecte à max la valeur de b |
if(A-B) | si A-B est vrai, si A-B est différent de 0, si A est différent de B |
printf("A est différent de B\n"); else
printf("A est différent de B\n");
Remarque sur les exemples: Comme une seule instruction suit le if et le else, les accolades ne sont pas obligatoires.
2) if-else imbriqués
Il est possible d'imbriquer plusieurs structures if-else, cela permet de prendre des décisions entre plusieurs alternatives. Mais, afin de gagner en lisibilité, on conseille d'adopter une écriture tabulée.
Exemple : if(N>0) if(A>B) MAX=A; else MAX=B;
Que fait ce programme? A quel if est rattaché le else?
La première remarque est qu’un else est toujours rattaché au dernier if qui ne possède pas de else, dans cet exemple, le else est donc rattaché au if (A>B). La seconde est qu'en adoptant une écriture lisible, c’est-à-dire tabulée, on verra tout de suite et beaucoup plus facilement l'imbrication des if-else.
if(N>0) if(A>B)
MAX=A;
else
MAX=B;
Comment faire pour forcer le programme à la seconde interprétation ? (Le else est rattaché au premier if) if(N>0)
{
if(A>B)
MAX=A;
}
else MAX=B;
Exemple 1 :
int A,B ; printf("Entrer deux nombres entiers:\n") ; scanf("%d %d",&A,&B); if(A>B) printf("%d est plus grand que %d\n",A,B); else if(A<B) printf("%d est plus petit que %d\n",A,B); else printf("%d est égal à %d\n",A,B); | Affichage: Entrer deux nombres entiers: 3 12 3 est plus petit que 12 |
Exemple 2 :
printf("Continuer (O)ui / (N)on?\n") ; getchar(C); if(C=='O') {… } else if(C=='N') printf("Au revoir…\n"); else printf("Erreur d'entrée\n"); | Affichage: Continuer (O)ui / (N)on? N Au revoir… |
Exercices 4 et 5
3) L'opérateur conditionnel
structure: result = expr1 ? expr2 : expr3 ; si expr1 est vraie (?0) result=expr2, sinon, result=expr3
Exemple :
MAX=(A>B)?A :B ;
Chapitre VI – Structure répétitive
Il existe trois sortes de structures répétitives: while, do while et for.
1) while = tant que
Structure:
while(condition) tant que condition est vraie (?0)
{ on exécute
bloc d'instructions ; bloc d'instructions
}
Remarques:
- S'il n'y a qu'une seule instruction, les accolades sont inutiles.
- Le bloc d’instructions est exécuté 0 ou plusieurs fois.
Exemple 1:
int i =0; while(i<4) { printf("%d\n",i); i++ ; } | Affichage: 1 2 3 |
Exemple 2:
int i =0; while(i<4) printf("%d\n",i++); | Affichage: 1 2 3 |
Exemple 3:
int i =0; while(i<4) printf("%d\n",++i); | Affichage: 1 2 3 4 |
Exemple 4:
int i =4; while(i) printf("%d\n",i--); | Affichage: 4 3 2 1 |
Remarque : Le bloc d’instructions peut être vide (notation : {} ou ;), si l’on attend un évènement sans avoir besoin de traitement de données.
Exemple :
while(getch()==’ ‘); Ignore tous les espaces entrés au clavier et sera utilisé jusqu’à l’entrée d’un caractère significatif.
2) Do-while = faire - tant que
Il est semblable au while, mais : while évalue la condition avant d’exécuter, alors que dowhile exécute une fois avant d’évaluer la condition.
Structure:
do on exécute
{
bloc d'instructions ; bloc d'instructions
}
while(condition) ; tant que condition est vrai (?0)
Remarques :
- S'il n'y a qu'une seule instruction, les accolades sont inutiles.
- Le bloc d’instructions est exécuté au moins une fois, et aussi longtemps que condition fournit une valeur vraie (différente de 0).
En pratique, do-while est moins courant que while, mais fournit parfois une solution plus élégante.
Exemple 1 :
int n ; do { printf("Entrer un nombre entre 1 et 10:\n") ; scanf("%d",&n); } while(n<1||n>10) ; | Affichage: Entrer un nombre entre 1 et 10: 12 Entrer un nombre entre 1 et 10: Entrer un nombre entre 1 et 10: 3 |
Exemple 2 :
int n, div ; printf("Entrer le nombre à diviser:\n") ; scanf("%d",&n); do { printf("Entrer le diviseur:\n") ; scanf("%d",&div); } while(!div) ; printf("%d/%d = %f\n",n,div,(float)n/div) ; | Affichage: Entrer le nombre à diviser: 2 Entrer le diviseur: Entrer le diviseur: 3 2/3= 0.666666 |
3) for
structure:
for(expr1;expr2;expr3)
{
bloc d'instructions ;
}
expr1 est évaluée une fois avant le passage dans la boucle, elle est utilisée pour initialiser les données de la boucle. expr2 est évaluée à chaque passage de la boucle, elle est utilisée pour savoir si la boucle est répétée ou non (c'est une condition de répétition, et non d'arrêt). expr3 est évaluée à la fin de chaque passage de la boucle, elle est utilisée pour réinitialiser les données de la boucle.
Equivalence entre une boucle for et une boucle while:
for(expr1;expr2;expr3) expr1;
{ while(expr2)
bloc d'instructions ; {
} bloc d'instructions ;
expr3;
}
Le plus souvent, for est utilisé comme boucle de comptage:
for(init;cond_repetition;compteur)
{
bloc d'instructions ;
}
Exemple 1 :
int i; for(i=1;i<=4;i++) { printf("Le carré de %d est %d\n",i,i*i); } | Affichage: Le carré de 1 est 1 Le carré de 2 est 4 Le carré de 3 est 9 Le carré de 4 est 16 |
Exemple 2 :
int i; for(i=4;i>0;i--) { printf("Le carré de %d est %d\n",i,i*i); } | Affichage: Le carré de 4 est 16 Le carré de 3 est 9 Le carré de 2 est 4 Le carré de 1 est 1 |
Remarque :
Les parties expr1 et expr2 peuvent contenir plusieurs initialisations ou réinitialisations, séparées par des virgules.
Exemple :
int n,tot;
for(tot=0, n=1;n<101;n++) tot+=n;
printf("La somme des nombres de 1 à 100 est égale à: %d\n",tot);
4) Choix de la structure répétitive
On choisit la structure qui reflète le mieux l'idée du programme que l'on veut réaliser, en respectant les directives suivantes:
- Si le bloc d'instructions ne doit pas être exécuté si la condition est fausse -> while ou for
- Si le bloc d'instructions doit être exécuté au moins une fois -> do-while
- Si le nombre d'exécution du bloc d'instructions dépend de une ou plusieurs variables qui sont modifiées à la fin de chaque répétition -> for
- Si le bloc d'instructions doit être exécuté aussi longtemps qu'une condition extérieure est vraie (par exemple aussi longtemps qu'il y a des données dans un fichier d'entrées) ->
while
Le choix entre for et while est souvent une question de préférence et d’habitude.
- for permet de réunir les instructions qui influencent le nombre de répétitions au début de la structure.
- while a l’avantage de correspondre plus exactement aux structures d’autres langages et à la logique humaine.
- for a le désavantage de favoriser la programmation de structures surchargées et par la suite illisibles.
- while a le désavantage de mener parfois à de longues structures dans lesquelles il faut chercher pour trouver les instructions influençant la condition de répétition.
Chapitre VII – Les tableaux
Les tableaux sont des variables structurées. Dans une première approche, leur traitement en C ne diffère pas de celui dans d’autres langages. On verra plus loin (Ch. IX – Les pointeurs) que le C permet un accès encore plus direct et rapide aux données d’un tableau.
1) Tableaux à 1 dimension
Un tableau unidimensionnel est une variable structurée formée d’un nombre entier N de variables simples du même type (composantes du tableau). Lors de la déclaration de variable, N doit être défini.
a)Déclaration et mémorisation
• Déclaration :
type Nom_du_tableau[dimension] ;
Remarque: Nom_du_tableau est un identificateur
Exemples: int A[25]; tableau de 25 entiers de type int float B[10]; tableau de 10 décimaux de type float char C[30]; tableau de 30 caractères (entiers de type char)
• Mémorisation :
En C, le nom d’un tableau est le représentant de l’adresse du premier élément du tableau. Les adresses des autres composantes sont calculées automatiquement, relativement à cette adresse.
Si un tableau possède N composantes et si le type déclaré des composantes requiert M octets, la mémoire réservée pour ce tableau est de N×M octets.
Exemple: int A[6];
Un entier int requiert 2 octets, il y a 6 éléments, la mémoire réservée pour le tableau A est donc de 2×6=12 octets.
b)Initialisation et réservation automatique
- Il est possible d’initialiser un tableau lors de sa déclaration, en indiquant la liste des valeurs Exemple: int A[5]={100,200,300,400,500};
Le premier élément du tableau, A[0] contiendra la valeur 100. le second élément, A[1], contiendra la valeur 200, le dernier élément, A[4], contiendra la valeur 500.
- Lors de sa déclaration, on peut initialiser le tableau, si le nombre de valeur dans la liste est inférieur à la dimension du tableau, les composantes restantes sont mises à 0.
Exemple:
int A[4]={10,20};
Le premier élément du tableau, A[0] contiendra la valeur 10. le second élément, A[1], contiendra la valeur 20, le troisième, A[2] sera mis par défaut à 0, de même pour le dernier élément, A[3].
- Si la dimension n’est pas indiquée, l’ordinateur réserve automatiquement le nombre d’octets nécessaires.
Exemple:
int A[]={10,20,30};
Les trois éléments du tableau sont initialisés à 10, 20 et 30, la taille du tableau sera automatiquement mise à 3.
Remarque: Il faut bien évidemment que le nombre de valeurs dans la liste soit inférieur ou égal à la dimension du tableau !
c) Accès aux composantes
Lorsque l’on déclare un tableau, (par exemple int A[5] ;), on définit un tableau avec 5 composantes, auxquelles on peut accéder par :
A[0], A[1], A[2], A[3], A[4]
Remarque: Le premier élément du tableau est l’élément 0, donc, pour un tableau de dimension N, le premier sera l’élément 0, le dernier l’élément N-1.
d) Affichage et affectation
La structure for se prête particulièrement bien au travail avec les tableaux.
• Affichage du contenu d’un tableau Exemple:
int A[5]={1,2,3,4,5} ; int i ; for(i=0 ;i<5 ;i++) printf("%3d",A[i]); | Affichage: 1 2 3 4 5 |
Remarque : Avant de pouvoir afficher les composantes d'un tableau, il faut bien sûr leur affecter des valeurs!
• Affectation Exemple:
int A[5]={1,2,3,4,5} ;
int i ;
for(i=0 ;i<5 ;i++)
scanf("%d",&A[i]);
Remarque: De la même manière que pour une variable "normale", on indique l'adresse (&A[i])
Exercice 6
2) Tableaux à 2 dimensions
En C, un tableau A à deux dimensions est à interpréter comme un tableau (à une dimension) de dimension L dont chaque composante est un tableau (unidimensionnel) de dimension C.
On appelle L le nombre de lignes, C le nombre de colon