I. Un premier exemple¶
#include <stdio.h>
/* Mon premier programme en C,
un classique de l'informatique ! */
int main() {
printf("Hello world !\n"); // affichage
return 0;
}
Hello world !
Quelques remarques sur la syntaxe¶
#include <stdio.h>
: directive du préprocesseur (???) qui permet d' inclure le fichier d'en-têtestdio.h
(???)- permet d' utiliser des fonctions définies par ailleurs (un peu comme
import
en Python)
- permet d' utiliser des fonctions définies par ailleurs (un peu comme
/* ... */
: désigne un commentaire, éventuellement sur plusieurs lignes
//
: commentaire jusqu'à la fin de la ligne
int
: type entier
int main() { ... }
: définition de fonction- le corps de la fonction est écrit entre accolades
- la fonction
main
ne prend aucun paramètre et la valeur de retour est de type entier
NB : pas de def
, pas de :
printf(...)
: appel de fonctionprintf
permet l'affichage sur la sortie standard (cf cours Linux)- la fonction
printf
utilisable ici car elle est déclarée (??) dans le fichierstdio.h
;
: à mettre après chaque une instruction
"Hello world !\n"
: chaîne de caractères.\n
: retour à la ligne, caractère spécial qui compte pour un seul caractère
return 0;
: valeur de retour de la fonction
Indentation ?¶
En C, l'indentation n'est pas indispensable, ni signifiante.
On utilise l'indentation pour améliorer la lisibilté du code.
#include <stdio.h>
int main() { printf("Hello world !"); return 0; }
Hello world !
Les puristes du C écrivent plutôt de la façon suivante (mais le code occupe davantage de lignes) :
#include <stdio.h>
int main()
{
printf("Hello world !");
return 0;
}
Hello world !
Quelques remarques sur l'exécution du code¶
En C, la fonction main
(fonction principale) est la fonction appelée au début de l'exécution du programme.
La fonction main
doit obligatoirement être présente dans le code à exécuter.
#include <stdio.h>
int toto() {
printf("Hello world !");
return 0;
}
/tmp/tmplrvt60rz.c: In function ‘main’: /tmp/tmplrvt60rz.c:5:1: warning: ISO C forbids nested functions [-Wpedantic] 5 | int toto() { | ^~~ At top level: /tmp/tmplrvt60rz.c:5:5: warning: ‘toto’ defined but not used [-Wunused-function] 5 | int toto() { | ^~~~
Quelques messages d'erreur¶
Comme en Python, certaines erreurs sont détectées avant l'exécution, d'autres pendant l'exécution
#include <stdio.h>
int main() {
printf("Hello world !\n")
return 0;
}
/tmp/tmpeolijl2q.c: In function ‘main’: /tmp/tmpeolijl2q.c:3:30: error: expected ‘;’ before ‘return’ 3 | printf("Hello world !\n") | ^ | ; 4 | return 0; | ~~~~~~ [C kernel] GCC exited with code 1, the executable will not be executed
#include <stdio.h>
int main() {
printf("Hello world !\n");
return 0/0;
}
/tmp/tmp1mpn9jf5.c: In function ‘main’: /tmp/tmp1mpn9jf5.c:4:13: warning: division by zero [-Wdiv-by-zero] 4 | return 0/0; | ^
Hello world !
[C kernel] Executable exited with code -8
II. Les principales caractéristiques du C¶
Historique¶
Le langage C a été conçu au début des années 1970, conjointement à la réalisation du système d'exploitation (OS) Unix (cf Diapo Systèmes d'exploitation).
Ken Thompson (concepteur d'Unix)
Dennis Ritchie (concepteur du langage C, co-concepteur d'Unix)
Brian Kernighan (premier auteur d'un livre sur C avec D.Ritchie : le K&R)
Historique¶
A l'époque, on programmait directement en langage machine. Mais les ordinateurs devenaient de plus en plus complexes ...
Principe d'un système d'exploitation (OS) : pouvoir s'abstraire du fonctionnement de la machine
Comment coder l'OS ?
Pas en langage machine ...
Début des langages de programmation ... (Algol, Fortran)
invention d'un nouveau langage : le C ! (à partir d'un langage appelé B)
Historique¶
C était considéré comme un langage de "haut niveau", c'est-à-dire loin du fonctionnement de la machine.
Largement adopté (un peu comme Python aujourd'hui), le langage C est normalisé dans les années 1980.
NB : la normalisation permet d'éviter les incompatibilités entre différentes implémentations
L'inertie des normes¶
Du fait de la normalisation, le langage C n'a que peu évolué depuis et présente plusieurs défauts importants qui persisteront probablement.
- pas de mécanisme d'exceptions (cf OCaml, en MPI)
- pas de structure de données génériques
- pas de système de nommage
- pas de gestion automatique de la mémoire
Historique¶
Aujourd'hui C est considéré comme un langage de "bas niveau", mais reste très utilisé, pour des raisons de performances.
Le langage C a grandement influencé les langages plus récents (C++, C#, Java, Python ...) dont les implémentations sont souvent, pour partie, écrites en C.
Exécution : compilé vs interprété¶
En Python, le code est lu puis exécuté par un programme (l'interpréteur Python : python
).
On dit que le langage Python est un langage interprété.
Exécution : compilé vs interprété¶
En C, le code n'est pas exécuté tout de suite...
Il est d'abord traduit en fichier exécutable (code machine) par un programme qui est appelé compilateur.
Le programme est ensuite exécuté directement par la machine (sans passer par un programme intermédiaire).
On dit que le langage C est un langage compilé.
Exécution : compilé vs interprété¶
langage interprété : la machine exécute un programme (l'interpréteur ou l'interprète) qui exécute mon programme
langage compilé : une fois compilé (par le compilateur, la machine exécute directement mon programme
NB : quelques compilateurs pour le langage C : gcc
, cc
, clang
NB : quelques interpréteurs pour le langage Python : python3
(cpython
), jython
, ...
La commande pour exécuter ce programme est python3 test.py
. Le programme appelé est python3
, et ce programme interprète le fichier test.py
.
NB : time
mesure le temps d'exécution d'une commande (ici 22s)
Compilation : le programme gcc
transforme le fichier test.c
en fichier exécutable test
.
Exécution : on mesure le temps d'exécution du programme test
(ici 1,13s)
- Sur cet exemple, le programme écrit en C est presque 20 fois plus rapide que le programme écrit en Pyton
Paradigme impératif¶
Un paradigme est une façon de se représenter les choses de manière cohérente.
La "philosophie" dans laquelle le langage C a été conçu en fait un langage dit impératif structuré : on donne des instructions/ordres à la machine qui les exécute séquentiellement.
A ce titre, on retrouve en C les notions de :
- variable et affectation
- instruction et séquence d'instructions
- structures conditionnelles : branchement
if
/else
,switch
(H.P.)
- structures itératives : boucles
for
etwhile
NB : on retrouve ces aspects "impératifs" dans la plupart des autres langages.
III. Le langage C, en bref¶
NB : en MP2I/MPI, on se restreint à un sous-ensemble du C (comme en OCaml)
III.1 Structure générale du langage¶
La plupart des langages de programmation sont construits de manière similaire ...
Le coeur du langage.¶
Tout ce qui est utilisable directement par le programmeur :
les types de base,
la syntaxe générale pour écrire une fonction, une boucle ...
- cf la suite ...
Les bibiliothèques fournies avec le langage.¶
(library en anglais) ou modules
Ce sont des ensembles cohérents de fonctions / constantes / types.
Elles sont utilisables quasi-directement par le programmeur.
En Python : les modules math
, random
... accessibles avec import
En C : la bibliothèque standard du C (lib c) accessibles avec #include
En OCaml : la Stdlib
Les bibliothèques externes¶
ou modules externes, ou packages (ensemble de modules), non fournis avec le langage.
Ecrits par d'autres programmeurs, il faut les installer en plus pour pouvoir les utiliser.
En Python : les modules numpy
, matplotlib
...
En C : ... (opengl
, sdl
...)
En OCaml : ... (graphics
, str
...)
Et pour gérer les nombreuses bibliothèques externes ...¶
Pour la plupart des langages, la communauté des programmeurs s'organise pour faciliter l'utilisation de ces modules externes :
En Python : PyPI : Python Package Index
En Ocaml : Opam : Ocaml Package Manager
En C : rien ...
La bibliothèque standard C :¶
on accède aux fonctions de la librairie standard en mettant en début du fichier une ou plusieurs directives #include <...>
stdio.h
: pour accéder aux fonctions entrées / sortiesmath.h
: pour accéder aux fonctions mathématiquesassert.h
: pour accéder à la fonctionassert
...
NB : .h
comme header (en-tête) car un tel fichier ne contient pas la définition complète de ces foctions, mais uniquement leur signature (en-tête) (cf la suite)
// Exemple fonction de math.h
#include <stdio.h>
#include <math.h>
int main(){
int a = pow(2,10); // fonction puissance de math.h
printf("%d", a);
return 0;
}
1024
//Exemple fonction assert
#include <stdio.h>
#include <assert.h>
int main(){
printf("avant\n"); // affiché
assert(1+1 == 3); // fonction assert de assert.h
printf("après\n"); // non affiché
return 0;
}
tmp0vnublly.out: /tmp/tmprio328my.c:6: main: Assertion `1+1 == 3' failed.
avant
[C kernel] Executable exited with code -6
III.2 Les types de base :¶
NB : types de base ou types scalaires
- entiers "signés" (négatifs ou positifs) :
int
...
- entiers "non-signés" (positifs uniquement) :
unsigned int
...
réels ou flottants :
float
...- ex :
-1.3
$\quad$4.
$\quad$-3.317e8
- ex :
caractères :
char
- ex :
'a'
$\quad$'A'
$\quad$'\n'
- ex :
- booléens : ... (en fait, codés avec ces entiers)
III.3 Affichage avec printf
:¶
La fonction printf
permet d'afficher des informations sur la sortie standard (stdout
, cf cours Linux).
utilisation : printf(chaine_de_formatage, arg1, arg2, ...)
printf
est une fonction à nombre variable d'arguments.la chaîne de formatage est le permier argument passé à la fonction. C'est une chaîne de caractères contenant des
%x
qui seront remplacés par les valeurs des autres arguments (dans l'ordre).
Attention, il faut tenir compte des types :
%d
: affichage décimal d'un entier%f
: affichage décimal d'un flottant%c
: affichage d'un caractère unique%s
: affichage d'une chaîne de caractères- ...
NB : et ne pas oublier #include <stdio.h>
// Exemple printf et chaine de formatage
#include <stdio.h>
int main(){
int i = -3;
unsigned int n = 12;
float x = 2.15e-3;
char lettre = 'a';
printf("i=%d n=%d x=%f lettre=%c", i, n, x, lettre);
return 0;
}
i=-3 n=12 x=0.002150 lettre=a
//Attention, aucun contrôle sur les types
#include <stdio.h>
int main(){
int i = 99;
printf("i=%d i=%c i=%f", i, i, i);
return 0;
}
i=99 i=c i=0.000000
III.4 Opérations sur les types de base¶
Opérateurs numériques :¶
* + - /
: sur les types numériques
NB : pas d'opérateur puissance (cf. fonction pow
)
NB : conversions automatiques si les opérandes sont de types différents
Attention : la division sur les entiers est la division entière. En effet, les opérandes ne sont pas de types différents ...
%
: sur les types entiers
// Illustration des conversions automatiques
#include <stdio.h>
int main(){
printf("%d %f %f", 7/2, 7/2.0, 3*2.1);
return 0;
}
3 3.500000 6.300000
III.3.1 Les variables en Python :¶
En Python, le type est associé à la valeur :
les types ne sont pas écrits dans le code
une variable peut changer de type au cours de l'exécution
la vérification de la cohérence des types se fait pendant l'exécution (typage dynamique)
## Code Python : variables et types ##
v = 4
print(type(v)) # v de type 'int'
v = [2]
print(type(v)) # v de type 'list'
print(2+[]) # erreur de type à l'exécution
<class 'int'> <class 'list'>
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-2-795a53079250> in <module> 6 print(type(v)) # v de type 'list' 7 ----> 8 print(2+[]) # erreur de type à l'exécution TypeError: unsupported operand type(s) for +: 'int' and 'list'
III.3.2 Les variables en C:¶
En C, le type est porté par l'identifiant:
le type d'une variable est systématiquement écrit dans le code
ce type correspond à une taille mémoire réservée pour cette variable
une variable ne peut pas changer de type
la vérification de la cohérence des types se fait avant l'exécution (typage statique), mais n'empêche pas forcément l'exécution (typage faible)
Définition / initialisation de variable¶
// Exemple de définition / initialisation de variables
#include <stdio.h>
int main(){
int x,y; // définition de deux variables entières non initialisées
int z=0,t; // définition de deux autres variables, la première étant initialisée
x = 1; y =2; t=3;
printf("%d %d %d %d", x, y, z, t);
return 0;
}
1 2 0 3
Taille mémoire associée à un type¶
Pour connaître la taille d'un type T
, on utilise sizeof(T)
qui donne le nombre d'octets occupés par une variable de type T
.
// taille mémoire associée à un type
#include <stdio.h>
int main(){
printf("%d %d %d", sizeof(int), sizeof(char), sizeof(float));
return 0;
}
4 1 4
- 4 octets pour un
int
- 1 octet pour un
char
- 4 octets pour un
float
Détection d'erreur de type avant l'exécution¶
En C, c'est le compilateur qui réalise la vérification de types
certaines erreurs sont fatales : le code ne s'exécutera pas
certaines erreurs ne le sont pas : un avertissement est affiché (warning), mais le code s'exécute tout de même, et souvent plante ...
// Erreur de type ... non fatale, malheureusement ...
#include <stdio.h>
int main(){
printf("avant\n");
printf(3); // printf ne s'applique pas à un entier ...
printf("après\n");
return 0;
}
/tmp/tmpfjd03vpv.c: In function ‘main’: /tmp/tmpfjd03vpv.c:5:12: warning: passing argument 1 of ‘printf_wrap’ makes pointer from integer without a cast [-Wint-conversion] 5 | printf(3); // printf ne s'applique pas à un entier ... | ^ | | | int In file included from /tmp/tmpfjd03vpv.c:2: /home/julien/jupyter-c-kernel/jupyter_c_kernel/resources/stdio_wrap.h:78:29: note: expected ‘const char *’ but argument is of type ‘int’ 78 | int printf_wrap(const char *format, ...) { | ~~~~~~~~~~~~^~~~~~
avant
[C kernel] Executable exited with code -11
Typage (faible) en C¶
Le langage C est très (trop) souple avec les types.
Il réalise des conversions automatiques si les types ne sont pas respectés.
Ces conversions sont parfois pertinentes et voulues par un programmeur C expérimenté. Mais elles sont souvent conséquences d'erreurs de programmation et à l'origine de nombreux bugs ...
Ici, l'entier 3 est converti automatiquement en chaîne de caractères (qui n'est pas la chaine "3") ... et ce code grossièrement faux s'exécute (et plante !)
Ils doivent donc :
- être lus
- considérés avec attention
- et, pour la plupart d'entre eux, le code doit être corrigé
... sous peine d'avoir un code qui plante sans raison apparente (ce qui est fort désagréable ...)
Variable locale / variable globale¶
Une variable définie en dehors des fonctions est dite variable globale
Une variable définie à l'intérieur d'une fonction est dite variable locale
NB : comme en Python
// Erreur portée de variable
#include <stdio.h>
int main(){
{
int i = 0;
printf("%d\n", i);
}
printf("%d\n", i); // i hors de portée ... erreur détecté avant l'exécution
return 0;
}
/tmp/tmpa3yk2r6w.c: In function ‘main’: /tmp/tmpa3yk2r6w.c:10:20: error: ‘i’ undeclared (first use in this function) 10 | printf("%d\n", i); // i hors de portée ... erreur détecté avant l'exécution | ^ /tmp/tmpa3yk2r6w.c:10:20: note: each undeclared identifier is reported only once for each function it appears in [C kernel] GCC exited with code 1, the executable will not be executed
// Exemple portée de variable
#include <stdio.h>
int main(){
int i = 1;
{
int i = 0; // nouveau i dans une nouvelle portée
printf("%d\n", i);
}
printf("%d\n", i); // i dans la portée actuelle
return 0;
}
0 1
// Exemple portée de variable
#include <stdio.h>
int main(){
int i = 1;
{
printf("%d\n", i); // on peut accéder aux variables des portées englobantes
}
printf("%d\n", i);
return 0;
}
1 1
// Erreur portée de variable
#include <stdio.h>
int main(){
int i = 1;
int i = 0; // interdiction de définir deux variables de même nom dans la même portée
return 0;
}
/tmp/tmpfkw64gyi.c: In function ‘main’: /tmp/tmpfkw64gyi.c:7:9: error: redefinition of ‘i’ 7 | int i = 0; | ^ /tmp/tmpfkw64gyi.c:6:9: note: previous definition of ‘i’ was here 6 | int i = 1; | ^ /tmp/tmpfkw64gyi.c:7:9: warning: unused variable ‘i’ [-Wunused-variable] 7 | int i = 0; | ^ [C kernel] GCC exited with code 1, the executable will not be executed
les variables "constantes"¶
NB: oxymore (!)
On peut les précéder du mot-clé const
:
on protège la variable d'un malencontreuse erreur de programmation
peut permettre au compilateur de générer un code machine un peu plus efficace
// Erreur tentative de modification d'un variable const
#include <stdio.h>
int main(){
const int x = 0;
x = 3; // tentative de modification
printf("%d",x);
return 0;
}
/tmp/tmppgfsh5yo.c: In function ‘main’: /tmp/tmppgfsh5yo.c:7:7: error: assignment of read-only variable ‘x’ 7 | x = 3; // tentative de modification | ^ [C kernel] GCC exited with code 1, the executable will not be executed
III.4 Les fonctions :¶
Pour une fonction, les types des paramètres et le type de la valeur de retour doivent être indiqués.
(Même principe que pour les variables : en C, on indique les types)
NB :
- fonctions récursives possibles
- possibilité de ne rien renvoyer : type
void
- possibilité de déclarer une fonction (donner sa signature) et de la définir par la suite
- pas de paramètres nommés, pas de paramètres avec valeur par défaut ...
- il est possible de passer en paramètre une fonction à une fonction (HP)
- il est possible de définir des fonctions avec un nombre variable de paramètres (HP)
// Exemple de fonction
#include <stdio.h>
int somme(int a, int b){
return a+b;
}
int main(){
int s = somme(2,3);
int t = somme(3, somme(3,3));
printf("s=%d t=%d\n",s,t);
return 0;
}
s=5 t=9
// Exemple de fonction sans valeur de retour
#include <stdio.h>
void welcome(){
printf("Bienvenue dans le jeu du taquin\n\n");
printf("Les règles du jeu sont les suivates:\n");
printf("...");
}
int main(){
welcome();
return 0;
}
Bienvenue dans le jeu du taquin Les règles du jeu sont les suivates: ...
// Exemple de séparation déclaration / définition
#include <stdio.h>
/* Déclaration de toutes les fonctions utiles */
int somme(int a, int b); // déclaration de la fonction somme
/* Fonction principale */
int main(){
int s = somme(2,3);
printf("s=%d\n",s);
return 0;
}
/* Implémentation des fonctions utiles */
int somme(int a, int b){ // définition de la fonction somme
return a+b;
}
s=5
// Exemple : if imbriqués
#include <stdio.h> // VERSION UN PEU LOURDE
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0) {
return 1;
} else {
if (delta > 0.0) {
return 2;
} else {
return 0;
}
}
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
NB : si 1 seule instruction entre accolades, on peut se passer des accolades
#include <stdio.h> // VERSION DECONSEILLEE
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0)
return 1;
else
if (delta > 0.0) {
return 2;
} else {
return 0;
}
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
En poursuivant :
#include <stdio.h> // VERSION DECONSEILLEE
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0)
return 1;
else if (delta > 0.0)
return 2;
else
return 0;
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
Et même :
#include <stdio.h>
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0) return 1;
else if (delta > 0.0) return 2;
else return 0;
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
ou encore (trop peu lisible) :
#include <stdio.h> // VERSION A EVITER
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0) return 1; else if (delta > 0.0) return 2; else return 0;
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
Version conseillée pour les cas disjoints :¶
on préserve les accolades (programmation défensive)
#include <stdio.h> // VERSION CONSEILLEE
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0) {
return 1;
} else if (delta > 0.0) {
return 2;
} else {
return 0;
}
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
sans accolades : un bug fréquent ...¶
#include <stdio.h> // CODE FAUX
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0)
printf("TEST");
return 1;
else if (delta > 0.0)
return 2;
else
return 0;
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
/tmp/tmp4ax2giop.c: In function ‘nbracines’: /tmp/tmp4ax2giop.c:8:5: error: ‘else’ without a previous ‘if’ 8 | else if (delta > 0.0) | ^~~~ [C kernel] GCC exited with code 1, the executable will not be executed
L'indentation n'est pas signifiante en C !
D'où l'intérêt de mettre systématiquement des accolades
Version possible, en cas d'instruction unique :¶
- on peut la mettre sur la même ligne que la condition
#include <stdio.h> // VERSION POSSIBLE
int nbracines(float a, float b, float c){
float delta = b*b-4*a*c;
if (delta == 0.0) return 1;
else if (delta > 0.0) return 2;
else return 0;
}
int main(){
printf("%d\n",nbracines(1,2,1)); // X^2 + 2 X + 1 : 1 racine réelle
printf("%d\n",nbracines(1,1,1)); // X^2 + X + 1 : 0 racine réelle
printf("%d\n",nbracines(1,-3,2)); // x^2 - 3X + 2 : 2 racines réelles
return 0;
}
1 0 2
III.5.2 boucle while¶
while (cond) {
...
}
NB :
break
(sortie anticipée),continue
(passage au tour suivant)parenthèses obligatoires
si 1 seule instruction entre accolades, on peut se passer des accolades
// Exemple while
#include <stdio.h>
int main(){
int i = 9;
while (i>0) {
printf("%d",i);
i -= 1;
}
return 0;
}
987654321
III.5.3 boucle for¶
for (init; expr; incr) {
...
}
c'est une while
déguisée !
init;
while (expr) {
...
incr;
}
NB : for (init; expr; incr)
possibilté de définir une variable dans
init
break
(sortie anticipée),continue
(passage au tour suivant)si 1 seule instruction entre accolades, on peut se passer des accolades
- mêmes remarques que pour
if
etwhile
; mieux vaut laisser les accolades
- mêmes remarques que pour
// Exemple for
#include <stdio.h>
int main(){
for (int i=0; i<10; i++) {
printf("%d",i);
}
return 0;
}
0123456789
// Exemple for
#include <stdio.h>
int main(){
for (int i=9; i>0; i--) printf("%d",i);
return 0;
}
987654321
// Exemple for imbriquées
#include <stdio.h>
int main(){
for (int i=0; i<3; i++) {
for (int j=0; j<2; j++){
printf("(i=%d j=%d) ",i,j);
}
}
return 0;
}
(i=0 j=0) (i=0 j=1) (i=1 j=0) (i=1 j=1) (i=2 j=0) (i=2 j=1)