Sunteți pe pagina 1din 26

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.
1

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 :

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. 2

#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
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. 3
2

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

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.

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
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. 5
5

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 6 entier donn. 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
La factorielle devient vite trs grande. Par exemple 20 ! est de lordre de 2 milliards de milliards, soit 2.1018. 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). 6
6

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 20=1 29=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 20= 1 210 = 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.

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 u0= 1 o lunit 1 reprsente un million dindividus. On a la rgle dvolution suivante : en lanne n, la population est de un et lanne suivante elle vaut un+1 = un + (10/100) un car 10% signifie 10/100, soit un+1 = 1,1 un. On obtient une suite de nombres dfinie par la condition initiale u0 = 1 et la relation de rcurrence un+1 = 1,1un. Maintenant on programme : 1) for() : On veut connatre u52 (population en 2060), ce qui permet dutiliser une boucle

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
8

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 RA D_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 ; }

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 22,42,62,82,102. 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 22, 22+42, 22+42+62, 22+42+62 +82, 22+42+62+82+102. 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
10

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) = x3 2x2 + 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().

11

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 L1 et L2, 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 ?
12

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
13

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 h2+x2=R2 (Pythagore), do h2 = R2 x2. Le volume dune tranche cylindrique situe labscisse x est gal laire de la base circulaire h2 multiplie par la hauteur dx. Le volume de la calotte est la somme des
14

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 = intgration. Le calcul donne finalement H 2 (R

par

). 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.

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. 15

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) ;

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 16

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_I IT_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.
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 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 !
10 9

17

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);

18

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

19

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.

20

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 :

21

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); } }

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. 22

11

Exemple 2: Trac dune courbe


Maintenant que nous savons savon colorier des pixels sur lcran, n, nous pouvons tracer des courbes point par point, partir de leur quation sous la forme y = f(x). Pour le moment, 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 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 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 couleur); 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 rouge=SDL_MapRGB(ecran->format, 255,0,0); blanc=SDL_MapRGB(ecran blanc=SDL_MapRGB(ecran->format, 255,255,255); noir =SDL_MapRGB(ecran->format,0,0,0); =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 >pixels+xe+ye*ecran->w)=couleur; } void repere(void) { int i; for(i=-300;i<300;i++) 300;i<300;i++) putpixel(xo+i,yo,rouge); /* les deux axes */ for(i=-300;i<300;i++) 300;i<300;i++) putpixel(xo,yo+i,rouge); for(i=-10;i<=10;i++) =10;i++) putpixel(xo+zoomx,yo+i,rouge); /* graduations 1 */ for(i=-10;i<=10;i++) 10;i<=10;i++) putpixel(xo+i,yo-zoomy,rouge); putpixel(xo+i,yo } void courbe(void) { float x,y; int xe,ye; 23

for(x=-2.;x<2.;x+=0.001) { y=x*x*x-x; /* on a pris y=f(x) avec f(x) = x3 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=R2. 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
24

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; }

25

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.

26

S-ar putea să vă placă și