You are on page 1of 26

1

Petite initiation au langage C


et au graphisme SDL



Lorsque lon utilise lordinateur pour rsoudre des problmes qui nous sont poss,
pas besoin dtre virtuose en programmation. Un bagage minimal de connaissances
suffit, et comme je vais utiliser le langage C, disons quil sagit plutt de faire du C - -
que du C + +. Pourquoi le langage C ? Parce que cest le plus cumnique. Mais si
vous prfrez aller plus loin avec dautres langages que le C, poursuivez votre chemin et
affirmez votre originalit.
Si vous connaissez dj des bribes de programmation, ce qui suit vous donnera des
lments sur la syntaxe du langage C, tant entendu que la structure interne dun
programme est la mme en C quen Pascal, Basic, Fortran, Par exemple, ce qui scrit
{ en C scrit begin en Pascal. Si vous ne connaissez quasiment rien la
programmation, le rapide survol du langage C qui suit vous donnera un premier aperu
des moyens de traitement de problmes via lordinateur. Au fond, tout se rsume en
quatre termes : boucles, tests, tableaux, fonctions. Il convient de faire avec !
Et maintenant quel langage C choisir ? Celui que vous voulez. Pour satisfaire aux
rumeurs qui courent sur Internet, jai pris Code Blocks, ayant lu que son principal
concurrent Dev-C++ ntait plus dvelopp depuis 2005, mais par la suite jai appris
lexistence de wxDevC++, alors les rumeurs En tout cas la premire chose faire est
de tlcharger le langage. Je vais vous dire comment installer Code Blocks sous
Windows, et mme Windows Vista, mais si vous prfrez le faire sous Linux, ce ne doit
pas tre plus compliqu.

Tlcharger Code Blocks sous Windows (Vista) en 5 minutes chrono

Allez chez Google, et demandez tlcharger code blocks 8.02 . Prendre la
premire proposition qui vient, et demandez tlcharger. Nouvelle page : cliquez sur
download the binary release. Vous tes envoy sur un site o dans la rubrique Windows
on vous propose Codeblocks-8.02mingw-setup.exe tlcharger avec Sourceforge ou
BerliOS. Choisissez qui vous voulez, et tlchargez. Quelques secondes plus tard, cest
fini. Une icne ronde est apparue sur votre bureau . Cliquez dessus, et obissez aux
instructions sans chercher faire preuve doriginalit. Quelques secondes encore, et le
rpertoire CodeBlocks se trouve install lintrieur de vos Programmes (Program
Files). Dans ce rpertoire C:\Program Files\CodeBlocks, vous allez trouver
lexcutable, parfaitement reprable grce son carr divis en quatre petits carrs
coloris (rouge, vert, jaune, bleu). Cliquez dessus, moins que vous ne fassiez un
raccourci partir de votre bureau. Et la page CodeBlocks apparat plein cran. Dans le
jargon informatique, cette page constitue lIDE (environnement de dveloppement
intgr), le centre de pilotage partir duquel vous allez crire votre programme dans
lditeur de texte, puis lancer la compilation.

Premier programme : bienvenue chez les dbiles

Dans la page Code::Blocks on vous propose, au centre de lcran : Create a new
project. Cliquez dessus. Dans la fentre qui apparat, cliquez sur Console application.
2

Faites next pour aller dune page la suivante. On va vous demander si vous voulez C
ou C++. Choisissez C. Puis on vous demande de donner un nom votre projet. Tapez
par exemple dans Project title : bonjour. Puis next, et on vous annonce quune
configuration release est cre. Cest fini.
Vous voyez apparatre, dans la colonne Projets gauche de lcran, le carr bonjour
en dessous de Workspace. Ainsi dans votre espace de travail (workspace) se trouve
intgr votre projet bonjour, encore vierge. Cliquez dessus, et vous voyez apparatre
Sources. Cliquez sur Sources, et vous voyez apparatre main.c. Cliquez sur main.c et l
est dit un petit programme dj tout prt.
Commencez par supprimer #include <stdlib.h> qui ne sert rien. Puis remplacez
Hello World !\n , par Bonjour\n ou ce que vous voulez.
Vous avez votre premier programme en C :

#include <stdio.h>
int main()
{
printf( Bonjour\n ) ;
return 0 ;
}

Pas besoin dtre un expert pour se douter que ce programme va nous afficher
Bonjour ! Encore convient-il de faire tourner ce programme. Pour cela aller dans la
rubrique Build en haut de lcran, et demander build puis run. Une fentre fond noir
apparat avec marqu dessus Bonjour. Quand vous en avez assez, appuyez sur une
touche, et la fentre va disparatre. Vous vous retrouvez dans votre IDE Code Blocks.
Pour sauvegarder ce programme, allez dans la premire colonne File en haut gauche,
et demandez par exemple Save everything. Ensuite vous pouvez tout fermer, et quitter
codeblocks (allez sur votre projet bonjour, puis un clic droite sur la souris donne un
menu o lon trouve close project). Votre projet va tre pieusement conserv dans le
rpertoire c:\Program Files\CodeBlocks sous le nom bonjour.
1
Et en allant visiter ce
rpertoire bonjour, vous allez constater quil contient 7 fichiers, tout a pour le prix
dun seul bonjour.

Maintenant quelques explications sur le programme. Voici comment se prsente en
gnral un programme en C :


1
En fait jai eu un problme avec Windows Vista, avec un refus total de compiler le moindre
programme. Faire un programme stupide de deux lignes pour afficher Bonjour, et en plus quil
ne marche pas, cest plutt frustrant. On peut en dduire quon est soi-mme stupide, ou bien
que cest une certaine informatique qui lest. Evidemment jai pens que ctait plutt la
deuxime ventualit. En fait si jai bien compris, Windows Vista est un centre de haute
scurit. Il refuse lexcution de programmes quil ne connat pas. Cest ce qui se passait avec la
laconique rponse de Code Blocks lors de la compilation du programme : permission denied
(permission refuse). Pour men sortir, jai d dsactiver le contrle sur les comptes
dutilisateur. Comme je suppose que je ne suis pas le seul qui cela puisse arriver, voici
comment faire : aller dans le panneau de configuration, puis dans la rubrique comptes
dutilisateur. L, aller ajouter ou supprimer des comptes dutilisateur. On tombe sur choisir le
compte modifier. Aller en bas de la page et cliquer sur ouvrir la page principale comptes
dutilisateur. Puis cliquer sur activer ou dsactiver le contrle des comptes dutilisateurs. Et une
fois arriv l, enlever la petite croix qui activait le contrle.
3



#include <stdio.h>
#include <stdlib.h>
main() { }

On commence par mettre quelques #include de fichiers .h o se trouvent certaines
fonctions du langage, celles que nous allons utiliser dans le programme, et qui sans cela
ne seraient pas reconnues. Il faut passer par l, se dire que pendant des annes on va
avoir sous les yeux, et taper des milliers de fois ce genre didioties. Cela permet au
moins de saiguiser les doigts en pensant autre chose. Puis vient le programme
principal int main(). Nouvelle plaisanterie : le main est considr comme une fonction
qui ne prend aucun argument (aucune variable) do les parenthses (), mais qui ramne
un nombre entier, do le int devant main. Cela explique la prsence du return 0 la fin
du programme. La fonction main ramne un entier, et cet entier est 0. Vous pouvez
mettre si vous prfrez return 1000, et le programme principal ramnera 1000 !
Dailleurs vous le verrez apparatre dans le message final sur lcran, aprs Bonjour. Si
cette situation vous exaspre, vous pouvez toujours simplifier, et crire le programme
suivant :

#include <stdio.h>
main()
{ printf( Un petit bonjour\n ) ;
}

Cela va marcher, mais vous recevrez un avertissement (warning) pour votre
mauvaise conduite.

En fait la seule chose intressante, cest de remplir lintrieur du programme
principal, entre les deux accolades {},
2
o vont se trouver une succession
dinstructions, toutes termines par un point virgule, comme vous avez dj pu le
constater. Cest l que tout se passe, car cest dans cette zone que le problme que lon
veut traiter sera crit et transmis par nos soins la machine, et se trouvera rsolu lors de
lexcution du programme, si tout va bien ! Evidemment avec notre affichage de
Bonjour, une chose que le moindre traitement de texte ferait beaucoup mieux et plus
simplement, on na pas lair malin.
3


Affichage sur lcran
Comme on la vu, on utilise la fonction printf(). Premier miracle, lorsquon excute
ce programme: lcran ne reste pas dsesprment noir. Bonjour apparat en haut
gauche de lcran, suivi dun message en anglais de fin dexcution du programme, o

2
Dans ce qui suit, nous omettrons souvent les #include, les dclarations de variables, et
mme le main() pour nous concentrer sur lessentiel: le contenu du programme principal.
3
Pour la petite histoire, signalons quil y a une vingtaine dannes le langage Visual C++ de
Microsoft cotait peu prs le prix de Word 2007 aujourdhui, et quil tait vendu avec une
brochure explicative de 250 pages, o le seul programme qui tait expliqu tait laffichage de
Hello world, sous une forme sophistique quand mme. Rsultats des courses : ventes
calamiteuses. On retrouve bientt la disquette Visual C++ dans des livres 200 F. On arrive
aujourdhui avec une version gratuite sur Internet.
4

lon vous dit aussi dappuyer sur une touche pour fermer la fentre. Si vous ne voulez
pas que votre Bonjour soit pollu par ce message, vous pouvez retarder lchance, en
faisant :
#include < stdio.h>
#include <conio.h> /* cest l que se trouve la fonction getch() */
main() { printf( Bonjour ) ; getch() ;}

La fonction getch() attend sagement que vous appuyiez sur une touche avant
denvoyer le message de fin.
4


Venons-en au symbole \n, que nous avions plac initialement dans notre
Bonjour\n . Aprs lcriture de Bonjour, il fait descendre dune ligne. Essayez par
exemple printf( Bonjour\nEt adios ). Si lon fait plutt printf( \n\nBonjour ),
Bonjour apparat aussi mais deux lignes en-dessous du haut de lcran. Si lon prfre
printf( Bonjour ), Bonjour apparat en haut de lcran, mais dcal vers la droite.
Cest dans la bibliothque stdio.h que se trouve dfinie la fonction printf(). Si on ne
lincluait pas au dbut du programme, on aurait un message derreur et un refus de
laffichage attendu.

Variable et assignation
La notion de variable est ambige. Au dpart cest une lettre ou un mot que lon
dclare par exemple en entiers (int), comme int a ; ou en entiers longs (long), ce qui
revient aujourdhui exactement au mme que les entiers courts !, ou en flottants (float)
quand on a un nombre virgule, tant entendu que la virgule est reprsente par un
point !
Il sagit en fait dun nom donn une case mmoire. Ce que lon met dedans peut
tre variable ou fixe, cela dpend de ce que lon veut. Si lon fait a=3 ; cela veut dire
que 3 est plac dans la case qui sappelle a. Le signe = est un symbole dassignation ou
daffectation : on affecte a la valeur 3. Tout btement on met 3 dans a, ou encore a
contient 3. Faisons ce programme :

main() {int a ; a=3 ; printf( %d , a) ; }

On voit safficher 3 sur lcran. A noter dans printf le symbole %d qui indique que
cest un entier qui va safficher, et cest celui qui est dans a.
Si lon veut mettre dans a un nombre virgule (un nombre dit flottant : float), on
fait :
float a ; a=3.14159 ; printf( %f ,a) ;
et on voit safficher 3.141590. Si lon veut seulement voir safficher 3.14 on peut
faire printf( %1.2f ,a). Le chiffre 2 de 1.2 indique que lon veut deux chiffres derrire

4
Dautres langages C que Code Blocks ont un dfaut supplmentaire : la fentre o
se trouve bonjour disparat aussitt et on na le temps de rien voir. Pour empcher cela,
une solution est de placer un getch(), qui attendra que vous appuyiez sur une touche
pour terminer lexcution et fermer lcran o se trouvait Bonjour.

5

la virgule. Quant au 1 de 1.2, il na pas grande importance ici, essayez avec 10.2, et il se
produira un dcalage droite de lcriture de 3.14 sur lcran.
On peut aussi changer le contenu de la case a, par exemple :
int a ; a=3 ; a=2*a ; Cette dernire instruction indique que la nouvelle valeur de a est
deux fois lancienne. Laffichage de a donnera 6.
Ajouter un, ou incrmentation
Faisons : i=0 ; i++ ; afficher i. On voit 1 sur lcran. Le fait dcrire i++ ajoute 1 la
valeur quavait i. Cest seulement un raccourci, on pourrait aussi bien faire i=i+1. De
mme si lon fait i -- avec le contenu de i qui diminue de 1. Et cela se gnralise : avec
i+=2 le contenu de la case i augmente de 2, ou avec i*=2 le contenu de la case i est
multipli par 2, etc.
Boucle et itration

La boucle for (i=0 ; i<10 ; i++) {} indique que la variable i va aller de 0 9 en
augmentant de 1 chaque fois ( cause du i++, qui peut scrire si lon prfre i=i+1, ce
qui indique qu chaque tape le nouvel i est lancien i augment de 1.
Imaginons que lon veuille afficher sur lcran les 10 premiers nombres entiers,
de 0 9. On fait :
int i ;
for(i=0 ; i<10 ; i++)
printf( %d ,i) ; /* ou bien for(i=0 ; i<10 ; i++) {printf( %d , i) ;}

Comme la boucle for() ne contient ici quune instruction, on nest pas oblig de
placer celle-ci lintrieur d accolades {}.
5
Profitons-en.
On veut maintenant avoir la somme des premiers nombres entiers, de 1 .
On utilise pour cela une variable de cumul, qui vaut 0 au dpart. Puis on lance une boule
qui chaque fois ajoute un nombre entier cumul. A la fin, cumul contient la somme
demande.
#include <stdio.h>
int main()
{int i, cumul, N ;
N=10 ; /* cest un exemple */ cumul=0 ;
for(i=1 ;i <=N ; i++) cumul + = i ; (ou si lon veut cumul= cumul+1 ; )
printf( %d , cumul) ;
return 0 ;
}

Premire source derreurs, si lon oublie de mettre cumul 0 au dpart, on sera
surpris des rsultats compltement faux que lon obtiendra, car le langage C est trs

5
Si lon fait : for(i=0 ; i<10 ; i++) printf( %d ,i) ; printf( %d ,i) ; on verra
safficher les nombres de 0 9, car la boucle for porte seulement sur le premier printf, puis on
verra safficher 10 cause du deuxime printf, celui-ci tant en dehors de la boucle. A
remarquer quaprs la boucle for avec i<10, i prend la valeur finale 10.
6

libre : si lon ne dit rien, cumul va quand mme contenir quelque chose, pour nous
nimporte quoi.

Calcul de factorielle , soit ! = (-1)(-2)3.2.1, tant un nombre
entier donn.
6
Aprs la condition initiale cumul=1, on a la boucle de cumul :

#include <stdio.h>
#define N 10 /* on va obtenir factorielle 10 */

int main()
{ int cumul,i ;
cumul=1 ;
for(i=2 ;i<=N ;i++) cumul*=i ;
printf( Factorielle %d = %d ,N,cumul) ;
return 0 ;
}

On voit apparatre la structure habituelle dun programme : conditions initiales, puis
boucle, puis affichage des rsultats.
La boucle for() est couramment utilise, quand on sait quune variable doit voluer
entre deux valeurs connues, avec un pas connu lui aussi. On peut aussi lutiliser sous
cette forme apparemment plus libre :

compteur=0 ; /* vous de mettre lenrobage habituel, les include, le main, etc. */
for( ;;)
{ afficher compteur ; /* pour afficher faites un printf ! */
if (compteur = = 10) break ; /* lgalit scrit = = , voir plus bas. Voir aussi plus bas le
test si alors, qui scrit if() */
compteur++ ;
}

On voit aussi safficher les nombres de 0 10. La boucle for(;;) na aucune
contrainte puisquelle ne porte sur rien. Elle se poursuivrait linfini si lon ne mettait
pas un break qui arrte la boucle ds que la variable compteur atteint une certaine
valeur. On utilise pour cela un test if (si en franais)
Assignation = et gal = =
Comme on le constate dans le programme prcdent, lgalit dans if ( compteur ==
10) scrit avec le double symbole = =. Ainsi, en langage C, lassignation scrit avec

6
La factorielle devient vite trs grande. Par exemple 20 ! est de lordre de 2 milliards de
milliards, soit 2.10
18
. Cest le moment de voir la limite du bon usage des entiers. Pour cela
reprendre le programme de la factorielle, en faisant la fois un calcul en entiers et un calcul en
flottants pour des valeurs croissantes de :
int cumul,i,N ; float cumulflottants ;
for(N=1 ; N<=20 ; N++) { cumul*=i ; cumulflottants * = i ;}
printf( Factorielle %3.d = %d %25.0f \n , cumul, cumulflottants) ;
On sapercevra qu partir de factorielle 13, les calculs en entiers deviennent compltement
faux (il apparat mme des valeurs ngatives). Do la rgle pratique : ne pas dpasser la limite
dun milliard pour les entiers (dclars int).
7

un = et lgalit avec ==. Largument avanc par les inventeurs du langage en faveur de
ce choix a t quon utilise beaucoup plus souvent lassignation que lgalit, et que
dans ces conditions mieux valait que lassignation scrive plus simplement et
rapidement que lgalit. En ce sens cest bien mieux que le langage Pascal qui crit
lgalit avec = et lassignation avec :=. Signalons toutefois quen Basic les deux
instructions scrivent toutes deux avec un =.
Les trois types de boucles
On a dj vu la boucle for(). Il existe deux autres types de boucles :
while() {}
do {} while() ;

A la diffrence du for() o sous la parenthse sont en gnral prcises la zone de
variation et lvolution des variables au coup par coup, la parenthse du while() ne
contient que le blocage final, il convient dajouter avant le while les conditions
initiales des variables concernes, et dans le corps {} de la boucle leur type
dvolution.
Exemple : La suite des puissances de 2

int compteur, u ;
compteur=0 ; u=1 ; afficher u ;
while(compteur<10) { compteur++ ; u = 2*u ; afficher u ; }

A chaque pas de la boucle, compteur augmente de 1, partir de compteur=0 mis
auparavant en conditions initiales, et la variable u est multiplie par 2 partir de u=1.
La suite des valeurs de u affiches donne les puissances successives de 2, de 2
0
=1
2
9
=512. Remarquons quau lieu de faire u = 2*u on pourrait crire u *=2.

On peut aussi bien faire :

int compteur, u ;
compteur=0 ; u=1 ; afficher u ;
do {compteur++ ; u= 2*u ; afficher u ; } while(compteur<10) ;

Mais ici on verra laffichage des puissances de 2
0
= 1 2
10
= 1024.

Les trois types de boucles sont interchangeables, mais dans certains cas on peut
prfrer juste titre utiliser lune plutt quune autre, comme on le verra loccasion.

Exercice 1

En 2008 une certaine population compte un million dindividus. Sa croissance
annuelle est de 10%. On dsire savoir :
1) Quel sera le nombre dindividus en 2060
2) En quelle anne elle dpassera les 100 millions dindividus.

