C20H Integrale Creative Commons by SaV2 AOUT2013
C20H Integrale Creative Commons by SaV2 AOUT2013
C20H Integrale Creative Commons by SaV2 AOUT2013
Le C en 20 heures
Creative Commons-BY-SA
(http ://creativecommons.org/licenses/by-sa/2.0/fr)
II
L’ouvrage que vous tenez dans les mains ou que vous consultez sur votre
écran a pour objectif de vous faire découvrir, par la pratique, la program-
mation en langage C.
Il a été testé par de nombreux étudiants qui n’avaient aucune connais-
sance préalable de ce langage. En 20 à 30 heures de travail, ils sont tous
parvenus au terme de leur apprentissage. Si vous ne connaissez encore
rien à la programmation et que vous désirez apprendre, vous serez donc
probablement très intéressé(e) par le contenu de cet ouvrage : il est très
facile d’accès et destiné aux grands débutants.
Il existe une multitude de façons de programmer un ordinateur, qui
dépendent du matériel dont vous disposez, du système d’exploitation
que vous utilisez et du langage de programmation que vous choisirez.
Nous avons fait le choix d’un système d’exploitation libre : G NU/Linux
et du langage C, très répandu, largement enseigné, et finalement assez
simple dans ses constructions. Néanmoins, même si vous n’utilisez pas
G NU/Linux, vous pouvez sans risque vous lancer dans la lecture de cet
V
VI
Daniel Schang, qui l’a utilisé et enrichi d’une quatrième rangée de briques
dans un cadre plus académique à l’ESEO d’Angers.
Il ne nous sera pas possible de dire combien de versions de ce cours
ont existé mais là n’est pas le plus important, ce qui compte c’est que
vous ayez maintenant ce livre entre les mains et ceci grâce à l’association
Framasoft.
CHAPITRE 1
Premiers pas
1. Système d’exploitation et C
1
2 Le C en 20 heures
Nous allons dans cette section tenter de définir une manipulation pour
lancer un éditeur 1 . Il existe une multitude d’éditeurs de texte qui permet-
tent de saisir des programmes : Emacs (que j’utilise en ce moment même),
Kate, Bluefish, Gedit. . .
Souvent, les éditeurs sont accessibles quelque part dans un menu. En ce
qui nous concerne, nous allons lancer l’éditeur de texte depuis la ligne
de commande du shell. Pour cela, nous allons exécuter un terminal. Selon
la distribution que vous utilisez le terminal n’est pas forcément rangé au
même endroit. Voici quelques pistes qui pourront vous aider :
– sous Gnome, faites Applications / Accessoires / Terminal ;
– sous Xfce (et avec une Debian), faites clic droit, puis Terminal ;
– dans un autre environnement, recherchez quelque chose qui pourrait
s’appeler Terminal, Console ou Xterm.
Dans cette nouvelle fenêtre qui ressemble à celle de la figure 1.1, exé-
cutez l’éditeur Scite en tapant la commande scite puis en validant.
3. Exemple de programme
Voici un premier programme. Il est fonctionnel, même s’il n’est pas nor-
malisé 1 . Il affiche le mot Bonjour à l’écran. À l’aide de votre éditeur de
texte (dans la fenêtre Scite donc), tapez le texte qui se trouve à l’intérieur
du cadre suivant :
main () {
puts ("Bonjour");
getchar ();
}
./programme1
4. Normalisation du programme
Jusqu’à présent, nous avons fait un peu « dans le sale ». Nous nous en
rendrons compte en demandant au compilateur d’être plus bavard. Lancez
la commande :
int main () {
puts ("Bonjour");
getchar (); /* Permet d’attendre la frappe d’une touche */
return 0;
}
À l’instar de l’étudiant qui recherche dans des livres, nous pouvons dire
que le « .h » représente l’index du livre et le « .c » le contenu du chapitre
concerné.
7. Compléments
int main () {
puts ("Bonjour");
getchar (); /* Permet d’attendre la frappe d’une touche */
return 0;
}
8. Squelette de programme
int main () {
/* Déclaration des variables (cf. chapitres suivants...) */
/* Corps du programme */
getchar(); /* Facultatif mais permet
d’attendre l’appui d’une touche */
9. Blocs
Retrait de la tabulation
Tout le texte est maintenant frappé à cette hauteur.
10. Commentaires
sont indispensables dans tout bon programme. Ils peuvent être placés à
n’importe quel endroit. Ils commencent par /* et se terminent par */ :
/* Commentaire */
Comme nous l’avons déjà mentionné, vous trouverez aussi parfois des
commentaires C++ :
#include <stdio.h>
int main () {
/* Affiche premier message */
puts ("Salut toi, appuie sur une touche s’il te plaît");
return 0;
}
13. À retenir
int main () {
puts ("Bonjour");
getchar (); /* Permet d’attendre la frappe d’une touche */
return 0;
}
Variables (partie 1)
1. Objectif
13
14 Le C en 20 heures
#include <stdio.h>
int main () {
return 0;
}
3. Notion de variable
Comme son nom l’indique, une variable est quelque chose qui varie.
C’est vrai mais ce n’est pas suffisant. Une variable peut être considérée
comme une boîte dans laquelle on met des données. Il est possible de lire
le contenu de cette boîte ou d’écrire des données dans celle-ci.
La manière la plus immédiate de lire le contenu d’une variable est de
simplement mentionner son nom.
La façon la plus simple d’affecter une valeur à une variable est l’opéra-
teur d’affectation =.
#include <stdio.h>
int main () {
int i; /* déclare un entier de nom i */
char c; /* déclare un caractère de nom c */
}
5. Application : exemples
int main () {
int i; /* i : variable de type entier */
int j; /* j : variable de type entier */
i=22; /* i vaut 22 */
j=i; /* on recopie la valeur de i dans j */
/* donc j vaut aussi 22 à présent */
return 0;
}
int main () {
char car; /* car: variable de type caractère */
char f; /* f: variable de type caractère */
car=’E’;
f=’e’;
printf("car=%c f=%c\n",car,f);
return 0;
}
car=E f=e
une correspondance entre les lettres (que nous autres, êtres humains,
comprenons) et leur codage par la machine. En résumé, chaque fois
que nous manipulerons la lettre A, pour l’ordinateur, il s’agira de la
valeur numérique 65. . .
7. Exercices
Dans les exercices qui suivent, vous devez utiliser ce que nous venons
de voir sur les variables, les caractères, et sur printf.
Une fois que vous avez votre propre solution, comparez avec celle qui
se trouve à la fin du chapitre. . .
Il est possible de réutiliser une variable autant de fois que l’on veut. La
précédente valeur étant alors effacée :
i = 3;
i = 5;
i = 7; Maintenant, i contient 7, les autres valeurs ont disparu.
car = ’E’ ;
car = ’G’ ;
car = ’h’ ; La variable car contient maintenant le caractère ’h’.
Variables (partie 1) 19
9. Caractères spéciaux
10. Exercices
int main () {
int i,a,b,c;
i=70;
a=82;
b=185;
c=30;
return 0;
}
Variables (partie 1) 21
int main () {
char a,b,c,d,e,f;
a=’c’;
b=’o’;
c=’u’;
d=’C’;
e=’O’;
f=’U’;
return 0;
}
int main () {
char car;
car=’’’; // erreur volontaire !!!
return 0;
}
int main () {
char car;
int i;
i = 1;
car = ’C’;
printf ("\n%c",car);
car = ’\’’;
printf ("\n%c",car);
22 Le C en 20 heures
car = ’e’;
printf ("\n%c",car);
car = ’s’;
printf ("\n%c",car);
car = ’t’;
printf ("\n%c",car);
return 0;
}
12. À retenir
int main () {
char caractere;
int entier;
caractere = ’c’;
entier = 1;
return 0;
}
CHAPITRE 3
Variables (partie 2)
1. Objectif
23
24 Le C en 20 heures
Pas à pas, nous allons maintenant réaliser notre petit programme de cal-
culatrice.
1. Par « saisir », nous voulons dire que l’ordinateur va attendre que l’utilisateur entre une
valeur au clavier puis qu’il appuie sur la touche entrée.
26 Le C en 20 heures
int i = 10 ;
int main () {
int a=0;
int b=0;
printf("Calculatrice :\n\n");
printf("Valeur de a : \n");
scanf("%d",&a);
printf("\n");
printf("Valeur de b : \n");
scanf("%d",&b);
getchar ();
return 0;
}
int main () {
printf("Calculatrice :\n\n");
printf("Valeur de a : \n");
getchar();
printf("Valeur de b : \n");
getchar();
int main () {
int a,b;
a=36;
b=54;
getchar();
return 0;
}
int main () {
int a,b;
int s;
a=0;
b=0;
printf("Calculatrice :\n\n");
printf("Valeur de a : ");
scanf("%d",&a);
printf("\n");
printf("Valeur de b : ");
scanf("%d",&b);
s=a+b;
printf("Valeur de a+b : %d\n",s);
getchar ();
return 0;
}
d = a-b;
printf("Valeur de a-b : %d\n", d);
m = a*b;
Variables (partie 2) 31
d = a/b;
printf("Valeur de a/b : %d\n", d);
getchar ();
...
8. À retenir
#include <stdio.h>
int main () {
float pi=3.14159;
int i=10;// déclaration + initialisation
int j;// déclaration seule (pas d’initialisation)
printf("\n i vaut:%d\n",i);
return 0;
}
Conditions
1. Objectif
33
34 Le C en 20 heures
Une fois que vous êtes satisfait(e) de votre solution, vous pourrez com-
parer avec la solution qui se trouve à la fin de ce chapitre.
Les conditions s’expriment avec des opérateurs logiques dont nous al-
lons expliquer tout de suite la signification et l’utilisation.
36 Le C en 20 heures
4. Opérateurs de comparaison
Signification Opérateur
Inférieur <
Supérieur >
Égal ==
Différent !=
Inférieur ou égal <=
Supérieur ou égal >=
int main () {
int valeur1;
int valeur2;
/* Saisie de valeur1 */
printf ("Entrez une 1ere valeur : ");
scanf ("%d",&valeur1);
/* Saisie de valeur2 */
printf ("Entrez 2e valeur : ");
scanf ("%d",&valeur2);
if (valeur1<valeur2)
printf("La plus grande valeur est: %d\n",valeur2);
else
printf("La plus grande valeur est: %d\n",valeur1);
return 0;
}
Conditions 37
5. Opérateurs logiques
Libellé Opérateur
Et (and) &&
Ou (or) ||
Non (not) !
6. Vrai ou faux
Ou Vrai Faux
Vrai Vrai Vrai
Faux Vrai Faux
+ 1 0
1 2 1
0 1 0
En logique pure, on écrira plus 1+1=1 du fait que toute valeur non nulle
est considérée comme Vrai.
Et Vrai Faux
Vrai Vrai Faux
Faux Faux Faux
* 1 0
1 1 0
0 0 0
1. L’analogie entre les opérateurs logiques d’une part et les opérations d’addition et de
multiplication d’autre part n’est pas parfaite. Elle permet néanmoins de se faire une idée plus
calculatoire du fonctionnement des opérateurs logiques.
Conditions 39
Par exemple :
int i1=1;
int i2=0;
printf("i1 || i2 = %d",i1||i2);
/* affichera 1 car : vrai||faux=vrai et vrai vaut 1 */
printf("i1 && i2 = %d",i1&&i2);
/* affichera 0 car : vrai&&faux=faux et faux vaut 0 */
printf("contraire(1)=%d",!(1));
/* affichera 0 car : !(vrai)=faux et faux vaut 0 */
7. Combinaison
8. Accolades
9. Exercices
int main () {
float h; /* valeur de l’hypoténuse */
float a; /* a,b les deux autres côtés */
float b;
/* Saisie de a */
printf ("Valeur du premier petit côté : ");
scanf ("%f",&a);
/* Saisie de b */
printf ("Valeur du second petit côté : ");
scanf ("%f",&b);
/* Affichage du résultat */
printf ("L’hypoténuse mesure : %.2f\n",h);
return 0;
}
int main () {
/* Variable pour stocker la valeur saisie */
int a = 0;
/* Saisie de a */
printf("Saisie de a : ");
scanf("%d",&a);
/* Strictement négative ? */
if (a < 0)
printf("la variable a est négative.\n");
else {
/* Strictement positive ? */
Conditions 43
if (a > 0)
printf("la variable a est positive\n");
/* Sinon a est nulle */
else
printf("la variable a est nulle\n");
}
getchar ();
return 0;
}
int main () {
/* Variable pour stocker la valeur saisie */
char car;
/* Saisie du caractère a */
printf("Saisie du caractère : ");
scanf("%c",&car);
getchar ();
return 0;
}
11. À retenir
if (a > 0)
printf ("Valeur positive");
else
printf ("Valeur négative");
Mise au point
1. Objectif
45
46 Le C en 20 heures
Par exemple :
si (nbre_saisi < 10)
alors écrire "plus petit"
getchar();
char car;
car = getchar();
Mise au point 47
int main () {
char car=’ ’;
int sortie=0;
do {
printf ("Appuyez sur S pour sortir !\n");
car = getchar ();
/* On le compare pour savoir si l’on peut →
,→ sortir: */
sortie = ((car == ’s’) || (car == ’S’));
}
while (sortie==0);
return 0;
}
5. Opérateur modulo
Par exemple :
int z;
z=10%2;
printf("10 modulo 2=%d\n",z);
z=10%3;
printf("10 modulo 3=%d\n",z);
. . . va nous afficher :
10 modulo 2=0
10 modulo 3=1
6. Nombres pseudo-aléatoires
#include <stdio.h>
#include <stdlib.h> // sert pour les fonctions →
,→ srand et rand
#include <time.h>
int main() {
int nb_alea=0;
int main() {
/* Pour notre information */
printf ("RAND_MAX : %ld\n", RAND_MAX);
return 0;
}
C’est plus !
...
Gagné !!!
int main () {
int nb_choisi = 33;
int nb_saisi = 0;
return 0;
}
int main () {
int valeur=0;
do {
printf ("Votre nombre : ");
scanf ("%d",&valeur);
52 Le C en 20 heures
}
while (valeur != 10);
return 0;
}
int main () {
int nb_hasard = 0;
int votre_nb = 0;
do {
printf("Votre nombre : ");
scanf("%d",&votre_nb);
printf ("Trouvé\n");
return 0;
}
CHAPITRE 6
53
54 Le C en 20 heures
1. Objectifs
2. Boucle While
char car = ’ ’;
while ((car != ’s’) && (car != ’S’)) {
car = getchar ();
}
4. Fonction toupper()
int main () {
char car;
char car_min;
car_min = ’a’;
car = toupper (car_min);
printf ("%c",car);
56 Le C en 20 heures
return 0;
}
Ce programme affichera : A
int i;
i=1;
i=i+1;
(ici 1) et lui ajoute 1. Le résultat est stocké dans la case mémoire associée
à i. Finalement, i vaudra 2.
Pour gagner du temps, le langage C nous permet de remplacer une ex-
pression comme : i=i+1 par l’expression suivante : i++ qui fera exacte-
ment la même chose.
int i;
8. Incrémentations, pré-incrémentations. . .
i++; ↔ i=i+1;
int main () {
int n=5;
int x;
x=n++;
printf ("x: %d n: %d\n",x,n);
return 0;
}
int main () {
int n=5;
int x=0;
x=++n;
printf ("x: %d n: %d\n",x,n);
return 0;
}
int main () {
char car = ’\0’;
printf("Tapez ’s’ ou ’S’ pour arrêter ...\n");
do {
car = getchar ();
}while ((car != ’s’) && (car != ’S’));
return 0;
}
int main () {
int nbre = 0;
printf("Tapez 10 pour arrêter ...\n");
do {
scanf ("%d", &nbre);
}while (nbre != 10);
return 0;
}
int main () {
int nbre = 0;
return 0;
}
ou bien :
#include <stdio.h>
int main () {
int nbre = 0;
return 0;
}
int main () {
char car = ’\0’;
while ((car != ’A’) && (car != ’E’) && (car != ’I’) &&
(car != ’O’) && (car != ’U’) && (car != ’Y’)){
int main () {
int nbre = 0;
int nb_nbre = 0;
do {
scanf("%d",&nbre);
nb_nbre ++;
}while (nb_nbre != 10);
return 0;
}
62 Le C en 20 heures
int main () {
char car = ’\0’;
int nbre = 0;
do {
car = getchar ();
nbre ++;
printf("j’ai lu (%c) nbre=%d\n",car,nbre);
}while (nbre != 10);
return 0;
}
int main () {
char car;
int nb_nbre = 10;
Et les Shadoks pompaient : je pompe donc je suis 63
car=toupper(car);
if (car==’A’ || car==’E’ || car==’I’ || car==’O’ || car==’U’) →
,→ {
nb_nbre--;
printf("Tapez encore %d voyelles pour arrêter...\n",nb_nbre);
}
}
while (nb_nbre != 0);
return 0;
}
int main () {
int nb_nbre = 10;
int nbre;
return 0;
}
64 Le C en 20 heures
10. À retenir
int main () {
int i=0;
while (i != 100) {
if (i%2==0) /* reste de la division de i par 2 */
printf("%d ",i);
/* pas de else ni de {} ici, c’est inutile...*/
i++;
}
return 0;
}
int main () {
int i=0;
while (i!=100) {
printf("%d ",i);
i+=2;
}
return 0;
}
Boucles
1. Objectifs
Afin d’effectuer un certain nombre de fois une tâche, nous utilisons l’in-
struction for de la façon suivante (avec i, une variable de type entier (int
par exemple)) :
65
66 Le C en 20 heures
i=i+pas;
}
Par exemple :
#include <stdio.h>
int main () {
int i;
for (i=0; i<15; i++){
printf("Je me répète pour i valant %d\n",i);
}
printf("L’instruction a été répétée... 15 fois\n" →
,→ );
return 0;
}
3. Syntaxe
par :
for (i=0; i<15; i++)
printf ("Je me répète pour i valant %d\n",i);
Par exemple :
#include <stdio.h>
int main () {
int i;
int j;
for (i=0; i<5; i++){
printf("\nJe suis dans la boucle i, i vaut %d\n" →
,→ ,i);
return 0;
}
68 Le C en 20 heures
*
**
***
****
*****
*
***
*****
*******
*********
***********
*************
***************
*****************
*******************
Boucles 69
Instructions :
– sur la ligne no 1, afficher 9 espaces puis 1 étoile ;
– sur la ligne no 2, afficher 8 espaces puis 3 étoiles ;
– sur la ligne no 3, afficher 7 espaces puis 5 étoiles ;
– sur la ligne no i, afficher 10-i espaces puis 2*i-1
étoiles.
Nous obtenons donc par exemple pour l’affichage des
étoiles sur la ligne i :
for (j=0; j<((2*i)-1); j++) {
printf ("*");
}
Affichage du tronc
@@@
@@@
@@@
6. Table Ascii
Les codes Ascii (c’est-à-dire les nombres qui représentent les caractères
en informatique) vont de 0 à 255.
Par exemple :
int i = 65;
printf("%3d : %c", i, i); // affichera 65 : A
int main () {
int i;
int j;
for (i=1; i<=5; i++){
for (j=1; j<=i; j++){
printf ("*");
}
printf ("\n");
}
return 0;
}
Boucles 71
int main () {
int i;
int j;
for (i=1; i<=5; i++){
for (j=1; j<=i; j++) // pas d’accolades nécessaires...
printf("*");
printf("\n");
}
return 0;
}
int main () {
int i;
int j;
printf("\n");
}
return 0;
}
int main () {
int i;
return 0;
}
int main () {
int i;
int j;
return 0;
}
Boucles 73
8. À retenir
i=1;
while (i<100) {
printf("i vaut:%d",i);
i=i+2;
}
CHAPITRE 8
Pointeurs et fonctions
1. Objectifs
75
76 Le C en 20 heures
2. Binaire, octets. . .
Binaire
Binaire Décimal
0 0
1 1
10 2
11 3
100 4
101 5
110 6
111 7
1000 8
1001 9
1010 10
... ...
11111111 255
Nous voyons dans cette table que le nombre 7 est donc représenté par
trois symboles « 1 » qui se suivent : 111.
Compter en base 2, 3, 10 ou 16
printf("i1=%d i2=%d",i1,i2);
Variables et mémoire
Une variable est une zone mémoire disponible pour y ranger des infor-
mations. Par exemple, dans le cas d’une variable car déclarée par char
car ;, la zone mémoire disponible sera de 1 octet (exactement une case
mémoire). En revanche, une variable de type int utilisera au moins 4
octets (la valeur exacte dépend du compilateur), c’est-à-dire 4 cases mé-
moires.
À présent, représentons-nous la mémoire comme une unique et longue
« rue » remplie de maisons. Chaque case mémoire est une maison. Chaque
maison porte un numéro, c’est ce qui permet de définir son adresse
postale. Cette adresse est unique pour chaque maison dans la rue. De
manière analogue, pour une case mémoire, on parlera d’adresse mémoire.
Par exemple, ce petit programme va afficher l’adresse mémoire d’une
variable de type caractère.
#include <stdio.h>
int main () {
char c=’A’;
printf ("c contient %c et est stocké à %p.\n",c,&c);
return 0;
}
Pointeurs
Pour manipuler les adresses mémoire des variables, on utilise des vari-
ables d’un type spécial : le type « pointeur ». Une variable de type pointeur
est déclarée ainsi :
type* variable;
int main () {
char car=’C’;
char * ptr_car; /* Variable de type pointeur */
return 0;
}
Exercice d’application
int main () {
char car=’C’;
char * ptr_car=NULL;
return 0;
}
car=’E’;
printf("\nAprès le caractère est : %c\n",car);/*on a modifié car →
,→ */
Pointeurs et fonctions 83
return 0;
}
Nous verrons par la suite que dans certains cas, on ne peut pas se passer
des pointeurs, notamment pour certaines manipulations au sein des fonc-
tions. . .
4. Fonctions
Une fonction est un petit bloc de programme qui à l’image d’une indus-
trie va créer, faire ou modifier quelque chose. Un bloc de programme est
mis sous la forme d’une fonction si celui-ci est utilisé plusieurs fois dans
un programme ou simplement pour une question de clarté. De la même
manière que nous avions défini la fonction main, une fonction se définit
de la façon suivante :
<type de sortie> <nom de la fonction> (<paramètres d’appels>) {
Déclaration des variables internes à la fonction
Corps de la fonction
Retour
}
Comme indiqué précédemment, il ne faut pas mettre les < et >, qui ne sont
là que pour faciliter la lecture.
Voici un exemple de fonction qui renvoie le maximum de deux nom-
bres :
int maximum (int valeur1, int valeur2) {
int max;
if (valeur1<valeur2)
max=valeur2;
else
max=valeur1;
return max;
}
05. if (valeur1<valeur2)
06. max=valeur2;
07. else
08. max=valeur1;
09. return max;
10. }
11.
12. int main () {
13. int i1,i2;
14. printf("entrez 1 valeur:");
15. scanf("%d",&i1);
16. printf("entrez 1 valeur:");
17. scanf("%d",&i2);
18. printf("max des 2 valeurs :%d\n",maximum(i1,i2));
19. return 0;
20. }
Type void
Le mot void signifie vide. Le type void est notamment utilisé comme
type de sortie pour les fonctions qui ne retournent aucun résultat (qu’on
appelle aussi procédures).
Exemple :
/* Fonction affichant un caractère */
void affiche_car (char car) {
printf ("%c",car);
}
int main () {
char c;
int i;
Variables locales
#include <stdio.h>
v = val * val;
return v;
}
int main () {
int val_retour = 0; /* Variable locale */
return 0;
}
Variables globales
#include <stdio.h>
int val = 0;
int val_retour = 0;
void carre () {
val_retour = val * val;
}
int main () {
Pointeurs et fonctions 87
val = 2;
carre ();
printf("Le carré de 2 est %d\n", val_retour);
return 0;
}
Par exemple :
#include <stdio.h>
Le nombre no est : 13
Le nombre a est : 12
Il faut donc retenir que les paramètres d’une fonction sont passés par
valeur et que modifier ces paramètres ne modifie que des copies des vari-
ables d’origine.
Pour pouvoir modifier les variables d’origine, il ne faut plus passer les
paramètres par valeur, mais par adresse, en utilisant les pointeurs, comme
c’est le cas dans l’exemple qui suit.
#include <stdio.h>
int main () {
int x=0;
avance_Position (&x);
return 0;
}
Nous devons utiliser des pointeurs pour pouvoir modifier certaines vari-
ables en dehors de l’endroit où elles sont déclarées. On dit généralement
qu’une fonction n’est pas capable de modifier ses arguments. L’usage des
pointeurs devient dans ce cas nécessaire. . . Ainsi, le programme suivant
affichera 2 et non 4.
#include <stdio.h>
x=x+x ;
}
int main () {
int i=2;
calcule_double(i);
printf("i vaut à présent :%d",i); /* il vaut toujours 2 !!! */
return 0;
}
int main () {
int i=2;
calcule_double(&i);
printf("i vaut à présent :%d",i);
return 0;
}
Néanmoins, la bonne pratique (celle qui donne les programmes les plus
simples à comprendre et les plus faciles à déboguer) serait d’écrire :
#include <stdio.h>
int main () {
int i=2;
i=calcule_double(i);
printf("i vaut à présent :%d",i);
return 0;
}
return y;
else
return x;
}
int main () {
int i1,i2;
i1=123;
i2=1267;
printf("max : %d\n",max(i1,i2));
printf("min : %d\n",min(i1,i2));
return 0;
}
/* PROTOTYPES : */
int max (int x, int y);
int min (int x, int y);
int main () {
int i1,i2;
i1=123;
i2=1267;
printf("max : %d\n",max(i1,i2));
printf("min : %d\n",min(i1,i2));
return 0;
}
Pointeurs et fonctions 93
int main () {
int val = 10;
int * ptr_val;
return 0;
}
int main () {
int i=10;
printf ("i=%d\n",i);
ajoute_un (&i);
printf ("i=%d\n",i);
return 0;
}
printf(" ");
for (j=1; j<= (i*2-1); j++)
printf("*");
printf("\n");
}
}
printf ("@@@\n");
}
}
int main () {
int nb_lig = 20;
ramure (nb_lig);
tronc (nb_lig - 2);
return 0;
}
6. À retenir
Pointeur
Un pointeur est une variable faite pour contenir une adresse mémoire,
souvent l’adresse d’une autre variable.
Pointeurs et fonctions 95
int main () {
int i=100;
int *pointeur_sur_i=NULL;
pointeur_sur_i=&i;
*pointeur_sur_i=200;
printf ("i vaut à présent %d\n",i);
return 0;
}
/* Prototypage */
void avance_Position (int* x);
int main () {
int i=0;
int x=0;
return 0;
}
CHAPITRE 9
1. Objectifs
97
98 Le C en 20 heures
2. Tableaux
Définition
Numéro de case 0 1 2 3 4 5 6 7
Contenu A B C D E F G H
Déclaration
Utilisation
/* déclarations */
int tab_int[10]; /* tableau de 10 cases (0 à 9)
d’entiers */
char tab_char[10]; /* tableau de 10 cases (0 à 9)
de caractères */
/* utilisation */
tab_char[3]=’C’; /* Initialisation de la case 3
(la quatrième) de tab_char */
tab_int[6]=10; /* Initialisation de la case 6
(la septième) de tab_int */
tab_int[7]=tab_int[6] * 2; /* La case 7 (la huitième)
contiendra donc 20 (10*2) */
3. Chaînes de caractères
printf("%s",chaine);
#include <stdio.h>
#include <string.h>
int main () {
char ch [] = "toto" ;
printf("La longueur de %s est : %d",ch,strlen(ch));
return 0;
}
Le programme suivant :
char tab[10];
printf("adresse où commence tab=%p",&tab[0]);
#include <stdio.h>
#include <string.h>
int main(void) {
char line[80];
strcpy(line,"un exemple de chaine initialisée...");
printf ("%s\n",line);
return 0;
}
int main(void) {
char line[80];
printf("veuillez entrer votre chaine :");
scanf("%s",line);
Exercice
Case 0 1 2 3 4 5 6 7 8 9 10
Contenu ’A’ ’B’ ’C’ ’D’ ’E’ ’F’ ’G’ ’H’ ’I’ ’J’ 0
TABLE 9.3 - – Remplissez un tableau. . .
for (i=’A’;i<=’Z’;i++){
tab_alpha[pos_tab]=i;
pos_tab++;
}
tab_alpha[26]=0;
printf("%s\n",tab_alpha);
return 0;
}
#include <stdio.h>
int main(void) {
char line[81];
/* 81 : taille arbitraire supposée suffisante
Une ligne écran = 80 caractères + 1 élément
pour le ’\0’ de fin de chaîne */
gets( line );
/* La frappe de l’utilisateur sera enregistrée dans
line, on suppose qu’il ne frappera pas plus de
80 caractères, sinon les problèmes vont commencer */
Notons qu’il n’y a qu’un seul passage à la ligne (celui affiché par la fonc-
tion printf).
int main () {
char ma_chaine [30];
ma_saisie (ma_chaine);
return 0;
}
int main () {
char ma_chaine [30];
ma_saisie (ma_chaine);
return 0;
}
106 Le C en 20 heures
La fonction strcat
int main () {
char chaine1[20]="Bonjour ";
char chaine2[20]="Paul";
printf("%s\n",chaine1);
return 0;
}
La fonction strncpy
int main () {
char chaine1[20]="Bonjour ";
char chaine2[20]="Edouard";
printf("%s\n",chaine1);
return 0;
}
. . . affichera :
Ednjour
La fonction strncat
int main () {
char chaine1[20]="Bonjour ";
char chaine2[20]="Edouard";
printf("%s\n",chaine1);
return 0;
}
. . . affichera :
Bonjour Ed
108 Le C en 20 heures
La fonction strcmp
sprintf(<chaine cible>,<chaine de
formatage>,<expr1>,<expr2>,...)
code=sprintf(s,"%d",i);
code=sscanf(s,"%f%f%f",&a,&b,&c);
5. Tableaux à 2 dimensions
Par exemple :
int table[5][5]; /* représente un tableau d’entiers de 5
lignes et 5 colonnes.*/
Ou bien :
float tab[3][2]= {{ 1.2, -1.3 },
{ 8.5, 12.4 },
{ -123.0, 4.0 }};
int main () {
int tab[5][10];
int i,j;
/* Pour chaque ligne ... */
for (i=0; i<5; i++){
/* ... considérer chaque case */
for (j=0; j<10; j++)
printf("%d ", tab[i][j]);
/* Retour à la ligne */
printf("\n");
}
return 0;
}
int main () {
int tab[5][10];
int i,j;
/* Pour chaque ligne ... */
for (i=0; i<5; i++){
/* ... considérer chaque case */
110 Le C en 20 heures
#define LIGNES 5
#define COLONNES 10
int main () {
int tab[LIGNES][COLONNES];
int i,j;
/* Pour chaque ligne ... */
for (i=0; i<LIGNES; i++){
/* Considérer chaque case */
for (j=0; j<COLONNES; j++)
scanf("%d", &tab[i][j]);
/* Retour à la ligne */
printf("\n");
}
return 0;
}
#define LIGNES 5;
#define COLONNES 10;
6. Zéro
Le caractère "0"
int main () {
char car=’0’;
Fin de chaîne 0
int main () {
char joke[5];
char moi[5]="eric";
joke[0]=’l’;
112 Le C en 20 heures
joke[1]=’i’;
joke[2]=’n’;
joke[3]=’u’;
joke[4]=’x’;
return 0 ;
}
Le pointeur NULL
int main () {
char* ptr=NULL;
Si vous aimez vous faire du mal, lisez ce qui suit, sinon passez votre
chemin. . .
7. Correction de l’exercice
#include <stdio.h>
#include <stdlib.h>
int main () {
/* 10 caractères + 0 de fin de chaîne */
char tab [11];
int i=0; /* compteur */
return 0;
}
8. À retenir
int main () {
char chaine1[81]; /* 80 caractères + ’\0’ */
char chaine2[81];
Tableaux et chaînes de caractères 115
return 0;
}
CHAPITRE 10
Structures et fichiers
117
118 Le C en 20 heures
2. Structures
typedef struct {
/* Définition de la structure */
} nom_du_type;
nom_du_type nom_variable;
struct personne{
char nom [LONGUEUR];
char prenom [LONGUEUR];
int age;
};
struct personne p;
#define LONGUEUR 40
typedef struct {
char nom [LONGUEUR];
char prenom [LONGUEUR];
int age;
} personne;
personne p;
nom_de_variable.nom_du_champ
120 Le C en 20 heures
Par exemple :
#include <stdio.h>
typedef struct {
char nom [40];
char prenom [20];
int age;
} personne;
int main () {
personne p;
printf("Veuillez entrer le nom de la personne :") →
,→ ;
scanf("%s",p.nom);
return 0;
}
Tout ce qui est enregistré sur votre disque dur ou presque est un fichier,
et porte un nom.
Il est possible de créer, de lire ou d’écrire dans des fichiers. Notez que
certains fichiers peuvent être protégés en lecture, en écriture ou les deux.
Voici un programme que nous allons détailler :
01. #include <stdio.h>
02. #include <stdlib.h>
03. int main () {
04. FILE *p_fichier; /* pointeur sur fichier*/
05. char nom_fichier[20], nom_personne[20];
06. int i, nbr_enregistrements;
Structures et fichiers 121
Explications :
– Ligne 4 : une variable p_fichier est créée ; elle va pointer sur un
type FILE. Sans entrer dans les détails, le type FILE est un type struc-
ture (vu au paragraphe précédent) qui permet de décrire un fichier.
– Ligne 9 : l’utilisateur va saisir une chaîne au clavier. Cette dernière
sera stockée dans la variable nom_fichier. Supposons pour fixer les
idées que l’utilisateur tape au clavier familles.txt. Le fichier qui
sera par la suite créé portera ce nom.
– ligne 12 : fopen va créer une sorte de lien entre le fichier du
disque dur qui s’intitule familles.txt et la variable p_fichier.
Ainsi dans la suite, vous allez faire des opérations sur la variable
122 Le C en 20 heures
/* Définition de constante */
#define maxligne 100
char ligne[maxligne];
FILE *p_fichier;
int main() {
p_fichier=fopen("essai.txt","r");
while (! feof(p_fichier)) {
fgets(ligne,maxligne,p_fichier);
if (! feof(p_fichier))
printf("J’ai lu :%s\n",ligne);
}
fclose(p_fichier);
return 0;
}
4. Fichiers et structures
typedef struct {
char nom [40];
char prenom [20];
int age;
} personne;
int main() {
FILE *p_fichier; /* pointeur fichier */
/* Créer et remplir le fichier */
p_fichier = fopen("essai.txt","w");
if (p_fichier == NULL) {
printf("\aImpossible de créer le fichier \n");
exit(-1); // Abandonner le programme
}
personne p;
printf("Veuillez entrer le nom de la personne:");
scanf("%s",p.nom);
printf("Veuillez entrer le prénom de la personne:");
scanf("%s",p.prenom);
fprintf(p_fichier, "%s\n",p.nom);
fprintf(p_fichier, "%s\n",p.prenom);
Structures et fichiers 125
fprintf(p_fichier, "%d\n",p.age);
fclose(p_fichier);
return 0;
}
CHAPITRE 11
1. Objectif
127
128 Le C en 20 heures
Erreur à la compilation
return 0 ;
}
Erreur d’exécution
#include <stdio.h>
int main () {
float f=1/0;
return 0 ;
}
3. Un phénomène surprenant. . .
return 0 ;
}
Essayez :
#include <stdio.h>
int main () {
printf ("Je suis ici\n") ;
while (1)
;
return 0 ;
}
int main () {
int i ;
for (i=0 ; i<100 ; i++)
printf("i=%d",i) ;
while (1)
;
return 0 ;
}
while (1)
;
return 0 ;
}
Corriger le bug
5. Bonne chasse. . .
i=0
i=1
...
i=9
La moyenne vaut: 4.50000
return 0 ;
}
Soit vous voyez tout de suite l’erreur. . . soit vous ajoutez des
mouchards :
#include <stdio.h>
int main () {
int i=0;
printf("1) Je suis ici\n") ;
scanf("%d",i);
printf("2) Je suis ici\n");
return 0 ;
}
int main () {
int tab[TAILLE];
tab[TAILLE+10]=100;
return 0 ;
}
1. N’oubliez pas les \n dans vos printf pour la raison évoquée plus haut. . .
134 Le C en 20 heures
Le debugger ddd
Faites :
– gcc -o essai essai.c -g
– ddd essai
– fermez les petites fenêtres « parasites » qui apparais-
sent au lancement de ddd
– cliquez sur le bouton run (il faut parfois chercher un
peu dans les menus). . .
Lorsque vous faites p=NULL ;, vous placez donc la valeur 0 dans cette
variable. Ceci signifie que p pointe sur un élément mémoire qui n’est pas
accessible par votre programme en écriture. Or, vous faites *p=123 ; qui
revient à vouloir écrire la valeur 123 à l’adresse NULL.
Le debugger ddd vous indique alors quelle ligne a provoqué l’erreur de
segmentation. Sur un programme de plusieurs centaines, voire plusieurs
milliers de lignes, cette aide est particulièrement appréciable.
int main () {
int i;
char chaine[]="! éuggubéd tse emmargorp el";
Dernière sournoiserie. . .
int main () {
int i;
int i1,i2 ;
char c1,c2;
printf("Entrez un chiffre:");
scanf("%d",&i);
printf("Entrez un caractère:");
gets(chaine);
c=chaine[0];
printf("Entrez un chiffre:");
gets(chaine);
sscanf(chaine,"%d",&i) ;
7. Solutions
int main () {
int i;
char chaine[]="! éuggubéd tse emmargorp el";
8. À retenir
Le debugger ddd
Compléments
1. Objectif
2. Conversions de type
141
142 Le C en 20 heures
int main () {
float f;
int i;
f=3.1415;
i=(int) f; /* résultat dans i : 3 */
/* donc la partie décimale est perdue... */
return 0 ;
}
#include <stdio.h>
int main () {
printf("Résultat : %f",3.0/4);
return 0 ;
}
#include <stdio.h>
int main () {
printf("Résultat : %f",(float)3/4);
return 0 ;
}
int main () {
printf("Résultat : %f",(float)(3/4));
return 0 ;
}
4. Fonction putchar
Le programme suivant :
#include <stdio.h>
int main () {
char c=’A’;
putchar(c);
return 0 ;
}
#include <stdio.h>
int main () {
char c=’A’;
printf("%c",c);
return 0 ;
}
Exemple :
sizeof(tab1) 20
sizeof(tab2) 50
sizeof(double) 8 Généralement !
sizeof("bonjour") 8 Pensez au zéro final des
chaînes
sizeof(float) 4 Généralement !
char * pointeur_sur_chaine;
char * pointeur_sur_float;
int main() {
char phrase[LONGUEUR_MAX_PHRASE];
char *phrases[NOMBRE_MAX_PHRASES];
int i;
/* Réservation de la mémoire */
phrases[i] = (char *) malloc(strlen(phrase)+1);
return 0;
}
Compléments 147
Fonction free
Lorsque nous n’avons plus besoin d’un bloc de mémoire que nous avons
réservé à l’aide de malloc, nous pouvons / devons le libérer à l’aide de la
fonction free déclarée dans <stdlib.h>.
L’appel à free(<Pointeur>) libère le bloc de mémoire désigné par
<Pointeur>. L’appel à free n’a pas d’effet si le pointeur passé en
paramètre possède la valeur zéro.
Par exemple :
char * pointeur_sur_chaine;
pointeur_sur_chaine = (char *) malloc(1000*sizeof(char));
...
Vous savez qu’une fonction n’est pas capable de modifier ses argu-
ments :
#include <stdio.h>
main () {
int i=2;
calcule_double(i);
printf("i vaut à présent :%d",i);/* i vaut toujours 2 !!! */
}
Compléments 149
main () {
int i=2;
calcule_double(&i);
printf("i vaut à présent :%d",i); /* i vaut bien 4 !!! */
}
4. * pointeur_int = (* pointeur_int)+(*
pointeur_int) : (* pointeur_int) pointe sur i. L’ancienne
valeur de i va être écrasée par la nouvelle valeur : 2+2
5. printf("i vaut à présent : %d", i) : on se retrouve avec
4 comme valeur de i.
150 Le C en 20 heures
int main() {
int n;
saisie(&n);
printf("n vaut : %d",n);
return 0;
}
Lorsque vous compilez, vous pouvez obtenir des erreurs, des warnings
(avertissements) ou parfois les deux.
Les erreurs, vous connaissez : lorsque écrivez par exemple floatt au
lieu de float, c’est une erreur.
S’il y a des erreurs à la compilation (gcc -o essai essai.c), le com-
pilateur ne génèrera pas de fichier exécutable (fichier essai). En re-
vanche, s’il n’y a que des warnings, le fichier essai sera créé, mais le
compilateur nous alerte au sujet d’une erreur possible.
Il est important de comprendre qu’en langage C, un warning équivaut à
une « erreur larvée ». Ainsi, vous pouvez effectivement exécuter votre pro-
gramme et ce malgré les warnings mais le problème est que vous risquez
de le « payer » par la suite.
Exemple
int main() {
int i=0,j=0;
int matrice[9][9];
int valeur=0;
{
matrice [i][j]=valeur;
valeur++;
}
affiche_matrice(matrice[3][3]);
}
9. C obscur
Un peu d’histoire 1
Un petit exemple
%
typedef unsigned char t;t*F="%c",l[]="|\\/=_ \n](.\0(),*(.(=(}*.)[[*.",N=’\n’,*
r;typedef(*H)();extern H Ar;Q(a){return(a|-a)>>31;}H S(c,a){return(H)(a&~c|(int
)Ar&c);}extern t*ist;V(t*u){*u^=*u&2^(*u>>7)*185;}Z(t*u,t n){*u-=n;}e(t c,H h){
R(h,Q(* r^c));}
I(){r=l +7-4*Q(
getchar ()^*l);
}R(H h, int c){Ar=S
(c,h);- main() ;}P(){r
++;}z() { O(&N);}
O(t*c){ printf( F,+*c);
}T(){r= "This is not a function\n" ;}w(U){
U=Z(r,8 ); r-=~Q(*
r/8-4); return 0; }M(){r=
ist-68; } h(){t G
=r[1]-r [2]^*r;
G^=30;V (&G);e(
0,(O(&G ),P(P(*
r++)),z));}g(){M();R(h,0);}f(){P(O(r));e(’f’,g);}p(){P();e(’a’,f);}d(){P(O(r));
e(’n’,p);}c(u){u=r[-2];T(Ar=d);R(f,Q(u^’"’));}n(){e(w(O(l+*r%8)),c);}a(){I();R(
n,0);}main(){S(Q(Ar),a)();}H Ar;t*ist="Rene Magritte"-(1898-1967);
Le ; est utilisé pour terminer une commande, il peut donc être utilisé
pour mettre plusieurs commandes sur une ligne.
#include <stdio.h>
int main ()
{
printf("Bonjour");printf("Bien plus lisible\n");printf("N’est ce →
,→ pas\n");
return 0;
}
#include <stdio.h>
int main ()
{
printf("Bonjour "),printf("Bien plus lisible\n"),printf("N’est →
,→ ce pas\n");
int a=1,b=2,c=0;c=a+=2,a+b;
printf("a: %d b: %d c: %d\n",a,b,c);
return 0;
}
$ ./monprog
Bonjour Bien plus lisible
N’est ce pas
a: 3 b: 2 c: 3
Hexadécimal
$ ./monprog
Bonjour
Opérateur ternaire
La suite d’instructions :
if (a>b)
maximum=a;
else
maximum=b;
Par exemple :
printf("Vous avez %i carte%c.\n", n, (n==1) ? ’ ’ : →
,→ ’s’);
Il existe une autre forme raccourcie pour faire des tests dans le lan-
gage C : && et ||.
Le symbole && est l’équivalent de si vrai et le symbole || l’équivalent
de si faux. Cette forme de test est très courante.
#include <stdio.h>
int main ()
{
int a=3;
( a >=2 ) && printf ("Test 1 - a >= 2\n");
( a <=2 ) || printf ("Test 2 - a < 2\n");
( a <=2 ) && printf ("Test 3 - a >= 2\n")
|| printf ("Test 3 - a < 2\n");
return 0;
}
CHAPITRE 13
1. Objectifs
2. Convertisseur francs/euros
157
158 Le C en 20 heures
#include <stdio.h>
#define TAUX 6.55957
int main () {
float francs=0;
while (francs<=10) {
printf("%4.1f francs = %.2f euros\n",francs,francs/TAUX);
francs=francs+0.5;
}
return 0;
}
L’exécution donnera :
0.0 francs = 0.00 euros
0.5 francs = 0.08 euros
1.0 francs = 0.15 euros
1.5 francs = 0.23 euros
2.0 francs = 0.30 euros
2.5 francs = 0.38 euros
3.0 francs = 0.46 euros
3.5 francs = 0.53 euros
4.0 francs = 0.61 euros
4.5 francs = 0.69 euros
5.0 francs = 0.76 euros
5.5 francs = 0.84 euros
6.0 francs = 0.91 euros
6.5 francs = 0.99 euros
7.0 francs = 1.07 euros
7.5 francs = 1.14 euros
8.0 francs = 1.22 euros
8.5 francs = 1.30 euros
9.0 francs = 1.37 euros
9.5 francs = 1.45 euros
10.0 francs = 1.52 euros
int main () {
int nb_hasard=0;
int i;
i=0;
do {
nb_hasard = rand ();
if (nb_hasard % 2==0) /* c’est un nombre pair */
nb_pairs=nb_pairs+1;
else
nb_impairs=nb_impairs+1;
i++;
}
while (i<1000);
int main () {
int ligne, colonne;
for (ligne=1;ligne<=10;ligne++) {
for (colonne=1;colonne<=10;colonne++) {
printf("%4d",ligne*colonne); /* affichage sur 4 caractères */
}
printf("\n");
}
return 0;
}
int main() {
int t1[] = {1,10,4,5,-7}, t2[] = {2,1,14,3} ;
printf("Maximum de t1 : %d\n", max_Tableau(t1,5) );
printf("Maximum de t2 : %d\n", max_Tableau(t2,4) );
return 0;
}
Quelques exemples de programmes 161
int main () {
int i,j;
#include <stdio.h>
#define TAILLE 10
int main () {
int i,j;
i=0;
j=TAILLE-1;
162 Le C en 20 heures
while (i<j) {
printf("i=%d j=%d\n",i,j);
i++, j--;
}
return 0;
}
#include <stdio.h>
#define TAILLE 10
int main() {
/* Déclarations */
int tab[TAILLE]; /* tableau donné */
saisie (tab,TAILLE);
miroir(tab,TAILLE);
return 0;
}
Supposons que l’on dispose d’un tableau tab qui contient 10 valeurs.
Nous souhaitons trier ce tableau. Une solution toute simple consiste à
faire un passage sur le tableau et à comparer la case d’indice n avec celle
d’indice n+1.
Si la case se trouvant à l’indice n contient une valeur plus grande que
celle de l’indice n+1, alors on inverse les deux valeurs, et ainsi de suite.
Voici un exemple sur un tableau de 10 cases :
164 Le C en 20 heures
Tableau initial :
Indice de la case : 0 1 2 3 4 5 6 7 8 9
Valeur stockée : 12 10 4 5 6 7 8 9 10 1
0 1 2 3 4 5 6 7 8 9
10 12 4 5 6 7 8 9 10 1
0 1 2 3 4 5 6 7 8 9
10 4 12 5 6 7 8 9 10 1
...
Au bout d’un parcours complet du tableau, on obtient :
0 1 2 3 4 5 6 7 8 9
10 4 5 6 7 8 9 10 1 12
Nous constatons que le tableau est « mieux » trié, mais ça n’est pas
encore parfait. Dans le pire des cas (tableau trié dans l’ordre décroissant)
n-1 passages seront nécessaires et suffisants pour trier un tableau de taille
n.
Cette méthode de tri porte un nom, il s’agit du tri à bulles.
Quelques exemples de programmes 165
/******************************************/
void saisie(int t[], int n);
void affiche(int t[],int n);
void tri_tableau (int tab[], int taille);
/******************************************/
int main () {
int tab[TAILLE];
saisie(tab,TAILLE);
tri_tableau(tab,TAILLE);
printf("Voici votre tableau trié :\n");
affiche(tab,TAILLE);
return 0;
}
/* Procédure de tri */
void tri_tableau (int tab[], int taille) {
int i,j;
int temp;
/* tri du tableau */
for (i=0; i<taille-1; i++)
for (j=0; j<taille-1; j++)
if (tab[j]>tab[j+1]) { /* échange de valeurs */
temp=tab[j];
tab[j]=tab[j+1];
tab[j+1]=temp;
}
}
printf("\n");
}
8. Jeu de la vie
Historique
Règles du jeu
Images obtenues
Proposition de programme
Nous allons considérer que toutes les cellules sont stockées dans une
matrice (notre damier ne sera donc pas infini). Pour une case m[i][j],
les huit voisins sont :
#include <stdio.h>
#include <stdlib.h>
#define TAILLE_SOUS_MATRICE 7
#define TAILLE_SUR_MATRICE 9
/* Taille de la matrice contenant */
/* les cellules + 2 pour la bordure */
/****************************************/
/******* P R O T O T Y P E S ********/
/****************************************/
int main() {
int i;
int nbr_cycles;
int matrice[TAILLE_SUR_MATRICE] [TAILLE_SUR_MATRICE ];
#include <stdio.h>
#include <stdlib.h>
#define TAILLE_SOUS_MATRICE 7
/* On peut avoir 7 * 7 cellules vivantes */
#define TAILLE_SUR_MATRICE 9
/* On place une bordure autour qui facilite la vie du programmeur →
,→ ... */
int main( ) {
int i;
int nbr_cycles;
int matrice[TAILLE_SUR_MATRICE] [TAILLE_SUR_MATRICE ];
char s[2];
Quelques exemples de programmes 173
init(matrice);
printf("La population au départ : \n");
affiche_matrice(matrice);
printf("Pressez sur ENTER pour continuer...\n");
gets(s);
/****************************************/
/* Initialisation de la matrice */
void init(int matrice [][TAILLE_SUR_MATRICE ]) {
/****************************************/
int i,j;
/****************************************/
/* Calcul du nombre de voisins vivants */
int nombre_voisins (int matrice[][TAILLE_SUR_MATRICE ],
int ligne, int colonne) {
/****************************************/
int compte=0; /* compteur de cellules */
int i,j;
for (i=ligne-1;i<=ligne+1;i++)
for(j=colonne-1;j<=colonne+1;j++)
compte=compte+matrice[i][j];
return compte;
}
/****************************************/
/* Correspond à l’étape n+1 */
void mise_a_jour(int matrice[ ][TAILLE_SUR_MATRICE ]) {
/****************************************/
int i,j;
int nbr_voisins;
int matrice_densite[TAILLE_SOUS_MATRICE][TAILLE_SOUS_MATRICE];
/* matrice qui comptabilise le nombre de voisins */
/* et cela, case par case */
/****************************************/
/* Affichage à l’écran des cellules vivantes */
void affiche_matrice(int matrice[ ][TAILLE_SUR_MATRICE ]) {
/****************************************/
int i,j;
/****************************************/
/* Tracé d’une ligne */
void ligne(int largeur) {
/****************************************/
int i;
for(i=0; i<largeur; i++)
printf("+-");
printf("+\n");
Quelques exemples de programmes 175
En deuxième lecture. . .
et à compiler en tapant :
gcc -o essai essai.c -lm
Voici quelques fonctions mathématiques très utiles.
177
178 Le C en 20 heures
2. Pointeurs et structures
typedef struct {
char nom [40];
char prenom [20];
int age;
} personne;
int main () {
personne p;
personne * pointeur_sur_une_personne;
printf("Veuillez entrer le nom de la personne :");
scanf("%s",p.nom);
pointeur_sur_une_personne=&p;
printf("Voici les caractéristiques de cette personne:\n");
printf("nom=%s\n",(*pointeur_sur_une_personne).nom);
En deuxième lecture. . . 179
return 0;
}
Notez que cette seconde écriture (plus pratique à l’usage) repose sur une
flèche qui est construite avec le signe moins (-) et le signe supérieur (>).
Supposons que votre programme soit utilisé sur internet et qu’un utilisa-
teur malveillant entre une chaîne de caractères plus grande que 10 carac-
tères, par exemple « ABCDEFGHIJKLMNOPQR ». Dans ce cas, à l’exécution,
votre programme va recopier à partir de l’adresse de la variable chaine
les caractères A, B, . . . jusqu’à R. Dès lors, les zones mémoires qui suivent
la variable chaine seront écrasées. Ceci explique que le compilateur vous
indique un warning.
Pour y remédier, vous pouvez utiliser :
char buffer[128];
fgets(buffer, 128, stdin);
en sachant que stdin (mis pour standard input c’est-à-dire entrée stan-
dard) désigne le plus souvent le clavier.
int i=123;
fprintf(stdout,"%d",i);
char mois[12][10]={"janvier","février","mars","avril","mai",
"juin","juillet","août","septembre","octobre","novembre",
"décembre"};
Verbe : programmer
je programme
tu programmes
il ou elle programme
nous programmons
vous programmez
ils ou elles programment
/* Conjuguer le verbe */
for (i=0; i<6; i++)
printf("%s %s%s\n",sujets[i], verbe, terminaisons[i]);
}
return 0;
}
6. Pointeurs et tableaux
Nous allons à présent examiner les liens très étroits qu’il y a entre poin-
teurs et tableaux. En fait, nous allons voir qu’à chaque fois que vous ma-
nipulez des tableaux, comme par exemple à la ligne contenant le printf
du programme ci-dessous, le langage C va transformer votre instruction
tableau[i] en se servant de pointeurs. . .
int tableau[10]={1,2,3,4,5,6,7,8,9,10};
int i;
for (i=0;i<10;i++)
printf("%d ",tableau[i]);
Si p pointe sur une case quelconque d’un tableau, alors p+1 pointe sur
la case suivante.
Ainsi, après l’instruction : p = p+1 ;
le pointeur p pointe sur tableau[1],
Si p = tableau, alors :
Formalisme tableau :
int main() {
int tableau[5] = {-4, 4, 1, 0, -3};
int positifs[5];
int i,j; /* indices courants dans tableau et positifs */
for (i=0,j=0 ; i<5 ; i++)
if (tableau[i]>0){
positifs[j] = tableau[i];
j++;
}
return 0;
}
int main() {
int tableau[5] = {-4, 4, 1, 0, -3};
int positifs[5];
int i,j; /* indices courants dans tableau et positifs */
for (i=0,j=0 ; i<5 ; i++)
if (*(tableau+i)>0){
*(positifs+j) = *(tableau+i);
j++;
}
return 0;
}
#include <stdio.h>
#define TAILLE 100
int main() {
i=1;
for (p1=tableau; p1<tableau+dim; p1++) {
printf("Valeur de l’élément %d : ", i++);
scanf("%d", p1); // notez l’absence de ’&’ !!!
}
/* Inversion du tableau */
for (p1=tableau,p2=tableau+(dim-1); p1<p2; p1++,p2--) {
aux = *p1;
*p1 = *p2;
*p2 = aux;
}
/* Affichage du résultat */
En deuxième lecture. . . 187
return 0;
}
7. Tableaux de pointeurs
<Type> *<NomTableau>[<N>]
Un premier exemple
double * tableau[10] ;
Ce petit programme stocke les jours de la semaine dans des zones mé-
moires allouées explicitement à l’aide de la fonction malloc.
188 Le C en 20 heures
#include <stdio.h>
#include <malloc.h>
#include <string.h>
int main() {
char * jours[7];
int i;
for (i=0;i<7;i++) {
jours[i]=(char *) malloc(9);
}
strcpy(jours[0],"lundi");
strcpy(jours[1],"mardi");
strcpy(jours[2],"mercredi");
// ...
return 0;
}
if (i==0)
printf ("Nombre nul\n");
else {
if (i==1)
printf ("Nombre non égal à un\n");
else
printf ("Autre type de nombre\n");
}
190 Le C en 20 heures
switch (i) {
case 0:
printf ("Nombre nul\n");
break;
case 1:
printf ("Nombre égal à un\n");
break;
default:
printf("Autre type de nombre\n");
break;
}
switch (i) {
case 0:
printf ("Nombre nul\n");
/* pas de break */
case 1:
printf("Nombre égal à un\n");
break;
default:
printf("Autre type de nombre\n");
break;
}
switch (a) {
case 1: case 2: case 5:
printf("Voici le premier message\n");
break;
case 3: case 4:
printf("Voici le second message\n");
break;
default:
printf("Voici le message par défaut\n");
break;
}
9. Édition de liens
gcc -c essai.c
Cette étape a pour effet de générer le fichier essai.o qui ne contient pour
le moment que le code objet qui correspond au source compilé, mais qui
ne lie pas les appels de fonctions des bibliothèques extérieures telles que
printf, scanf, feof, sqrt à leur code respectif.
L’étape suivante, appelée édition de liens, est réalisée en entrant la com-
mande :
#include <stdio.h>
int main () {
int j;
int main ()
{
int a=13;
int b=15;
int c=minimum(a,b);
printf ("Minimum entre %d et %d : %d",a,b,c);
return 0;
}
Compilons le :
gcc -o principal principal.c
$ ./principal
Minimum entre 13 et 15 : 13
int main ()
{
int a=13;
En deuxième lecture. . . 195
int b=15;
int c=minimum(a,b);
printf ("Minimum entre %d et %d : %d",a,b,c);
return 0;
}
On remarquera que les < > de l’include se sont transformés en " " pour
indiquer que le .h est à rechercher sur le répertoire courant et non dans
les librairies C.
La compilation du programme fonctionne bien sauf au moment de la réal-
isation de l’édition de liens.
$ gcc -c principal.c
$ gcc -o principal principal.o
principal.o: In function ‘main’:
principal.c:(.text+0x29): undefined reference to ‘minimum’
collect2: ld returned 1 exit status
La raison pour laquelle cette dernière ne fonctionne pas est qu’il n’existe
pas de fichier binaire (.o) contenant la fonction minimum contrairement
à ce qui a été annoncé.
Corrigeons cela tout de suite en créant un fichier minimum.c :
#include "minimum.h"
L’intérêt de cette méthode n’est pas forcément très évidente sur cet ex-
emple mais imaginez un programme disposant de centaines de fonctions !
CHAPITRE 15
Exercices
1. Objectifs
2. Jeu de morpion
Principe
197
198 Le C en 20 heures
X O .
X O X
O . O
Fin du jeu
Améliorations possibles
3. Jeu de pendu
Principe
Le but du jeu est de deviner en moins de 7 essais un mot que seul l’or-
dinateur connaît.
Pour mener à bien votre mission, vous allez proposer une lettre :
– si la lettre est correcte alors, celle-ci s’affiche à sa place dans le mot
à deviner ;
200 Le C en 20 heures
Exemple
Un peu d’aide
Point de départ
Algorithme
Améliorations possibles
4. Balle rebondissante
int main () {
while (1) {
system("clear");
affiche_grille(grille);
Améliorations
5. Solutions
Le morpion
#include <stdio.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
printf ("\n-------\n");
204 Le C en 20 heures
for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
printf("|");
switch(plateau[i][j]) {
case 0:
printf(" ");
break;
case 1:
printf("O");
break;
case 2:
printf("X");
break;
}
}
printf ("|\n");
printf ("-------\n");
}
}
for (i=0;i<3;i++) {
for (j=0;j<3;j++) {
if (plateau [i][j]==0) {
return FALSE;
}
}
}
return TRUE;
}
do {
printf ("%s", invite);
scanf ("%d",&valeur);
} while (( valeur <1) || (valeur >3));
return (valeur);
}
}
}
return FALSE;
}
do {
printf ("Joueur %d\n",joueur);
pos_x= saisie_donnee ("Ligne : ");
pos_y= saisie_donnee ("Colonne : ");
if ( plateau[pos_x-1][pos_y-1]>0 ) {
printf ("Case occupée !\n");
} else {
plateau[pos_x-1][pos_y-1]=joueur;
correct=TRUE;
}
}
while (! correct);
dessine_plateau (plateau);
}
int main () {
int plateau [3][3];
int joueur=1;
206 Le C en 20 heures
dessine_plateau (plateau);
do {
jeu (plateau, joueur);
if ( joueur==1 ) {
joueur=2;
} else {
joueur=1;
}
}
while (( !gagne (plateau)) && (!fin_jeu (plateau)) );
return 0;
}
Le pendu
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
char lireCaractere() {
char chaine[2];
gets(chaine);
return chaine[0];
}
int main() {
int i=0;
int coups=7;
char motAtrouver[]="BONJOUR";
char lettreSaisie=’ ’;
int lettre_trouvee=FALSE;
char gagne=FALSE;
char* motCherche;
motCherche=malloc (sizeof (motAtrouver));
memset (motCherche,’*’,sizeof (motAtrouver));
motCherche[sizeof (motAtrouver)-1]=0;
do {
// Aucune lettre trouvée
lettre_trouvee=FALSE;
if(lettreSaisie==motAtrouver[i]) {
motCherche[i]=lettreSaisie;
lettre_trouvee=TRUE;
}
}
if ( gagne )
puts ("GAGNE");
else
puts ("PERDU");
getchar();
free (motCherche);
return 0;
}
208 Le C en 20 heures
Balle rebondissante
#include <stdio.h>
#include <string.h>
#include <unistd.h>
grille [pos_balle_x][pos_balle_y]=’O’;
}
}
printf ("\n");
}
}
int theo_pos_x=0;
int theo_pos_y=0;
int main () {
while (1) {
system("clear");
affiche_grille(grille);
...
32: 33: ! 34: " 35: # 36: $ 37: % 38: 39: ’
40: ( 41: ) 42: * 43: + 44: , 45: - 46: . 47: /
48: 0 49: 1 50: 2 51: 3 52: 4 53: 5 54: 6 55: 7
56: 8 57: 9 58: : 59: ; 60: 61: = 62: 63: ?
64: @ 65: A 66: B 67: C 68: D 69: E 70: F 71: G
72: H 73: I 74: J 75: K 76: L 77: M 78: N 79: O
80: P 81: Q 82: R 83: S 84: T 85: U 86: V 87: W
88: X 89: Y 90: Z 91: [ 92: \ 93: ] 94: ^ 95: _
96: ‘ 97: a 98: b 99: c 100: d 101: e 102: f 103: g
104: h 105: i 106: j 107: k 108: l 109: m 110: n 111: o
...
211
ANNEXE
Bon à savoir
213
214 Le C en 20 heures
Format Conversion en
%d int
%f float
%lf double
%c char
%s char*
Format Conversion en
%d int
%f float
%f double
%c char
%s char*
if (i=0) if (i==0)
if (a & b) if (a && b)
tab[i,j] tab[i][j]
Les bornes d’un tableau de N cases Les bornes d’un tableau de N cases
varient entre 1 et N varient entre 0 et N-1
char c ; char c ;
char * s; char * s;
ou mieux :
char chaine[]="12345";
217
218 Le C en 20 heures
219
Table des matières
Avant de commencer iv
1 Premiers pas 1
1. Système d’exploitation et C . . . . . . . . . . . . . . . . . . . . . . . . . . 1
2. Utiliser un éditeur sous G NU/Linux . . . . . . . . . . . . . . . . . . . . . . 2
3. Exemple de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
4. Normalisation du programme . . . . . . . . . . . . . . . . . . . . . . . . . 5
5. Petit mot sur ce qu’est une bibliothèque . . . . . . . . . . . . . . . . . . . . 7
6. Un exemple de fichier en-tête . . . . . . . . . . . . . . . . . . . . . . . . . 7
7. Compléments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
8. Squelette de programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
9. Blocs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
10. Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
11. Exercice d’application . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
12. Corrigé de l’exercice du chapitre . . . . . . . . . . . . . . . . . . . . . . . 10
13. À retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2 Variables (partie 1) 13
1. Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2. Affichage : la fonction printf . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3. Notion de variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
4. Déclaration d’une variable . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
5. Application : exemples . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
6. Utilisation de % dans printf . . . . . . . . . . . . . . . . . . . . . . . . . . 17
221
222 Le C en 20 heures
7. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
8. Réutilisation d’une variable . . . . . . . . . . . . . . . . . . . . . . . . . . 18
9. Caractères spéciaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
10. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
11. Corrigés des exercices du chapitre . . . . . . . . . . . . . . . . . . . . . . 20
12. À retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
3 Variables (partie 2) 23
1. Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
2. Exercice de mise en bouche . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3. Déclaration de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
4. Saisie des variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5. Les types flottants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
6. D’autres fonctions utiles . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7. Corrigés des exercices du chapitre . . . . . . . . . . . . . . . . . . . . . . . 29
8. À retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
4 Conditions 33
1. Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
2. Exercice de mise en bouche . . . . . . . . . . . . . . . . . . . . . . . . . . 34
3. Condition : Si Alors Sinon . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
4. Opérateurs de comparaison . . . . . . . . . . . . . . . . . . . . . . . . . . 36
5. Opérateurs logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6. Vrai ou faux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
7. Combinaison . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
8. Accolades . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
9. Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
10. Corrections des exercices du chapitre . . . . . . . . . . . . . . . . . . . . . 42
11. À retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
5 Mise au point 45
1. Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
2. Plus petit ou plus grand . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
3. Retour sur getchar() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
4. Boucle : Faire . . . Tant que (condition) . . . . . . . . . . . . . . . . . . . . 47
5. Opérateur modulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
6. Nombres pseudo-aléatoires . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7. Corrigés des exercices du chapitre . . . . . . . . . . . . . . . . . . . . . . . 51
223
7 Boucles 65
1. Objectifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
2. Et les Shadoks pédalèrent pendant 15 tours . . . . . . . . . . . . . . . . . . 65
3. Syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
4. Notion de double boucle . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
5. Et les Shadoks fêtèrent Noël. . . . . . . . . . . . . . . . . . . . . . . . . . . 68
6. Table Ascii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
7. Corrigés des exercices du chapitre . . . . . . . . . . . . . . . . . . . . . . . 70
8. À retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
8 Pointeurs et fonctions 75
1. Objectifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
2. Binaire, octets. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
3. Variables : pointeurs et valeurs . . . . . . . . . . . . . . . . . . . . . . . . . 78
4. Fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
5. Corrigés des exercices du chapitre . . . . . . . . . . . . . . . . . . . . . . . 93
6. À retenir . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
12 Compléments 141
1. Objectif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
2. Conversions de type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 141
3. Usage très utile des conversions de type . . . . . . . . . . . . . . . . . . . . 142
4. Fonction putchar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
5. Allocation dynamique de mémoire . . . . . . . . . . . . . . . . . . . . . . 144
6. Avez-vous bien compris ceci ? . . . . . . . . . . . . . . . . . . . . . . . . . 148
7. Sur l’utilité des pointeurs . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
8. Un mot sur les warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
9. C obscur . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
15 Exercices 197
1. Objectifs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
2. Jeu de morpion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197
3. Jeu de pendu . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 199
4. Balle rebondissante . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201
5. Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 203