8

Dabord on pose le problme, et cela na rien dinformatique. On considre que 2008
est lanne 0 (le point de dpart de lvolution comme si on enclenchait un
chronomtre), et quen cette anne 0 la population vaut u
0
= 1 o lunit 1 reprsente un
million dindividus. On a la rgle dvolution suivante : en lanne n, la population est
de u
n
et lanne suivante elle vaut u
n+1
= u
n
+ (10/100) u
n
car 10% signifie 10/100, soit
u
n+1
= 1,1 u
n
. On obtient une suite de nombres dfinie par la condition initiale u
0
= 1 et
la relation de rcurrence u
n+1
= 1,1u
n
. Maintenant on programme :

1) On veut connatre u
52
(population en 2060), ce qui permet dutiliser une boucle
for() :

float u ; int N, annee ;
u= 1. ; N=52 ;
for(annee=1 ; annee<=N ; annee++) u = 1.1 * u ;
afficher u.

On trouve quen 2060 la population atteint 142 millions dindividus.

2) On veut une boucle o lvolution se fait anne par anne jusqu ce que la
population dpasse la valeur 100, ce qui invite utiliser plutt un while :

int annee ; float u ;
u=1. ; annee=0 ;
while( u<=100.) {annee++ ; u=1.1*u ;}
afficher annee

On trouve que cest en 2057 que la population dpasse pour la premire fois 100
millions. Vrifiez-le.

Boucles imbriques

Que fait le programme suivant :

for(i=1; i<=5 ; i++) /* la grande boucle */
for(j=0 ; j<i ; j++) /* la petite boucle imbrique dans la grande */
afficher i

On voit safficher sur lcran 122333444455555. Pour chaque valeur de i dans la
grande boucle, la petite boucle se droule compltement. Par exemple lorsque i=3, la
petite boucle provoque laffichage de 3 trois fois de suite (j allant de 0 2).

Test si alors, sinon

Ce test scrit if () {} else {}, mais selon les problmes le sinon (else)
nest pas obligatoire. Au fond si lon rsume, tout problme trait sur ordinateur se
rsume des boucles et des tests. Prenons un exemple.

Imaginons que lon fasse 10000 tirages au hasard de nombres tous compris entre 0 et
9, et que lon veuille savoir combien parmi eux sont pairs et combien sont impairs. On
peut sattendre en avoir en gros moiti-moiti, ce qui permet de tester la validit du
9

gnrateur de nombres alatoires de notre langage C. On utilise pour cela la fonction
rand() qui ramne au hasard un nombre compris entre 0 et RAD_MAX=32767. Pour
obtenir un nombre au hasard compris entre 0 et 9, il suffit de faire rand()%10, ce qui
signifie que lon prend le reste de la division du nombre rand() par 10, ce reste tant
compris entre 0 et 9. Ensuite, pour savoir si un nombre n (0) est pair ou impair, il suffit
de chercher son reste lorsquon le divise par 2. Si le reste est nul, le nombre n est pair, et
sil vaut 1, le nombre est impair. Pour avoir ce reste dans la division par 2, on crit
n%2, qui se lit n modulo 2. Par exemple 13%2=1, 18%2=0. Cela revient enlever au
nombre un certain nombre de fois 2 pour arriver un nombre compris entre 0 et 1. Plus
gnralement n%p ramne un nombre compris entre 0 et p-1, aprs avoir enlev p
autant de fois quil le faut n.

Revenons notre problme, qui se traite ainsi :

#include <stdio.h>
#include <stdlib.h> /* pour la fonction rand() */

int main()
{
int i, chiffre,nombrepairs, nombreimpairs ;
nombrepairs=0 ; nombreimpairs=0 ; /* les deux variables de cumul */
for(i=0; i<10000 ; i++)
{ chiffre = rand()%10 ;
if (chiffre%2 ==0) nombrepairs ++ ; else nombreimpairs ++ ;
}
printf( Nombres des pairs :%d et des impairs : %d\n , nombrepairs, nombreimpairs) ;
return 0 ;
}

Mais excutons ce programme plusieurs fois de suite. On constate que lon obtient
toujours les mmes rsultats. En fait la srie des 1000 nombres alatoires na pas chang
dun iota. Pour viter ce problme o le hasard fait cruellement dfaut, on appelle au
dbut du programme la fonction srand(time(ULL)) qui relie le gnrateur de nombres
alatoires lheure quil est. Quand on fait plusieurs excutions du mme programme,
le temps a chang, et le gnrateur alatoire ne dmarre pas avec les mmes nombres,
donnant ainsi des sries de nombres diffrentes.

#include <stdio.h>
#include <stdlib.h> /* pour la fonction rand() */
#include <time.h> /* pour la fonction srand() */
int main()
{ int i, chiffre,nombrepairs, nombreimpairs ;
nombrepairs=0 ; nombreimpairs=0 ; srand(time (NULL)) ;
for(i=0; i<10000 ; i++)
{ chiffre = rand()%10 ;if (chiffre%2 ==0) nombrepairs ++ ; else nombreimpairs ++ ;}
printf( Nombres des pairs :%d et des impairs : %d\n , nombrepairs, nombreimpairs) ;
return 0 ;
}




10

Tableaux

En gnral, on na pas une ou deux variables traiter dans un programme. On a une
collection dobjets, en grand nombre. On est alors amen les placer lun aprs lautre
dans un tableau de cases successives. Si lon a nombres entiers mettre, on dclare le
tableau a[] dans lequel les nombres vont tre placs. Chaque case est numrote de 0
-1. Insistons : quand un tableau a pour longueur , sa dernire case est numrote -1.
Un programme consiste alors parcourir le tableau, avec une boucle for(i=0; i< ; i++)
en procdant des transformations ou recherches selon le problme traiter. Diverses
situations peuvent se prsenter :
Soit le tableau nous est impos au dpart, et cest nous de le remplir, par
exemple :

int a[10] ;
a[10]={2, -4, 3, 5, -7, 8, -8, 1, 7, -3} ;
ou si lon prfre, on fait : a[0]=2; a[1]=-4 ; a[2]=3 ; a[9]=-3.

Imaginons alors quon nous demande le nombre dlments ngatifs dans ce tableau.
On fera le parcours :

compteurnegatifs=0 ;
for(i=0 ; i<N ; i++) if (a[i]<0) compteurnegatifs++ ;
afficher compteurnegatifs

Ou bien le tableau est rempli automatiquement par le programme. Voici un
exemple :
On nous demande dafficher les carrs des nombres pairs successifs partir de 2.
Si =5, on veut connatre les valeurs de 2
2
,4
2
,6
2
,8
2
,10
2
. On peut enregistrer ces
calculs dans un tableau puis on affiche les rsultats :

for(i=1 ; i<=N ; i++) { nbpair=2*i ; carre[i]=nbpair*nbpair ;}
for(i=1 ; i<=N ; i++) printf( %d , carre[i]) ;

Remarquons quen faisant cela le tableau doit tre au pralable dclar sur une
longueur +1, en faisant int a[+1]. Les carrs qui nous concernent sont dans les cases
de 1 , la case 0 ne nous intresse pas.

Maintenant on veut connatre les sommes partielles de ces carrs, soit 2
2
, 2
2
+4
2
,
2
2
+4
2
+6
2
, 2
2
+4
2
+6
2
+8
2
, 2
2
+4
2
+6
2
+8
2
+10
2
. On va les enregistrer dans un tableau int
sommepartielle[+1] :

cumul=0 ;
for(i=1 ; i<=N ; i++)
{ nbpair=2*i ; carre=nbpair*nbpair ; cumul+=carre ; sommepartielle[i]=cumul;}
for(i=1 ; i<=N ; i++) printf( %d , sommepartielle[i]) ;

Remarquons que si le problme se rduisait cet affichage, on naurait pas vraiment
besoin dutiliser un tableau. Mais imaginons quon nous demande le nombre de termes
prendre dans cette somme de carrs pour atteindre ou dpasser le quart de la somme
totale des carrs. Par exemple, pour =5, avec les sommes partielles de carrs
obtenues : 4, 20, 56, 120, 220, il faut prendre les trois premiers carrs, dont la somme
11

vaut 56, pour dpasser le quart de la somme totale, soit 220/4= 55. Dans ce cas, lusage
dun tableau savre plus utile. Voici le programme complet :

#include <stdio.h>
#include <conio.h>
#define N 5 /* ce #define provoque le remplacement de N par 5 dans tout le programme */
main()
{ int i, nbpair, carre, sommepartielle[N+1], cumul, quartdutotal ;
cumul=0 ;
for(i=1 ; i<N ; i++)
{=2*i ; carre=nbpair*nbpair ; cumul+=carre ; sommepartielle[i]=cumul; }
quartdutotal= sommepartielle[N] / 4 ;
i=1 ; while ( sommepartielle[i] < quartdutotal) i++ ;
printf( Pour N=%d, le nombre de termes pour dpasser le quart du total est %d , N, i) ;
}

Fonctions

Le langage C est base de fonctions. En ce sens il est unifi et cest un avantage par
rapport dautres langages qui mlent les fonctions et les procdures (des blocs
dinstructions) comme le Pascal ou le Basic, ou feu le Logo.
Quant elle est gnralise, la notion de fonction devient trs lastique. Il y a les
vraies, les vraies-fausses, les fausses Au sens strict, une fonction prend une variable x
et ramne une valeur y, ce qui scrit y = f(x), cest--dire y est fonction de x.
Commenons par voir comment se prsente une telle fonction classique en C.

Imaginons que lon veuille calculer les valeurs du polynme P(x) = x
3
2x
2
+ 4x 3
pour les valeurs entires de x comprises entre 5 et 5. Cela peut se programmer ainsi,
mme si on peut le faire plus simplement :

#include <stdio.h>
int polynome(int x) ; /* on dclare la fonction avant le main() */
main()
{ int x, y ;
for(x=-5 ; x<=5 ; x++) { y = polynome(x) ; printf( x=%d y=%d \n ,x, y ;}
return 0 ;
}

int polynome(int x)
{ int valeur ;
valeur = x*x*x 2*x*x + 4*x 3 ;
return valeur ;
}

Prenons la fonction polynome(). On constate que sa variable x doit tre dclare, ici
en entiers, par int x, et que la valeur entire quelle ramne doit tre annonce devant
elle, do int polynome(). Dautre part, la fin du corps de la fonction, il est oblig de
dire quelle ramne une valeur entire, do return valeur. Cest cette valeur retourne
qui est mise dans le y du programme principal, puis affiche. Enfin il est indispensable
de dclarer la fonction au dbut du programme, avant le main().

12

Mais il existe dautres types de fonctions, notamment des fonctions qui ne prennent
aucune variable, et ramnent quand mme une valeur, comme par exemple notre
fameux int main(), ou rand() qui ramne un entier entre 0 et 32767. Il y a encore des
fonctions qui prennent des variables mais ne ramnent rien. On les dclare ainsi, par
exemple : void fonction (int u, int v) , une fonction de deux variables, et o void indique
que rien nest ramen. Il ny a alors aucun return mettre lintrieur de la fonction.
Que fait une telle fonction ? Elle se contente dafficher des rsultats sur lcran ou dy
dessiner des objets, et cest dj beaucoup. Mieux encore, il existe des fonctions qui ne
prennent aucune variable et qui ne ramnent rien. Elle sont dclares sous la forme void
fonction(void). De telles fonctions ne sont autres que des procdures englobant un bloc
dinstructions, elles servent de prte-nom (ou dtiquette ou de label) pour indiquer ce
que lon veut raliser.

Variables locales et globales

Une variable locale est dclare au dbut dune fonction (cette fonction pouvant
notamment tre le programme principal). Elle nagit alors qu lintrieur de cette
fonction. Par exemple si une variable int i est dclare dans le main() et que lon a aussi
une variable int i dclare dans une autre fonction, cela donne deux variables
compltement indpendantes et diffrentes lune de lautre, malgr leur nom identique.
Par contre, une variable globale est dclare au dbut du programme, avant le main()
et les autres fonctions ventuelles du programme. Alors elle agit dans toutes les
fonctions. Il y a aussi un autre avantage : lorsque lon dclare un tableau a[] en global,
il est automatiquement mis 0 (par contre sil est dclar lintrieur du main(), il
contient nimporte quoi, et si on veut linitialiser 0, il faut le parcourir en mettant
chaque case 0).

Exercice 2 : coupes dun paquet de cartes

On a un paquet de cartes, on va le couper en deux morceaux de longueur L
1
et L
2
,
aucun ntant vide, puis on va le reconstituer en intervertissant les deux morceaux.

1) On fait une coupe au hasard. Programmer cette opration de coupe

On va dabord noter les cartes du paquet 0, 1, 2, , -1. Il sagit l dune
conversion toute simple : si la premire carte du paquet est las de cur, on dcide de le
noter 0, et ainsi de suite. Ainsi simplifi, le paquet est plac dans un tableau a[].
Ensuite on va numroter la coupure avec un nombre C compris entre 0 et -2, et choisi
au hasard. Une coupure numrote C signifie que le premier morceau va de lindice 0
C dans le tableau a[], et que le deuxime va de C+1 -1. Dans ces conditions chacun
des deux paquets a au moins une longueur gale 1.

for(i=0 ; i<N ; i++= a[i]=i ;
C=random(N-1) ; L1=C+1 ; L2=N C 1 ;
for(i=0 ;i<N ; i++) if (i<=C) paquet1[i]=a[i] ; else paquet2[i L1]=a[i] ;
for(i=0 ; i<N ; i++) if (i<L2) a[i]=paquet2[i] ; else a[i]=paquet1[i L2] ;
afficher le paquet mlang a[]

2) Pour mlanger les cartes, on se propose de rpter cette opration de coupe un
certain nombre de fois. Programmer. Que va-t-il se passer ?
13


Evidemment lessentiel cest le programme prcdent. Il suffit de le rpter un
certain nombre de fois (dans le programme qui suit nbdecoupes vaut 10). Pour montrer
comment on intgre des fonctions au programme principal main(), on a plac
lopration de coupe dans la fonction couper(), et laffichage dans la fonction afficher().
Voici le programme complet :

#include <stdio.h>
#include <conio.h>
#include <stdlib.h> /* pour le gnrateur rand() de nombres alatoires */
#include <time.h> /* pour la relance srand() du gnrateur alatoire */

#define N 32
#define nbcoupes 10
int a[N], paquet1[N-1], paquet2[N-1], L1, L2; /* variables globales, qui concernent toutes
les fonctions */
void couper(void); /* deux fonctions ne prenant aucune variable et ne ramenant rien */
void afficher(void);

main()
{
int i,coupe; /* variables locales */
srand(time(NULL));
for(i=0; i<N; i++) a[i]=i;
afficher(); /* le tableau initial */
for(coupe=1; coupe<=nbcoupes; coupe++) couper(); /* les coupes rptes */
afficher(); /* rsultat aprs les coupes */
}

void couper(void)
{ int i, C;
C=rand()%(N-1); L1=C+1; L2=N-C-1;
for(i=0; i<N; i++) if (i<=C) paquet1[i]=a[i]; else paquet2[i-L1]=a[i];
for(i=0; i<N; i++) if (i<L2) a[i]=paquet2[i]; else a[i]= paquet1[i-L2];
}

void afficher(void)
{ int i;
for(i=0;i<N;i++) printf("%d ",a[i]);
printf("\n"); getch();
}

Que constate-t-on ? On a beau multiplier les coupes, on a toujours la fin un
dcalage cyclique des cartes, par exemple pour =5, avec au dpart 012234, on va par
exemple obtenir 23401. Tout se passe comme si lon navait fait quune seule coupe. Ce
nest pas un vritable mlange. La machine sest comporte comme un ordinateur .
On nen veut pas.

3) Modifier lopration de mlange pour quaprs lavoir effectue un certain
nombre de fois le paquet soit vraiment mlang.

Pour casser le quasi ordre indfiniment retrouv de la mthode prcdente, et crer
un vritable dsordre, on dcide par exemple de mettre la dernire carte du deuxime
14

morceau en premier, puis on met le reste du deuxime morceau, suivi du premier
morceau. Et lon rpte cela un certain nombre de fois, par exemple autant de fois quil
y a de cartes. On obtient bien la fin une permutation quelconque des cartes.

Il suffit de reprendre le programme prcdent, et aprs la coupure en deux paquets
dans la fonction couper(), de modifier la fin la reconstruction du paquet a[] en
faisant :

a[0] = paquet2[L2 1] ;
for(i=1 ; i<N ; i++) if (i < L2) a[i] = paquet2[i 1] ; else a[i] = paquet1[i L2] ;

Conclusion provisoire

Voil pour cette petite initiation au langage C. Beaucoup de choses nont pas t
dites, mais avec ce bagage minimal on peut traiter de nombreux problmes sur
ordinateur. Dautres choses non dites sont sous-jacentes travers les exemples de
programmes. Autre limite de cette initiation : nous avons toujours choisi des exemples
base de nombres. Cela peut sembler restrictif, mais lordinateur nest-il pas avant tout
un computer, cest--dire un computeur, un calculateur ? Et dans de nombreux cas,
quand on travaille avec des lettres, on a intrt les convertir en nombres. Enfin, il
existe plusieurs langages C et aussi des systmes dexploitation diffrents. Cela
provoque quelques variations et demande des adaptations (par exemple jutilise getch()
sous Windows, mais sous Unix on ne lutilise pas).
A lavenir, il reste une chose essentielle raliser : ajouter une bibliothque
graphique. La frustration suprme, avec les langages C basiques daujourdhui, cest de
ne pas avoir les moyens de dessiner un point sur un cran dordinateur. Quand tout nest
quimage !

Exercice 3 : Calcul dune calotte sphrique

Sur une sphre de rayon R, on prend une calotte sphrique de hauteur H (avec H
entre 0 et R), dont on veut dterminer le volume suivant les valeurs de H.


A gauche, la calotte sphrique de
hauteur H, et droite son dcoupage
en tranches (3 tranches ici, en fait on
en fera des dizaines ou des centaines)



Dcoupons la calotte en tranches toutes de mme paisseur dx. Chaque tranche est
assimile un cylindre de hauteur dx, et dont la base circulaire a
un rayon h, dpendant de labscisse x, distance entre le centre de
la sphre et celui de la base circulaire du cylindre. Cette abscisse
x est comprise entre R-H et R, et lon a h
2
+x
2
=R
2
(Pythagore),
do h
2
= R
2
x
2
. Le volume dune tranche cylindrique situe
labscisse x est gal laire de la base circulaire h
2
multiplie
par la hauteur dx. Le volume de la calotte est la somme des
15

volumes de toutes les tranches, soit

, o x prend les valeurs comprises


entre R-H et R en augmentant chaque fois de dx.

Do le programme, o lon utilise une variable de cumul volume qui vaut 0 au
dpart, et qui augmente chaque tape du volume dune tranche, ce qui donne la fin le
volume de la calotte :

#include <stdio.h>
#define pi 3.1416
float H,R,volume,x,dx; /* dclaration des variables en flottants (nombres virgule) */

int main()
{ R=1.; H=0.5; dx=0.0001; /* valeurs prises comme exemple */
volume=0.;
for(x=R-H; x<R; x+=dx) volume + = pi*(R*R-x*x)*dx;
printf("Volume de la calotte (pour R=%3.1f et H=%3.1f) = %3.3f\n\n",R,H,volume);
return 0;
}

Remarque : Nous venons de raliser ce qui est la source du calcul intgral. Le
volume de la calotte sphrique est


par
intgration. Le calcul donne finalement H
2
(R -

). On peut comparer les rsultats


obtenus par le programme prcdent et par cette formule thorique, en ajoutant cette
ligne au programme prcdent :

volume=pi*H*H*(R-H/3.); printf("Volume thorique = %3.3f\n\n",volume);

Dans les deux calculs, on trouve pour lexemple choisi un volume gal 0,655. Cest
plutt rconfortant.


Et maintenant la libert de dessiner


Rappelez-vous o on en tait rest dans notre art de programmer. On pouvait voir
safficher des millions de chiffres ou de caractres sur lcran. Mais interdiction de
dessiner un seul point volont, encore moins le moindre cercle ou la moindre image.
Nouvel avatar de la pense scuritaire si chre nos politiciens et nos philosophes.
Alors remettons la main dans le cambouis, et installons SDL,
7
qui va nous permettre de
faire du graphisme, cest--dire de mettre des images sur notre cran, ce qui est la
moindre de choses.




7
Encore un peu de jargon : SDL est une API, une interface de programmation (application
programming interface), cest--dire pour les profanes une bibliothque de fonctions,
graphiques et autres, qui vont se greffer sur notre machine informatique, comme un pace maker.
Ce nest pas la seule possibilit, il y a aussi Allegro, DirectX, etc. si vous prfrez.
16

Tlchargement de SDL sous Windows Vista

Allez sur http//www.libsdl.org et cliquez sur download SDL 1.2. Dans la liste des
propositions, descendez sans complexe jusqu la rubrique developpement librairies
(bibliothques de dveloppement) et cliquez sur SDL-devel-1.2.13-mingw32.tar.gz. Le
fichier compress apparat sur votre bureau. Pour le dcompresser, procdez son
extraction grce un logiciel comme winrar ou 7zip. Dans le fichier SDL obtenu
seuls trois rpertoires nous concernent : bin, include, et lib. Vous allez prendre leurs
contenus et les copier dans leurs quivalents respectifs bin, include et lib qui se trouvent
dans votre programme CodeBlocks\MinGW. Notamment le rpertoire SDL (soit
SDL\include\SDL) qui est le seul contenu de SDL/include comme vous pouvez le
constater, va se retrouver dans CodeBlocks\MinGW\include, et vous aurez les fichiers .h
du SDL dorigine qui se retrouvent dans CodeBlocks\MinGW\include\SDL. Mais pour
viter les ennuis que jai eu par la suite, vous allez copier une deuxime fois tous les
fichiers .h de SDL\include directement dans CodeBlocks\MinGW\include (ceux-l
mmes qui taient dj dans CodeBlocks\MinGW\include\SDL). Enfin vous prenez le
fichier SDL.dll qui est dans le SDL\bin dorigine et vous le balancez dans
c:\windows\system32.

Premier programme : lcran noir

Retournons dans notre diteur Code Blocks, et demandons comme dhabitude :
create a new project. On tombe sur une fentre ew from template. A lintrieur
cliquez sur SDL project (et non plus sur Console application). On va vous demander de
donner un titre votre projet, prenez par exemple ecrannoir. et juste aprs on va vous
demander o se trouve SDL. Ecrivez alors C:\Program Files\CodeBlocks\MinGW,
8
et
continuez jusqu finish. Votre projet ecrannoir se trouve dans votre espace de travail
(workspace). Tapez sur Sources, puis sur le main.cpp qui va apparatre, et qui est dj
rempli. Par acquit de conscience, excutez ce programme qui vous est gracieusement
offert pour constater que a marche ! Le logo Code Blocks apparat sur un fond dcran
noir. Fermez cette fentre (avec la croix X) et jetez un il sur le programme main.cpp.
On ny comprend rien et cest tant mieux. On constate quand mme un grand nombre de
scurits mises en place, juste pour nous faire peur. On va sempresser de les
supprimer ! Voil ce que lon peut se contenter de mettre dans notre premier
programme, pour voir la fentre cran apparatre, ici rduite un rectangle noir :

#include <SDL/SDL.h> /* dornavant indispensable, pour disposer des .h de SDL */

#define OUI 1 /* utilis dans la fonction pause() */
#define NON 0
void pause(void) ;

int main (int argc , char ** argv) /* crire le main ainsi dsormais */
{
SDL_Surface * ecran ; /* dclaration de la variable ecran */
SDL_Init(SDL_INIT_VIDEO) ;
ecran= SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE) ;


8
Cest l que javais eu un problme dans un premier temps, et la raison pour laquelle jai
copi une deuxime fois les fichiers .h du include de SDL. Si vous trouvez mieux
17

SDL_WM_SetCaption( ECRAN NOIR ,NULL) ; /* juste une fioriture pour voir crit
ECRA OIR sur la bordure en haut de notre fentre cran*/
SDL_Flip(ecran) ;

pause() ;
return 0 ;
}

void pause()
{ int continuer=OUI;
SDL_Event event;
9

while(continuer= = OUI)
{ SDL_WaitEvent(&event);
if (event.type==SDL_QUIT) continuer=NON;
}
}

On commence par dclarer la variable ecran comme tant ladresse dune surface,
cest--dire ladresse de la premire case que cette surface va occuper dans la mmoire
de lordinateur.
10

On met en conditions initiales linstallation du mode graphique, grce
SDL_Init(SDL_IIT_VIDEO). Puis on demande la mise en place en mmoire de la
fentre-cran, grce SDL_SetVideoMode, en indiquant que cette fentre va avoir une
longueur de 800 pixels, une largeur de 600 pixels, et o la couleur de chaque pixel va
occuper 32 bits. Cette fonction ramne ladresse ecran, indiquant la place o se trouve
la fentre cran dans la mmoire, ce qui permettra daccder celle-ci en cas de besoin.
Comme on ne met rien dans cette zone de mmoire, on aura une fentre- cran noire sur
notre cran dordinateur. Mais pas encore ! Si on ne fait rien dautre, visiblement rien ne
se passe. Encore faut-il balancer sur lcran ce qui tait jusque l dans la mmoire
vido, do le SDL_Flip(ecran). Cela ne suffit toujours pas, la fentre-cran noire ne
faisant quune apparition fugace avant de disparatre. Pour quelle reste fige sur lcran
de lordinateur, il convient dajouter une pause. Do la fonction dattente pause() o
une boucle while ne cesse de tourner tant quun vnement extrieur ne se produit pas.
Et le seul vnement qui est pris ici en compte est SDL_QUIT, qui se produira ds que
nous cliquerons sur la petite croix en haut droite de notre fentre cran. Alors
seulement la boucle while sarrte, et la fentre cran va finalement disparatre.

Extension 1: Plaquer une surface rectangulaire rouge sur lcran

Mettons maintenant un peu de couleur.

9
Au lieu dappeler cette variable event, vous pouvez lappeler evenement, mais alors il
faudra faire ce remplacement partout dans la suite, notamment mettre WaitEvent(&evenement),
puis if(evenement.type
10
La programmation SDL utilise de nombreux pointeurs , savoir des numros de cases
mmoires (des adresses). Do lapparition dtoiles *, de & et de flches -> (utiliser les touches
et >). Cela sexpliquera plus tard. Pour le moment se contenter de recopier !


18

Dans un premier temps nous allons faire en
sorte que la fentre-cran soit en blanc (au lieu
de rester noire). Pour cela, aprs avoir dclar
la variable blanc comme un entier sur 32 bits
(Uint32), nous appelons la fonction
SDL_MapRGB (ecran->format, 255, 255, 255)
o les trois 255 indiquent que les trois couleurs
de base, rouge, vert et bleu, sont mises leur
valeur maximale, cette combinaison donnant
alors du blanc. La fonction ramne le numro
donn cette couleur blanche. Puis on
demande de remplir le rectangle de la fentre-cran en blanc, grce SDL_FillRect
(ecran, ULL, blanc).
Rajoutons cela au programme prcdent :

Uint32 blanc=SDL_MapRGB(ecran->format,255,255,255);
SDL_FillRect(ecran,NULL,blanc);

et la fentre-cran est devenue blanche.
Allons plus loin. Nous voulons maintenant installer un rectangle rouge au centre de
la fentre-cran blanche. Comme il sagit toujours de rectangles, les fonctions
prcdentes vont encore nous servir. Mais maintenant il sagit dun nouveau rectangle
(newrectangle) lintrieur de celui de lcran et il convient de donner sa position. Do
lapparition de nouvelles fonctions. Au lieu de SDL_SetVideoMode, on fait
SDL_CreateRGBSurface (attention cette fonction possde huit arguments, les quatre
derniers nayant pas dintrt pour nous sont mis 0). Avec position.x et position.y on
se donne les coordonnes du sommet en haut gauche du nouveau rectangle. Tout cela
est indiqu ci-dessous dans la partie mise en gras du programme. Une fois le nouveau
rectangle install, avec ses dimensions de 200 sur 100 ici, il convient de lappliquer
dans la position demande sur la fentre-cran, do la fonction :
SDL_BlitSurface(newrectangle,ULL ,ecran,&position). A la fin il est recommand
de librer la place en mmoire prise par le nouveau rectangle, avec
SDL_FreeSurface().Voici le programme final :

#include <SDL/SDL.h>
#define OUI 1
#define NON 0
void pause();
int main (int argc, char ** argv )
{
Uint32 rouge, blanc;
SDL_Surface * ecran , * newrectangle;
SDL_Rect position;
SDL_Init(SDL_INIT_VIDEO);
ecran=SDL_SetVideoMode(800, 600, 32,SDL_HWSURFACE);
newrectangle= SDL_CreateRGBSurface(SDL_HWSURFACE,300,200,32,0,0,0,0);

SDL_WM_SetCaption("RECTANGLE ROUGE SUR FOND BLANC",NULL);

blanc=SDL_MapRGB(ecran->format,255,255,255);
SDL_FillRect(ecran,NULL,blanc);

19

position.x=400-150;position.y=300-100 ;
rouge=SDL_MapRGB(ecran -> format, 255, 0, 0);
SDL_FillRect(newrectangle,ULL,rouge);
SDL_BlitSurface(newrectangle,ULL,ecran,&position);

SDL_Flip(ecran);
pause(); /* rutiliser la fonction dj fabrique dans le programme prcdent */
SDL_FreeSurface(newrectangle);
return 0;
}

On peut ainsi plaquer (Blit) autant de rectangles que lon dsire sur la fentre-cran
qui est dj un rectangle. Ce que nous allons faire dans ce qui suit.

Extension 2 : Dgrad cyclique de couleurs sur lcran

On va tracer des lignes verticales sur lcran, chacune avec sa couleur. Une ligne
verticale nest autre quun rectangle de longueur 1 de largeur 600 (la hauteur de la
fentre-cran). La longueur dcran va tre 3x256= 768. Pour chaque valeur de i allant
de 0 767, on va faire :

ligne[i]=SDL_CreateRGBSurface(SDL_HWSURFACE,1,600,32,0,0,0,0);

Et maintenant les couleurs:














Comme indiqu sur le dessin
ci-contre, chacune des trois
couleurs R, G, B prend tour de
rle la prdominance. Par exemple
le rouge R dmarre 255 (rouge
vif), les autres couleurs tant 0,
puis il diminue de un en un
jusqu attendre la valeur 0 sur la
colonne 256. Ensuite le rouge
reste bloqu 0 jusqu la colonne 512, puis il remonte de un en un jusqu 255 sur la
dernire colonne 767. Les deux autres couleurs suivent la mme volution mais
dcales de 256. On obtient finalement une palette cyclique de couleurs o les trois
20

couleurs de base senchanent avec des dgrads intermdiaires. Do cette partie de
programme :

for(i=0;i<768;i++)
{ if (i<256) couleur=SDL_MapRGB(ecran->format,255-i,i,0);
else if (i<512) couleur=SDL_MapRGB(ecran->format,0,255-(i-256),i-256);
else couleur=SDL_MapRGB(ecran->format,i-512,0,255-(i-512));
}

Dans cette mme boucle, il reste se donner la position de chaque colonne dont on
connat maintenant la couleur, puis remplir la surface correspondante avec cette
couleur, et enfin plaquer (blit) cette colonne sur la fentre-cran. Le programme en
dcoule :

#include <SDL/SDL.h>
#define OUI 1
#define NON 0
void pause();
int main ( )
{ Uint32 couleur ;
SDL_Surface *ecran, *ligne[768] ;
SDL_Rect position;
int i;

SDL_Init(SDL_INIT_VIDEO);
ecran=SDL_SetVideoMode(768, 600, 32,SDL_HWSURFACE);

for(i=0;i<768;i++)
ligne[i]=SDL_CreateRGBSurface(SDL_HWSURFACE,1,600,32,0,0,0,0);

SDL_WM_SetCaption("DEGRADE SDL",NULL);

for(i=0;i<768;i++)
{
position.x=i; position.y=0;
if (i<256) couleur=SDL_MapRGB(ecran->format,255-i,i,0);
else if (i<512) couleur=SDL_MapRGB(ecran->format,0,255-(i-256),i-256);
else couleur=SDL_MapRGB(ecran->format,i-512,0,255-(i-512));
SDL_FillRect(ligne[i],NULL,couleur);
SDL_BlitSurface(ligne[i],NULL,ecran,&position);
}

SDL_Flip(ecran);
pause(); /* toujours cette mme fonction recopier */
for(i=0;i<768;i++) SDL_FreeSurface(ligne[i]);
return 0;
}
On vient de voir comment notre logiciel SDL permet de tracer des rectangles dans un
rectangle dcran. On pourrait gnraliser cela au coloriage des pixels, un pixel ntant
autre quun rectangle de un sur un. Mais il vaut mieux sy prendre autrement.



21

Dessiner des points

Comment donner une couleur donne un pixel de la fentre-cran situ labscisse
xe et lordonne ye (rappelons que laxe des ye est dirig vers le bas) ? On va fabriquer
pour cela la fonction putpixel(int xe, int ye, Uint32 couleur).







La fentre-cran, telle quon la voit, se trouve dans la mmoire de lordinateur, avec
une certaine adresse initiale qui est ecran->pixels, o ecran vient de la mise en place du
mode vido, comme on la dj vu :

ecran = SDL_SetVideoMode(800, 600, 32, SDL_SWSURFACE);

La mmoire ressemble une rue trs longue, borde de cases ayant des adresses
(seulement des numros puisque la rue est unique) qui se suivent. Il sagit de passer de
la zone rectangulaire de lcran cette ligne de cases mmoires. Imaginons que lon
veuille donner la couleur c au point (200, 3). Ce point va se trouver dans la case numro
ecran->pixels + 3 x 800 + 200. Il suffit de mettre c dans le contenu de cette case.








void putpixel(int xe, int ye, Uint32 couleur)
{ Uint32 * numerocase ;
numerocase = (Uint32*)(ecran->pixels) + xe + ye * ecran->w ;
*numerocase = couleur; /* la case numrote par numerocase va contenir couleur */
}

Exemple 1 : brouillage dcran

Nous allons dessiner une nue de 10 000 points sur la fentre-cran, ces points tant
placs au hasard, avec une couleur elle aussi alatoire. Et nous allons rpter cela un
millier de fois de faon voir sur lcran ce nuage de points en perptuel mouvement,
comme une sorte de brouillage tel quon le voit sur un tlviseur quand on narrive pas
capter une chane.
Pour la premire fois nous utilisons une fonctionnalit dj toute prte de SDL qui
est le double buffer. Pendant quune image est affiche sur lcran (grce Flip()), la
suivante se prpare en arrire-plan en mmoire. Do une succession fluide dimages,
sans -coups. On va avoir ici en succession : affichage de la nue de points - effaage
de lcran - nouvelle nue - effaage - . Pour cela il suffit dannoncer au dpart :

22

ecran = SDL_SetVideoMode(800, 600, 32, SDL_SWSURFACE | SDL_DOUBLEBUF);

Le programme sensuit:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <SDL/SDL.h>
#define OUI 1
#define NON 0
void brouillage(void);
void putpixel(int xe, int ye, Uint32 couleur);
void pause(void);
SDL_Surface* ecran;

int main (int argc, char ** argv )
{
int i,noir;
srand(time(NULL));
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode(800, 600, 32, SDL_SWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("BROUILLAGE",NULL);
noir=SDL_MapRGB(ecran->format,0,0,0);

for(i=0;i<1000;i++)
{ brouillage();
SDL_Flip(ecran);
SDL_FillRect(ecran,NULL,noir); /* effaage de l'cran, en le coloriant en noir */
}
pause();
return 0;
}

void putpixel(int xe, int ye, Uint32 couleur)
{ *( (Uint32*)(ecran->pixels)+x+y*ecran->w ) = couleur;
}

void brouillage(void)
{ int i,xe,ye; Uint32 rouge,vert,bleu,color;
for(i=0;i<10000;i++)
{ xe=1+rand()%798; ye=1+rand()%598;
11

rouge=rand()%256; vert= rand()%256; bleu=rand()%256;
color=SDL_MapRGB(ecran->format, rouge,vert,bleu);
putpixel(xe,ye,color); putpixel(xe+1,ye,color); /* on dessine en fait 5 pixels pour faire
une petite croix */
putpixel(xe-1,ye,color); putpixel(xe,ye+1,color); putpixel(xe,ye-1,color);
}
}


11
Labscisse xe va de 1 798. Comme on dessine en fait une petite croix, on aura des
points labscisse 0 et dautres 799, ce qui constitue les limites de la fentre-cran.
Attention, si lon fait par exemple xe=1+rand()%799, des points vont sortir de lcran, et le
programme va bloquer.

Exemple 2: Trac dune courbe

Maintenant que nous savon
courbes point par point, partir de leur quation sous la forme
on se contente de cette mthode de trac, mme si, pour prserver la continuit du
dessin, il convient de prendre un trs grand nombre de points. La seule chose faire est
de passer de la zone calcul, celle de
units au plus, la zone cran o les coordonnes sont des nombres entiers pouvant
atteindre des centaines dunits, do la ncessit de procder un changement
dchelle, avec la mise en place dun zoom.


#include <stdlib.h>
#include <SDL/SDL.h>

SDL_Surface* ecran;

void putpixel(int xe, int ye, int co
void repere(void);
void courbe(void);
int xo=400,yo=300,zoomx=150,zoomy=100;
Uint32 rouge,blanc,noir;

int main (int argc, char* argv[])
{
SDL_Init( SDL_INIT_VIDEO );
ecran = SDL_SetVideoMode(800, 600, 32,SDL_HWSURFACE);
rouge=SDL_MapRGB(ecran
blanc=SDL_MapRGB(ecran
noir =SDL_MapRGB(ecran

SDL_FillRect(ecran,0,blanc);
repere(); courbe();
SDL_Flip(ecran);
pause();
return 0;
}

void putpixel(int xe, int ye, int couleur)
{ *((Uint32 *)ecran->pixels+xe+ye*ecran
}

void repere(void)
{
int i;
for(i=-300;i<300;i++) putpixel(xo+i,yo,rouge);
for(i=-300;i<300;i++) putpixel(xo,yo+i,rouge);
for(i=-10;i<=10;i++) putpixel(xo+zoomx,yo+i,rouge);
for(i=-10;i<=10;i++) putpixel(xo+i,yo
}

void courbe(void)
{
float x,y; int xe,ye;
Exemple 2: Trac dune courbe
Maintenant que nous savons colorier des pixels sur lcran, nous pouvons tracer
courbes point par point, partir de leur quation sous la forme y = f(x
on se contente de cette mthode de trac, mme si, pour prserver la continuit du
prendre un trs grand nombre de points. La seule chose faire est
de passer de la zone calcul, celle de y=f(x) o il sagit de nombres virgule de quelques
units au plus, la zone cran o les coordonnes sont des nombres entiers pouvant
centaines dunits, do la ncessit de procder un changement
dchelle, avec la mise en place dun zoom.
#include <SDL/SDL.h>
void putpixel(int xe, int ye, int couleur);
int xo=400,yo=300,zoomx=150,zoomy=100;
Uint32 rouge,blanc,noir;
int main (int argc, char* argv[])
SDL_Init( SDL_INIT_VIDEO );
ecran = SDL_SetVideoMode(800, 600, 32,SDL_HWSURFACE);
rouge=SDL_MapRGB(ecran->format, 255,0,0);
blanc=SDL_MapRGB(ecran->format, 255,255,255);
noir =SDL_MapRGB(ecran->format,0,0,0);
SDL_FillRect(ecran,0,blanc);
courbe();
void putpixel(int xe, int ye, int couleur)
>pixels+xe+ye*ecran->w)=couleur;
300;i<300;i++) putpixel(xo+i,yo,rouge); /* les deux axes */
300;i<300;i++) putpixel(xo,yo+i,rouge);
=10;i++) putpixel(xo+zoomx,yo+i,rouge); /* graduations
10;i<=10;i++) putpixel(xo+i,yo-zoomy,rouge);
23
n, nous pouvons tracer des
x). Pour le moment,
on se contente de cette mthode de trac, mme si, pour prserver la continuit du
prendre un trs grand nombre de points. La seule chose faire est
) o il sagit de nombres virgule de quelques
units au plus, la zone cran o les coordonnes sont des nombres entiers pouvant
centaines dunits, do la ncessit de procder un changement
graduations 1 */
24

for(x=-2.;x<2.;x+=0.001)
{ y=x*x*x-x; /* on a pris y=f(x) avec f(x) = x
3
x */
xe=xo+(int)(zoomx*x); ye=yo-(int)(zoomy*y); /* passage de (x,y) (xe,ye) */
if (ye>20 && ye<580) putpixel(xe,ye,noir); /* dessin dans les limites verticales */
}
}

Au point o nous en sommes arrivs, ce qui est dommage cest de ne pas savoir
tracer directement des collections de points qui finalement donnent des figures simples
comme des droites ou des cercles. En attendant mieux, on peut toujours faire comme
pour la courbe prcdente, savoir prendre les quations. Rappelons que lquation
dune droite est de la forme y = ax+b, sauf si la droite est verticale, et que lquation
dun cercle est (x-xo)
2
+(y-yo)
2
=R
2
. Il est stupfiant de constater que ce qui se trouvait
immdiatement disponible dans tous les langages classiques de programmation il y a
trente ans (droites, cercles, sprites, etc.) nest pas prsent doffice aujourdhui, et doit
tre intgr par nos soins.

Heureusement de nouvelles fonctionnalits sont de nos jours disponibles, qui
auparavant taient bien plus complexes. Comme par exemple la possibilit de grer des
vnements, ce qui permet dinteragir sur ce qui se passe sur lcran depuis lextrieur,
en cliquant sur la souris ou en appuyant sur des touches.

La gestion dvnements

Jusqu prsent le seul vnement que nous avions gr tait dans la fonction
pause() , avec SDL_QUIT. Le fait dappuyer sur la croix en bordure de la fentre-cran,
arrtait lexcution du programme, et en attendant cet vnement, la fentre restait
immuablement prsente. Reprenons la fonction pause() et ajoutons dans sa boucle
while, juste aprs if (event.type==SDL_QUIT) continuer=O;

else if (event.type== SDL_KEYDOWN && event.key.keysym.sym==SDLK_ESCAPE)
continuer = NON;

Maintenant le programme sarrtera aussi si lon appuie sur la touche Escape (ou
Echap) en haut gauche du clavier. Mais on va faire mieux. En appuyant sur des
touches, on va faire bouger un objet volont sur lcran. Quel objet ? Un rectangle
bien sr, puisque SDL sy prte bien. Plus prcisment nous allons prendre limage du
logo Code Blocks (avec ses quatre carrs accols) dans le programme qui nous est
offert lorsque lon cre un nouveau projet. Cette image sappelle cb.bmp, il suffit de la
garder ou de la rcuprer lorsque lon fait notre projet actuel. On la charge comme on
la fait pour la fentre-cran, mais en utilisant la fonction ad hoc :

codb = SDL_LoadBMP("cb.bmp");

aprs avoir declar codb avec SDL_Surface *codb;. Cette surface rectangulaire
possde maintenant une position (position.x et position.y) pour son coin en haut
gauche. On commence par faire en sorte que cette image cb se trouve au centre de
lcran, avec position.x = (ecran->w - codb->w) / 2; position.y = (ecran->h - codb->h) / 2; .

La grande nouveaut cest que lon va la faire bouger en appuyant sur des touches.
Par exemple, en appuyant sur la touche du clavier, limage cb va se dplacer sur la
25

droite. Pour cela, on sinspire de notre ancienne fonction pause(), mais dans la boucle
while(continuer== OUI) on ne se contente plus des tests darrt avec SDL_QUIT ou
SDL_KEYDOW avec SDLK_ESCAPE. Par exemple pour provoquer le mouvement
droite de limage cb on fait :

if (event.type== SDL_KEYDOWN && event.key.keysym.sym==SDLK_RIGHT)
position.x +=2;

Cela implique que lon mette lintrieur de la boucle while le placage de limage
cb sur la fentre-cran, dabord en mmoire puis sur lcran grce Flip(), tout cela
tant ralis par le double buffer. Le programme qui suit devrait maintenant tre
limpide.

#include <stdlib.h>
#include <SDL/SDL.h>
#define OUI 1
#define NON 0

int main ( int argc,char *argv[])
{ SDL_Surface *ecran,*codb;
SDL_Rect position; int continuer=OUI; SDL_Event event;

SDL_Init( SDL_INIT_VIDEO );
ecran= SDL_SetVideoMode(800, 600, 32,SDL_HWSURFACE | SDL_DOUBLEBUF);
codb = SDL_LoadBMP("cb.bmp");
SDL_WM_SetCaption("Mouvements",NULL);
position.x = (ecran->w - codb->w) / 2; position.y = (ecran->h - codb->h) / 2;
SDL_EnableKeyRepeat(10,10); /* pour viter le coup par coup et permettre davancer
de 10 pixels quand on laisse la touche appuye */

while (continuer==OUI)
{
SDL_WaitEvent(&event);
if (event.type==SDL_QUIT) continuer=NON;
else if (event.type== SDL_KEYDOWN)
if (event.key.keysym.sym==SDLK_ESCAPE) continuer=NON;
else if(event.key.keysym.sym==SDLK_UP) position.y -=2;
else if(event.key.keysym.sym==SDLK_DOWN) position.y +=2;
else if(event.key.keysym.sym==SDLK_LEFT) position.x -=2;
else if(event.key.keysym.sym==SDLK_RIGHT) position.x +=2;

SDL_BlitSurface(codb, 0, ecran, &position); /* on plaque le logo CodeBlocks*/
SDL_Flip(ecran); /* on balance le tout sur lcran */
}

SDL_FreeSurface(codb);
return 0;
}






26






et a bouge!








Pour aller plus loin

Il existe plusieurs tutoriels de SDL disponibles sur Internet, notamment sur :
le Siteduzero.com, avec un prolongement : manipulation des images pixel par pixel
demander siteduzero sdl sur la recherche google)
Developpez.com
Gnurou.com
Enfin vous avez intrt consulter la rubrique enseignement programmation graphique
sur le site de mon collgue Fares Belhadj, qui ma convaincu de minitier SDL, et que
je remercie.

You might also like