Skip to content

C

36 Topics 253 Posts

This category can be followed from the open social web via the handle [email protected]

Subcategories


  • 2 14
    2 Topics
    14 Posts
    D
    <p>Hello, voici un petit exercice, tiré du livre "The C Programming Language" (K&R).</p> <p></p><p>En suivant ce prototype (vous  pouvez changer le nom des paramètres) :</p> <pre class="ipsCode prettyprint"> int strend(char *s, char *t) </pre> <p>Créez une fonction qui retourne 1 si la string <em>s</em> se termine par la string <em>t</em>,sinon, retourne 0.</p> <p> </p> <p>Exemples :</p> <pre class="ipsCode prettyprint"> strend("ABCDavy","Davy"); // == 1 strend("Melinyel","oyel"); // == 0 strend("Microsoft","sofa"); // == 0 strend("Forum","rum"); // == 1 </pre> <p>Je posterais ma solution mardi  </p>
  • 0 Topics
    0 Posts
    No new posts.
  • [Cours #5] ArgC, ArgV et allocations Dynamiques

    4
    0 Votes
    4 Posts
    3k Views
    AlexMogA
    <p>Bonjour à tous,<br/> Bienvenue dans ce 4ième cours sur la programmation en C.<br/> Aujourd'hui, nous allons voir un point intéréssent de notre programme, et un point clé en les<br/> Arguments de lancement, et les allocations dynamiques.</p> <p><strong>I- Qu'est-ce qu'un argument de lancement?</strong><br/> Un argument de lancement est une string ajoutée au lancement du programme permettant de faire passer ladite string au programme (string = chaine de caractères).<br/> Ainsi, si je lance le programme avec cette ligne de commande:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>mon_programme mon_argument <p> </p> </div></blockquote> <p>mon programme recevra comme argument 1 : "mon_argument".<br/> (En faite, d'une façon générale, les arguments sont gérés par les shells qui lancent le programme. C'est une convention de programmation).<br/> Quelques exemples d'utilisations d'arguments:<br/> Les commandes unix utilisent très souvent les arguments:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>ls --help<br/> cd --<br/> cd /home<br/> cd ~<br/> mkdir test<br/> ... <p> </p> </div></blockquote> <p>et peuvent donc permettre de faire passer une valeur, ou même un chemin à son programme (bah oui, c'est des Strings (tableaux de caractères). Bon, passons à la pratique:</p> <p><strong>II- Récupérer des arguments de lancement</strong><br/> Nous avions vu la structure basique d'un main en C:</p> <pre class="ipsCode prettyprint"> int main(void) { }</pre> <p> Eh bien, je ne vous ai pas dit la vérité sur cette fonction!<br/> En effet, main peut prendre un void pour argument (et donc ne prendre aucun arguments), ou bien prendre un int, et un char **.<br/> Le véritable prototypage de la fonction main est donc:</p> <pre class="ipsCode prettyprint"> int main(int argc, char *argv) { }</pre> <p> En voyant ça, vous allez me dire "dis donc, j'ai mal à la tête, y'a un ** dans ton code!" Eh bien ne<br/> vous inquiétez pas, il s'agit d'un tableau de chaines de caractères.Prenons pour exemple ce programme lancé comme ceci:</p> <pre class="ipsCode prettyprint"> coucou arg1 arg2 arg3 je suis fou </pre> <p>Eh bien, nous pouvons récupérer les arguments de ce programme de la façon suivante:</p> <pre class="ipsCode prettyprint"> / ** Je re-crée les fonctions d'affichage. Voir cours #1 et #2 */ void my_putchar(char c) { write(1, &c, 1); } void my_putstr(char *str) { while(str) my_putchar((str++)); } int main(int argc, char **argv) { my_putstr(argv[0]); // Affichera my_putstr(argv[1]); // Affichera my_putstr(argv[2]); // Affichera my_putstr(argv[3]); // Affichera my_putstr(argv[4]); // Affichera my_putstr(argv[5]); // Affichera my_putstr(argv[6]); // Affichera return (0); } </pre> <blockquote class="ipsQuote" data-ipsquote=""><div>"cocuou"<br/> "arg1"<br/> "arg2"<br/> "arg3"<br/> "je"<br/> "suis"<br/> "foud" <p> </p> </div></blockquote> <p>Nous butons à présent sur un problème, ré-utilisons le programme précédent, mais supprimons tous,<br/> ou un des arguments:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>Segmentation Fault <p> </p> </div></blockquote> <p> Eh oui, comme vous le voyez, nous essayons d'accéder à la valeur d'un tableau qui n'existe pas, ce qui provoque une erreur d'accès en mémoire.<br/> Pour remédier à cela, les développeurs nous ont rajoutés "argc".<br/> Pour mieux vous faire comprendre, je vais vous définir exactement ce que signifie argc et argv:<br/> ArgC est un couplage entre les mots: Argument et Count, il s'agit donc du nombre d'arguments qui ont été passés en paramètres.<br/> ArgV est un couplage entre les mots: Argument et Value, il s'agit donc des valeurs de ces dits arguments.</p> <p> Maintenant que vous avez le nombre d'arguments, vous pouvez vérifier que le nombre d'arguments est correcte avant de l'afficher:</p> <pre class="ipsCode prettyprint"> int main(int argc, char **argv) { if (argc > 1) my_putstr(argv[1]); return (0); }</pre> <p>argv[0] sera toujours présent, puisqu'il s'agit du tout premier argument, qui est vital pour lancer le programme (il s'agit plus exactement de la commande utilisée pour lancer le programme).<br/> Passons à présent à la partie complexe de ce cours: les allocations dynamiques.</p> <p><strong>III- Les allocations dynamiques</strong><br/> L'allocation dynamique, c'est l'art de savoir utiliser sa RAM et les répercussions de l'alloc sur celle-ci.<br/> Nous avions vu précédemment que pour pouvoir avoir une chaine de caractère avec une certaine taille, nous devions définir un tableau de caractères, avec une taille FIXE.<br/> Comme ceci:</p> <pre class="ipsCode prettyprint"> char mon_tableau[talle_de_mon_tableau]; </pre> <p>Là est le problème, imaginons que nous devions modifier notre chaine, en lui imposant une taille plus grande: SegFault.<br/> Eh bien, la solution, c'est d'utiliser l'allocation dynamique: Au lieu de stocker notre chaine dans la stack, stockons la dans la RAM! (ce qui nous permet d'avoir plus d'espace, d'ailleurs! (généralement, la stack est limitée à quelques Ko, alors que la RAM non))<br/> Vous comprenez donc qu'il est dangereux d'utiliser malloc de façon idiote: dans une boucle infinie par exemple... Puisque vous allez remplir votre RAM!</p> <p> Prenons un exemple simple:<br/> J'ai un programme qui connaît la taille d'une chaine de caractère, et je dois la stocker dans une variable:</p> <pre class="ipsCode prettyprint"> int main(void) { int lenght = 300000; // Oui, notre chaine est très longue }</pre> <p> Si je tentais de déclarer un tableau statique de char de taille 300 000, il y aura énormément de chances pour que mon programme segfault dès le lancement.<br/> C'est problématique, en effet.<br/> Tentons donc d’allouer un emplacement dans la ram pour cette chaine:</p> <pre class="ipsCode prettyprint"> int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); }</pre> <p> Tiens, ça marche!<br/> Lisons un peu mieux le man de malloc: en cas d'erreur, malloc retourne NULL.<br/> Nous allons donc vérifier si il y a eu une erreur (pour éviter le segfault):</p> <pre class="ipsCode prettyprint"> int main(void) { char ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } }</pre> <p> Bon, nous avons donc alloué un emplacement de type char (donc tableau de caractères) dans notre ram, avec une taille de 300 000 cases! Cool!<br/> Nous pouvons donc remplire "ptr" exactement comme un tableau (case par case, voir cours sur les chaines de caractères).<br/> ATTENTION: ptr est un POINTEUR. Si vous modifiez son adresse, vous perdez l'ancienne adresse allouée! Donc ceci:</p> <pre class="ipsCode prettyprint"> int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } ptr = "coucou"; } </pre> <p>est interdit et stupide (ne rigolez pas, les profs de programmation font souvent l'erreur!).<br/> Bon, c'est bien, nous avons alloué de la mémoire, mais bon, c 'est pas cool pour la RAM, on ne la vide jamais, il va falloir la vider!<br/> Pour la vider, la fonction "free" est là pour nous aider!<br/> Voilà mon programme une fois la fonction "free" utilisée:</p> <pre class="ipsCode prettyprint"> int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } free(ptr); } </pre> <p>Tout marche! Cool!<br/> ATTENTION: pour bien vous montrer que modifier un pointeur est une mauvaise idée, tentez de faire ceci:</p> <pre class="ipsCode prettyprint"> int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } ptr = "coucou"; free(ptr); }</pre> <p> Hop, vous tomberez sur une erreur qui se nomme "glibC" et qui corresponds à une erreur de pointage, la fonction "free" vous hurle dessus comme quoi votre pointeur ne pointe pas sur une zone<br/> allouée.<br/> Pour vous montrer que mon code fonctionne, je vais afficher ma chaine de caractère, qui fera<br/> l'alphabet avec 300 000 lettres!</p> <pre class="ipsCode prettyprint"> int main(void) { char *ptr; int i; i = 0; j = 0; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } while(i < 300000) { ptr[i] = j + 'a'; i = i + 1; j = j + 1; if (j + 'a' >= 'z') j = 0; } ptr[i] = '\0'; // NE PAS OUBLIER LA FIN DE LA CHAINE (voir cours sur les chaines de caractères) my_putstr(ptr); free(ptr); }</pre> <p> Et voilà, vous savez à présent utiliser les allocations dynamiques!<br/> A bientôt pour le prochain cours!<br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr</p>
  • [Cours #7] Les pointeurs sur fonction

    4
    0 Votes
    4 Posts
    2k Views
    AlexMogA
    <p>Bonjour à tous,<br/> Ce cours va être très court (oh ce jeu de mot!). En effet, je vais juste vous montrer comment faire un pointeur sur fonction.</p> <p> </p> <p><strong>I- Pointeur sur fonction? Kesako?</strong><br/> Un pointeur sur fonction, c'est simplement une manière d'appeler une fonction, en passant par un pointeur.<br/> Par exemple:</p> <pre class="ipsCode prettyprint"> void (*function_pointer)(char); function_pointer = &my_putchar; // Vous pouvez retrouver la fonction my_putchar sur le cours #1. function_pointer('A');</pre> <p> Le programme ci-dessus crée le pointeur sur fonction function_pointer, et lui définit l'adresse de my_putchar (qui permet d'afficher un caractère).<br/> Il affiche 'A'.</p> <p> II- Utilité?<br/> Un pointeur sur fonction permet d'appeler une fonction via un pointeur. Il est très souvent utilisé pour les tableaux de pointeurs sur fonction. Ce qui permet, par exemple, d'appeler une fonction en fonction d'une condition, sans avoir 40 000 if/else.<br/> Exemple de tableau de pointeurs sur fonction:</p> <pre class="ipsCode prettyprint"> #include <unistd.h> void my_putchar(char c) { write(1, &c, 1); } void my_putstr(char *str) { while(str) my_putchar((str++)); } void aff_help() { my_putstr("Commandes:\ncoucou: affiche salut\ndada: affiche dadi\npopo affiche caca"); } void aff_coucou() { my_putstr("salut\n"); } void aff_dada() { my_putstr("dadi\n"); } void aff_popo() { my_putstr("caca\n"); } void do_cmd(char *cmd) { void (*fptr[])() = {&aff_popo, &aff_dada, &aff_coucou}; char cmds[] = {"popo", "dada", "coucou"}; int i = -1; while (++i < 3) { if (!strcmp(cmds[i], cmd)) { fptr(i)(); return ; } } my_putstr("Commande introuvable."); } int main(int ac, char **av) { int readed; char buffer[4096]; my_putstr("Entrez votre commande. Utilisez CTRL+D pour quitter\n"); while ((readed = read(0, buffer, 4095)) != -1) { buffer[readed] = '\0'; do_cmd(buffer); } return (0); } </pre> <p><strong>III- Déclaration et appel.</strong><br/> Enfin, voyons comment déclarer un pointeur sur fonction, puis comment lui définir une fonction.<br/> Déclarons notre pointeur. Forme de déclaration:</p> <pre class="ipsCode prettyprint"> typage_renvoyé_par_la_fonction (*nom_pointeur)(arguments_pris_par_la_fonction);</pre> <p> Par exemple, pour printf:</p> <pre class="ipsCode prettyprint"> int (*myptr)(char *, ...); // oui, les ... sont un type. Il existe une fonction qui permet de récupérer une infinité d'args dans une fonction, mais je vousl’expliquerais dans un prochain cours! // Assignation myptr = &printf; // Utilisation myptr("Salut tout le %s", "monde!\n"); </pre> <p>Voilà.<br/> Vous l'aurez compris, les pointeurs sur fonctions sont très, TRES utilisés dans le monde du développement. Il est donc important de savoir les utiliser, pour apprendre à gagner des lignes.<br/> Je vous dis a bientôt pour un prochain cours!<br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr</p>
  • Cours #0 - Avant propos et outils

    15
    0 Votes
    15 Posts
    5k Views
    AlexMogA
    <p>Bonjour à tous, et bienvenue dans ce premier cours dédié au C.<br/><br/> Dans ce cours, nous allons voir pourquoi il est important de comprendre et de programmer en C, puis nous passeront à une partie plus pratique en regardant les outils qui nous sont proposés pour cela.<br/><br/><br/><strong>I- Pourquoi apprendre le C?</strong><br/><br/> Le C est un langage le plus bas niveau qui existe (après l'ASM bien entendu!), il permet donc de mieux comprendre le fonctionnement de sa machine.<br/><br/> Bas niveau? Cela signifie qu'il est simple?<br/><br/> Bas niveau ne corresponds pas au niveau de simplicité du C. Il s'agit en faite d'un niveau par rapport à la machine. Plus un langage est bas niveau, plus il sera proche du fonctionnement de la machine, donc difficile. Plus il sera bas niveau, plus il nous permettera de comprendre le fonctionnement de la machine.<br/><br/><br/> Nous allons donc avoir plusieurs cours, en ayant pour but de comprendre comment fonctionne notre machine. Pour cela, nous allons nous orienter vers une programmation impérative que nous permet le C, en nous forçant à n'utiliser QUE des appels system (Donc pas de libc! (à titre informatif: c'est la méthode Epitech)). Nous seront donc obligés de re-créer nos propres outils de travail!<br/><br/><br/> Vous l'aurez compris: les prochains cours ont pour but de vous apprendre à utiliser de façon extrême le C. Sans utiliser les outils déjà mis à disposition (libs, etc...), pour vous apprendre à comprendre comment ceux-ci fonctionnent!<br/><br/><br/><strong>II- Les outils pour programmer en C</strong><br/><br/> Le tout premier outils que je vous conseille, c'est d'utiliser LINUX.<br/><br/><em>Pourquoi Linux?</em><br/><br/> Eh bien c'est très simple: Linux propose énormément d'outils de débugage, et beaucoup d'outils de programmation (Make, Valgrind, GDB, Emacs etc...). Ainsi qu'une documentation détaillée des appels system et de la libc (grâce notamment à la commande "man"). Enfin, une protection plus rapprochée du système qui vous évitera de mauvaises suprises lorsque vous jouerez avec la mémoire (je conseille fortement d'utiliser les limitations de ram par users pour éviter les forkbombs et autres malloc infinis). Je vous conseille donc fortement d'utiliser Linux.<br/><br/> De mon côté, j'ai opté pour un Debian sur lequel j'ai installé une interface graphique et tout les outils nécéssaires! Je conseille fortement Mint qui est basé sur Debian.<br/><br/> Vous pouvez utiliser une machine virtuelle pour faire tourner votre Linux si vous ne souhaitez pas le rajouter au Dump!<br/><br/><br/> Ensuite, les outils de base:<br/><br/> Nous allons programmer en utilisant 5 outils très importants:<br/><br/><strong>Emacs:</strong> C'est l'éditeur qui va nous permettre d'éditer nos codes en C. Il est très pratique, mais il faut connaitre les syntaxes et les racourçis qu'il propose!<br/><br/><strong>GDB:</strong> C'est un excellent débugueur qui permet de fixer des points d'arrêt sur son programme, pour réussir à trouver les problèmes de notre programme!<br/><br/><strong>Valgrind</strong>: C'est un de mes outils préférés: Il permet de savoir si vous avez bien free tout vos malloc (et donc, bien vidé toute la mémoire) et de repérer les segfaults (à notter: il faut rajouter -g3 aux flags de compilation pour que celui-ci marche pleinement, n'oubliez surtout pas de supprimer -g3 de vos makefiles à la version finale. -g3 rends l'exécutable très lourd).<br/><br/><strong>Make</strong>: L'outil Make est l'un des plus importants: il nous permettra de créer un "Makefile" qui va nous permettre, grâce à la commande Make, de compiler, et nétoyer notre programme facilement.<br/><br/><strong>htop ou top</strong>: C'est un invité de commandes pour unix, qui va nous permettre de voir l'avancement et l'utilisation de notre RAM/CPU.<br/><br/><br/> Voilà, je vous es donc fait une courte introduction sur tout ce qui es des outils et de la programmation en C!<br/><br/><br/> Rendez-vous au prochain cours!<br/><br/><br/><br/><br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr</p>
  • IA #1 - le pathfinding (1/2)

    3
    0 Votes
    3 Posts
    2k Views
    daemondragonD
    <p>Bonjour a tous !<br/><br/> Cette suite de tutoriel va vous expliquez comment faire une IA basique pour des pnj<br/> que vous pourrez adapter pour des jeux simples(non ce n'est pas une super grosse IA<br/> de la mort qui tue qui va faire vos problèmes de math toute seule).<br/><br/> Dans la première partie du tutoriel, nous allons voir une partie fondamentale<br/> des IA dans les jeux vidéos : le pathfinding.<br/> Le code du pathfinding était trop long pour être expliqué dans un seul tutoriel,<br/> le premier traitera de la théorie et le deuxième de la pratique.<br/><br/> Le pathfinding, qu'est ce que c'est ?<br/><br/> Le pathfinding c'est le fait de dire a une personne :<br/> tu vas du point A au point B en évitant les obstacles.<br/> (c'est mieux que de se prendre les murs non ? )<br/><br/> Pour le pathfinding, nous allons mettre en place un algorithme A*, qui est<br/> très célèbre et qui peut être utilisé un peu partout, surtout dans le jeu<br/> utilisant un système de grille(starcraft, zelda etc...)<br/><br/> A* tiens son nom de la recherche "en étoile" qu'il fait :<br/> pour chaque case, il va regarder celles d'autour qui n'ont pas été déjà exploré et va dire :<br/> celle la elle est plus loin de la case de départ que la précédente.<br/><br/> petite image :</p> <p><img alt="ExplicationAStar.png" src="<base_url>/applications/sslimageproxy/interface/image.php?url=http://www.nicolas-texier.net/fr/system/files/ExplicationAStar.png"/><br/><br/> Le 0 correspond au début.<br/> Plus on s'éloigne du 0, plus le coût (ou le poids, c'est la même chose) augmente.<br/> Le but, c'est de prendre le chemin, qui possède le plus faible coût.<br/><br/> Par exemple, si vous voulez partir du point (0, 3) -> le 4eme point<br/> tout en haut a gauche, vous n'allez pas partir carrément a gauche, faire X fois<br/> le tour du gros truc noir, non ?<br/> Vous allez simplement prendre le chemin le plus court.<br/><br/> Pour réaliser donc ce merveilleux pathfinding, vous allez donc partir du début<br/> (le point (7, 6)) et regarder autour, si ce bloc n'est pas un mur. Vous augmenter<br/> alors le coût du déplacement pour cette case, puis on refait cela jusqu’à ce qu'on<br/> trouve la fin voulu ou jusqu’à ce qu'il n'y ai plus de possibilité<br/> de passer car tous les blocs ont été explorés, il n'y a donc pas de possibilité<br/> d'aller du point A au point B.<br/> Puis on part de la fin et on passe par les blocs qui ont le plus faible coût.<br/><br/> Pour réaliser cela, on commence par créer une file (oui je parle enfin de code).<br/> Une file est une structure de données qui permet de mettre des variables l'une après l'autre.<br/> La première donnée qui rentre dans la file est la première à sortir.<br/><br/> Pour ceux qui ne savent pas ce que c'est :<br/><iframe data-embed-src="<base_url>/topic/783-cours-8-listes-chain%C3%A9es/?do=embed" data-embedcontent="" frameborder="0" src="//melinyel.net/applications/core/interface/js/spacer.png"></iframe><br/><br/> Donc ont la créer, cette file et on met, si ce n'est pas des murs, et s'il n'ont pas<br/> été déjà explorés,la position des blocs d’à coté, tout a la fin.<br/> A chaque tour de boucle, ont prend la première position et on refait la même chose.<br/> Pour les minecraftien, c'est comme l'eau qui coule déjà sur la case la plus proche, puis sur celles<br/> plus éloignées.<br/><br/> Quand on a trouvé la fin, la où le pnj par exemple veut aller, on arrête, ou alors quand il n'y a plus<br/> de blocs a explorer, alors le pnj est triste car il ne peut pas y aller.<br/><br/> Si on a trouvé la fin, on met alors dans une pile, (les dernières données qui arrivent dedans<br/> seront les premières à sortir), car le chemin doit être pris dans le sens contraire où l'on va.<br/> On cherche alors, a partir de la fin, la case autour d'elle qui a le plus faible coût,<br/> puis on enregistre sa position et on mets la direction contraire (n'oublier pas que le<br/> pnj va parcourir le chemin dans l'autre sens) dans la pile et on refait ça<br/> jusqu’à ce qu'on trouve le début.<br/><br/> Et voila vous pouvez maintenant, grâce à ces explication créer vous même votre pathfinding, ou alors<br/> attendre le prochain tutoriel qui ne devrait pas tarder a suivre.<br/> En utilisant uniquement le pathfinding et intelligemment vous pouvez déjà créer un planning pour chaque pnj,<br/> ce qui va permettre de rendre une ville plus vivante (je pense surtout au village pnj de zelda qui sont<br/> toujours au même endroit, c'est un peu triste non ?).</p>
  • [Cours #6] Librairies (statiques) et fichiers Headers (.h)

    4
    0 Votes
    4 Posts
    2k Views
    AlexMogA
    <p>Bonjour à vous,<br/> Dans ce cours, nous allons voir à quoi corresponds un fichier header, ainsi que comment créer une  librairie, et enfin, les structures!</p> <p> </p> <p><strong>I- Qu'est-ce qu'une lib?</strong><br/> Une lib, aussi nommée librairie (dynamique ou statique) est un fichier binaire contenant une liste de fonctions prédéfinies.<br/> Je vais vous donner un exemple de son utilisation, et pourquoi il est bon de créer une lib!<br/> Imaginons que vous avez créé plusieurs fonctions, il vous serait pratique de les ré-utiliser dans un autre programme! Malheureusement, la compilation est très longue si il y a beaucoup de fonctions.<br/> La lib est donc là pour deux choses: partager des fonctions sur diverses programmes, et éviter une  compilation inutile sur des fonctions déjà près compilées.<br/> Pour mieux vous faire comprendre tout cela, créons trois fichiers distincts:<br/> main.c:</p> <pre class="ipsCode prettyprint"> int main(void) { my_putstr("coucou\n"); return (0); } my_putchar.c: void my_putchar(char c) { write(1, &c, 1); } my_putstr.c: void my_putstr(char *str) { while(str) my_putchar((str++)); }</pre> <p> Tentons à présent de compiler main.c:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>cc main.c <p> </p> </div></blockquote> <p> Hum.. notre linker nous gueule dessus en nous disant qu'il est impossible de trouver la fonction "my_putstr". C'est normal! my_putstr n'a pas été compilée avec notre main. Elle ne fais donc pas partie du programme.<br/> Maintenant, tentons de compiler tous nos fichiers en même temps:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>cc main.c my_putchar.c my_putstr.c <p> </p> </div></blockquote> <p>Ah! Là ça marche! On a notre a.out qui est bien créé, et qui affiche bien "coucou".C'est un bon point, mais nous ne sommes pas avancés, j'ai envie de réutiliser my_putchar et my_putstr dans mes autres programmes, je vais tenter des les compiler pour voir si je peux les ré-utiliser sans avoir à les recompiler!</p> <blockquote class="ipsQuote" data-ipsquote=""><div>cc my_putchar.c<br/> cc my_putstr.c <p> </p> </div></blockquote> <p> Hum... Mon linker me dit cette fois-ci qu'aucun main n'a été trouvé... Je ne peux donc pas compiler mes fonctions séparément?<br/> Eh bien si! Il a une solution, les transformer en fichiers binaires non exécutables (aussi appelées lib), leur extentions est généralement .a pour un rassemblement de mini-libs, et .o pour les fichiers de fonctions de cette lib (pour résumer, les .o sont les briques, et .a est une partie du mur ! On utilise les briques pour construire cette partie).<br/> Créons donc nos .o!</p> <blockquote class="ipsQuote" data-ipsquote=""><div>cc -c my_putchar.c<br/> cc -c my_putstr.c <p> </p> </div></blockquote> <p> (man cc pour plus d'informations)<br/> Voila! Je découvre my_putchar.o et my_putstr.o, tentez la commande "file my_putchar.o" pour voir qu'il s'agit bien d'un fichier binaire non exécutable.<br/> C'est cool, mais pour l'instant mes fichiers sont séparés, j'aimerais bien tous les avoir dans un même  "packetage" pour éviter de me trimballer 40 fichiers par programmes.<br/> Eh bien, nous allons utiliser notre linker (et non plus notre compilateur) pour tous les liés dans un même  package, un véritable fichier lib: un fichier .a.<br/> Nous l'appellerons libmy.a:<br/> Pour créer notre lib, voici la commande linker (je vous laisse le soin de lire le man de celle-ci):</p> <blockquote class="ipsQuote" data-ipsquote=""><div>ar rc libmy.a my_putstr.o my_putchar.o <p> </p> </div></blockquote> <p>On peux en faite considérer les .o comme des briques, et les .a comme le ciment qui va maintenir ces briques sur le programme.<br/> Nous avons enfin notre lib! Tentons à présent de compiler main.c avec notre lib (je vous laisse, encore une fois, le soin de lire le man de gcc):</p> <blockquote class="ipsQuote" data-ipsquote=""><div>cc main.c -L./ -lmy <p> </p> </div></blockquote> <p>Hop! Nous avons notre a.out fonctionnel!<br/> Vous savez à présent créer vos propres librairies!</p> <p><strong>II- Les fichiers Header</strong><br/> Nous avons vu précédemment comment créer notre propre librairie, mais néanmoins, nous avons, de temps à autres, des warnings qui apparaissent lors de notre compilation, voir même des erreurs car notre compilateur ne connaît pas les fonctions qu'il utilise.Les fichiers Headers ont plusieurs particularités. Il s'agit avant tout de fichiers d'"entête" chargés de fournir des informations au compilateur pour qu'il sache où chercher les fonctions, et leur utilité dans le programme.<br/> Il permet aussi de rendre le code plus propre: nous pourrions faire nos headers directement dans notre .c, mais c'est plus moche, et la compilation d'un .h diffère de celle d'un .c (tentez cc *.h vous verrez bien).<br/> Un header, c'est donc un fichier de préparation à la compilation. Il contiendra ainsi les prototypes des fonctions utilisées dans notre programme.<br/> Vous pouvez trouver des exemples de headers dans les librairies que nous avions déjà utilisé!<br/> Souvenez-vous:<br/> Nous avions utilisé:</p> <pre class="ipsCode prettyprint"> #include <unistd.h> </pre> <p>qui corresponds à inclure le fichier .h de la libraire unistd. les <> signifient que le header se trouve dans le dossier include de notre compilateur.<br/> Pour inclure un fichier local, il suffit de faire</p> <blockquote class="ipsQuote" data-ipsquote=""><div>#include "fichierlocal" <p> </p> </div></blockquote> <p> tout simplement!<br/> Donc revenons sur notre histoire de warnings, nous allons créer un .h pour la lib précédente que nous avons créé:</p> <pre class="ipsCode prettyprint"> #ifndef MY_H #define MY_H void my_putchar(char); void my_putstr(char ); #endif / MY_H */</pre> <p> Je vais vous expliquer le fichier lignes par lignes.<br/> Mais avant cela, je vais vous expliquer ce qu'est un define.<br/> Un define est une sorte de variable statique et constante. Elle permet de remplacer la valeur du define par la valeur associée à celui-ci.<br/> Voici un exemple simple:</p> <pre class="ipsCode prettyprint"> #define VERSION "1.0.0"</pre> <p> J'ai définit VERSION comme ayant comme value 1.0.0<br/> Je peux le ré-utiliser dans mon code, si j'inclus le fichier .h qui contient ce define, comme ceci:</p> <pre class="ipsCode prettyprint"> int main(void) { my_putstr(VERSION); return (0); }</pre> <p> ATTENTION: il ne s'agit pas d'une variable. Un define est remplacé par le compilateur par la valeurqui lui est destinée!<br/> J'espère que vous m'aurez compris...<br/> Passons donc à la définition de notre fichier .h:</p> <pre class="ipsCode prettyprint"> #ifndef MY_H</pre> <p> Notre première ligne de code permet d'éviter ce qu'on appelle une "double inclusion", en effet, si on inclue notre fichier .h dans plusieurs autres fichiers du même programme, nous pouvons créer de multiples inclusions, ce qui ne sert à rien, et ralentit la compilation.</p> <pre class="ipsCode prettyprint"> #define MY_H</pre> <p> Si notre fichier n'a jamais été inclus, nous définissons qu'il l'a à présent été void my_putchar(char);</p> <pre class="ipsCode prettyprint"> void my_putstr(char );</pre> <p> On y ajoute ensuite les prototypes des fonctions utilisées...</p> <pre class="ipsCode prettyprint"> #endif / MY_H */</pre> <p> Enfin, on ferme notre "#ifndef" (if not defined).<br/> Nous y sommes, revoyons notre main à présent:</p> <pre class="ipsCode prettyprint"> #include "my.h" int main(void) { my_putstr("coucou\n"); return (0); }</pre> <p> Compilons le:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>cc main.c -lmy -L./ <p> </p> </div></blockquote> <p> Et voilà! Plus aucun warnings ou erreurs! Nous pouvons passer à la suite!</p> <p> </p> <p><strong>III- Les Structures.</strong><br/> Une structure est un ensemble de données. Il permet de stocker plusieurs données sous un même typpage. (nous verrons en même temps la déclaration de typpages, grâce à typedef).<br/> Construction d'une structure:</p> <pre class="ipsCode prettyprint"> struct s_nom_de_ma_struct { int valeur_numerique; char valeur_caractere; typpage valeur_n'importe_quel_typpage; };</pre> <p> C'est aussi simple que cela.<br/> A savoir : Une structure doit être déclarée dans un .h!Nous allons créer une structure, qui contiendra une  chaine de caractères "pseudo" et une autre<br/> chaine de caractère "texte":</p> <pre class="ipsCode prettyprint"> struct s_mastruct { char *pseudo; char *texte; };</pre> <p> Nous allons afficher les données de notre structure:</p> <pre class="ipsCode prettyprint"> void set_structure(struct s_mastruct mastruct) { / (*mastruct).pseudo = "AlexMog" est la même chose que mastruct->pseudo = "AlexMog" */ mastruct->pseudo = "AlexMog"; mastruct->texte = "Coucou! :)"; } int main(void) { struct s_mastruct mastruct; set_structure(&mastruct); my_putstr("Pseudo: "); my_putstr(mastruct.pseudo); my_putchar('\n'); my_putstr("Texte: "); my_putstr(mastruct.texte); my_putchar('\n'); return (0); }</pre> <p> Ce code nous affichera:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>Pseudo: AlexMog<br/> Texte: Coucou! <p> </p> </div></blockquote> <p>A SAVOIR: lorsque vous utilisez un pointeur sur structure (comme dans la fonction set_structure) les "." sont remplacés par "->".<br/> Voilà, vous savez à présent vous servir des structures. Mais vous avez remarqué que taper "struct s_mastruct mastruct" est tout de même long pour la ré-utilisation de cette structure... Nous allons donc créer notre propre typage!<br/> Rendez-vous dans le .h:</p> <pre class="ipsCode prettyprint"> struct s_mastruct { char *pseudo; char *texte; }; </pre> <p>et créons notre nouveau typage:</p> <pre class="ipsCode prettyprint"> typedef struct s_mastruct { char *pseudo;char *texte; } t_mastruct;</pre> <p> Nous pouvons à présent déclarer nos structures comme ceci:</p> <blockquote class="ipsQuote" data-ipsquote=""><div>t_mastruct mastruct; <p> </p> </div></blockquote> <p> Cool n'est-ce pas ?<br/> Vous remarquerez, pour ceux qui font de la programmation orientée objet, qu'une structure ressemble énormément à un objet, il s'agit en faite de la maman de l'objet connu actuellement! Nous verrons cela plus en détails, lorsque j'aborderais les notions sur la programmation en C Modulaire dans un prochain cours (dans longtemps donc, puisque nous devons voir les pointeurs sur fonctions avant (un objet = une structure contenant un ensemble de données et de pointeurs sur fonctions allouée dans la mémoire)).</p> <p> </p> <p>Voilà!<br/> A très bientôt pour un prochain cours!<br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr</p>
  • IA #1 - le pathfinding (2/2)

    2
    0 Votes
    2 Posts
    2k Views
    daemondragonD
    <p>Et voila le deuxieme tutoriel où je vais vous expliquer tout le code<br/> du pathfinding ( et oui enfin ! )<br/><br/> Tout d'abord n'hésitez pas a télécharger les sources en bas du post afin<br/> de les lire en même temps, c'est plus pratique pour comprendre de<br/> quoi je parle.<br/><br/> On va commencer par le prototype de la fonction :</p> <pre class="ipsCode prettyprint"> path_direction* create_path(const int largueur, const int hauteur, int map[][hauteur], const path_pos debut, const path_pos fin, int pivot) </pre> <p>Cette fonction retourne un pointeur vers une structure, je vais vous expliquer a quoi<br/> elle sert vers la fin. Il faut donc en paramètre la largueur et la hauteur de la map</p> <p>(attention, la map doit être de format map[largueur][hauteur] et non, map[hauteur][largueur]<br/> la map qui contient des nombres afin de représenter votre terrain, et maintenant les trucs<br/> intéressant : la structure path_pos ne contient que deux int, x et y, pour connaître la position<br/> du début et celle de la fin.<br/><br/> Attention, le début de la map commence a (0, 0), il faut faire attention !<br/> Et enfin le pivot, mais qu'est ce que c'est ?<br/> C'est tout simplement tout les nombres qui sont supérieur ou égal a lui sont traversables,<br/> tout ceux inférieur sont des murs par exemples. cela nécessite par contre de penser a<br/> cela dès le début e la conception du jeu mais c'est pas très difficile. personnellement,<br/> j'utilise souvent des énumération pour définir les différentes tiles (blocs) de la map.<br/><br/> ensuite :</p> <pre class="ipsCode prettyprint"> if(debut.x == fin.x && debut.y == fin.y) { return NULL; } </pre> <p>assez explicite je crois, on retourne NULL afin de savoir qu'il n'y a pas de chemin.<br/><br/> On doit créer ensuite une grille de coût , de la taille qui faut exactement, et on initialise<br/> le tout a 0, c'est très important !<br/> on met a jour a grille de coût, en mettant a 1 le début.</p> <p>Ainsi, on sait que tout les blocs avec un coût égal a zéro sont non explorés<br/><br/> Il faut ensuite créer une file, les positions actuelle et les suivantes, ce qui donne :</p> <pre class="ipsCode prettyprint"> path_pos actuel; path_pos suivant; control control_list; </pre> <p>la structure control et donc se qui va nous servir a contrôler la file, on va mettre les donnée<br/> en file a partir de cette structure là.<br/> Elle contient un pointeur vers la première donnée, pour la récupérer. (n'hésitez pas a regarder<br/> le précédent tutoriel pour voir de quoi je veux parler) Et aussi un pointeur vers la dernière<br/> données, afin de mettre les données dans la file plus rapidement. S'il n'y en avait pas, on<br/> aurait du parcourir TOUTES les données de la file une par une afin de trouver la fin.<br/> Vous imaginez sur une énorme file de 1000 données ?<br/> Il faut initialiser la file avec la position de début et on commence les choses sérieuse.<br/><br/> Il faut ensuite créer une boucle qui s’arrête quand on a trouvé la fin ou que la file est vide.<br/> dedans, on met a jour la position actuelle qui erre égale a la valeur du début de file.<br/> si la position actuelle est égale a celle de fin on sort de la boucle, sinon on regarde sur le coté.<br/> Cela donne en code:</p> <pre class="ipsCode prettyprint"> while(control_list.premier != NULL && fini) { actuel.x = control_list.premier->actuel.x; actuel.y = control_list.premier->actuel.y; if(actuel.x == fin.x &amp;&amp; actuel.y == fin.y) { fini = 0; } if(actuel.x != 0) { if(map[actuel.x-1][actuel.y] &gt;= pivot &amp;&amp; poid[actuel.x-1][actuel.y] == 0) { suivant.x = actuel.x-1; suivant.y = actuel.y; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&amp;control_list, suivant); } } if(actuel.x != largueur -1) { if(map[actuel.x+1][actuel.y] &gt;= pivot &amp;&amp; poid[actuel.x+1][actuel.y] == 0) { suivant.x = actuel.x+1; suivant.y = actuel.y; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&amp;control_list, suivant); } } if(actuel.y != 0) { if(map[actuel.x][actuel.y-1] &gt;= pivot &amp;&amp; poid[actuel.x][actuel.y-1] == 0) { suivant.x = actuel.x; suivant.y = actuel.y-1; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&amp;control_list, suivant); } } if(actuel.y != hauteur - 1) { if(map[actuel.x][actuel.y+1] &gt;= pivot &amp;&amp; poid[actuel.x][actuel.y+1] == 0) { suivant.x = actuel.x; suivant.y = actuel.y+1; poid[suivant.x][suivant.y] = poid[actuel.x][actuel.y] + 1; add_to_file(&amp;control_list, suivant); } } remove_to_file(&amp;control_list); } </pre> <p>Il faut bien entendu éviter de partir sur les coté de la map, sinon on risque d'avoir des problèmes de mémoires.<br/> Vous vous dites aussi sûrement : "mais c'est quoi add_to_file et remove to file" non ?<br/> Ce sont les structure qui servent a mettre les données dans la file, ou a les enlever.<br/> (regardez dans le code source fournit, elle y sont au début.)<br/> A partir de là, la grille de coût est fini, on peut vider totalement la file, on<br/> n'en a plus besoin. ( il faut éviter les fuites mémoires) :</p> <pre class="ipsCode prettyprint"> while(control_list.premier != NULL) { remove_to_file(&control_list); } </pre> <p>Et non ce n'est toujours pas fini :<br/> Il faut regarder la variables fini, qui si elle est égale a zéro, signifie qu'on a trouvé la<br/> fin ,sinon, il faut encore retourner NULL.<br/> si le chemin est trouvé, on se place sur la position de fin et regarde a coté.<br/> On va dans la direction on le coût est égal au coût - 1 de la case.<br/> Il ne faut surtout PAS prendre la case qui a un coût inférieur a celle autour, car a ce<br/> stade la, certaine case n'ont pas encore été explorer ( se n'était pas la peine, on<br/> avait trouver le plus court chemin jusqu’à la fin) et sont donc encore égale a 0.<br/> On risque alors de se trompé totalement de chemin.<br/> On met ensuite dans la pile les directions contraire ou on va aller.<br/> (on part de la fin je vous rappelle) et on retourne a la fin cette pile.<br/> En code :</p> <pre class="ipsCode prettyprint"> if (fini == 0) { fini = 1; actuel.x = fin.x; actuel.y = fin.y; path_direction *control = NULL; char direction; while((actuel.x != debut.x &amp;&amp; fini) || (actuel.y != debut.y &amp;&amp; fini)) { //les directions sont inversé car le png va aller dans l'autre sens if(poid[actuel.x][actuel.y+1] == poid[actuel.x][actuel.y] - 1) { direction = NORD; actuel.y++; } else if(poid[actuel.x][actuel.y-1] == poid[actuel.x][actuel.y] - 1) { direction = SUD; actuel.y--; } else if(poid[actuel.x+1][actuel.y] == poid[actuel.x][actuel.y] - 1) { direction = OUEST; actuel.x++; } else { direction = EST; actuel.x--; } empile(&amp;control, direction); } return (control); } </pre> <p>La structure path_direction comporte, une direction sous forme de point cardinaux (NORD, SUD...)<br/> et un pointeur vers la donnée suivante (c'est une pile je vous rappelle).<br/> la fonction empile sert a empiler la direction dans la pile (elle va tout au début).<br/> A la fin, on retourne la pile, qu'il faut récupérer avec un pointeur sur une structure path_direction</p> <p>Le seul problème de ce path_finding actuel, c'est qu'il faut éviter que le chemin, se trouve sur les bord,</p> <p>sinon on peut passer de l'autre coté de la map dans certain cas, ce qu'il faut a tout prix empêcher.</p> <p> </p> <p>Dans le cas de situation différentes a celle d'un labyrinthe, (quand les chemins ont une grande</p> <p>chance d'être droit, vous pouvez dirigez le path_finding en lui faisant allez dans la direction vers la</p> <p>fin et en transformant la file de départ en pile. Il faut alors pouvoir réécrire un coût d'une bloc si la</p> <p>deuxième fois, le coût est plus faible.</p> <p>Bref, il est facilement améliorable et il ne tiens qu'à vous de le récréer totalement. </p> <p>Et voila le tour est joué, vous avez maintenant un path_finding qui marche</p> <p><a href="https://github.com/daemondragon/pathfinding.git" rel="external nofollow">https://github.com/daemondragon/pathfinding.git</a></p>
  • Cours #1 - Introduction au C

    8
    0 Votes
    8 Posts
    3k Views
    AlexMogA
    <p>Bienvenue pour ce tout premier cours sur le L'introduction au C.<br/><br/><br/> Dans cette première partie, nous allons voir de quoi se compose un programme "de base" en C.<br/><br/><br/><strong>I- Avant propos.</strong><br/><br/> J'aimerais vous informer au niveau des cours qui vont suivre: Le but étant de travailler en étant le plus près possible du fonctionnement de la machine, les seules fonctions autorisées (et vous le verrez pendant les exercices) sont les fonctions System (Googlisez tout ça!).<br/><br/> Donc merci de jouer le jeu jusqu'au bout, et de ne pas utiliser de fonctions "interdites" .<br/><br/><br/><strong>II- Notre premier programme.</strong><br/><br/> Nous allons créer notre tout premier programme.<br/><br/> Le but de ce programme est d'afficher une lettre.<br/><br/><br/> Avant tout: Un programme en C est composé de fonctions, et plus particulièrement de la fonction "main" cette fonction est la fonction principale appelée lors du lancement de notre programme.<br/><br/> Commençons donc par créer un fichier test.c qui contient notre main:<br/>  </p> <pre class="ipsCode prettyprint"> int main() { }</pre> <p>Pour compiler notre programme, nous allons utiliser GCC. Pour des raisons personnelles et utilitaires, je code sous linux, je vais donc vous proposer de suivre tout mes cours sous linux. Vous aurez donc des informations sur la compilation en ligne de commande.<br/><br/><br/> Pour compiler notre programme grâce à GCC, il faut utiliser la commande suivante: gcc test.c -o test<br/><br/> Un fichier "test" viens d'être créé. Vous pouvez le lancer: ./test<br/><br/> Oh! Nous avons compiler notre premier programme en C... Qui ne fait rien (pour l'instant!).<br/><br/><br/> Revenons donc à notre but principal: Créer un programme qui affiche une lettre.<br/><br/> Nous allons donc avoir besoin d'une fonction système d'affichage qui s'appelle "Write" (Lisez le man de Write pour avoir plus d'informations sur cette fonction!).<br/><br/> Créons donc une fonction "my_putchar" qui prendra en argument une variable de type char (caractère) et qui aura pour but de l'afficher:<br/>  </p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } int main() { }</pre> <p>Voila! Nous avons notre fonction d'affichage! A present, affichons notre premier caractère!<br/>  </p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } int main() { my_putchar('A'); }</pre> <p>Compilons tout ça... Oh! Lorsqu'on lance notre programme, il affiche un A !<br/><br/><br/> Un autre exemple: HelloWorld.<br/><br/> Le but de ce programme est d'afficher HelloWorld. Reprenons la base précédente:</p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } int main() { }</pre> <p>Et affichons notre "HelloWorld":<br/>  </p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } int main() { my_putchar('H'); my_putchar('e'); my_putchar('l'); my_putchar('l'); my_putchar('o'); my_putchar('W'); my_putchar('o'); my_putchar('r'); my_putchar('l'); my_putchar('d'); }</pre> <p>On compile tout ça, et on obtient un joli "HelloWorld"!<br/><br/><br/><strong>III - Les variables de type char[]</strong><br/><br/> Nous allons à présent stocker notre chaine de caractères "HelloWorld" dans un tableau de Char, puis nous allons l'afficher:<br/>  </p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } int main() { char mon_mot[] = "HelloWorld"; my_putchar(mon_mot[0]); my_putchar(mon_mot[1]); my_putchar(mon_mot[2]); my_putchar(mon_mot[3]); my_putchar(mon_mot[4]); my_putchar(mon_mot[5]); my_putchar(mon_mot[6]); my_putchar(mon_mot[7]); my_putchar(mon_mot[8]); my_putchar(mon_mot[9]); }</pre> <p>En compilant nous obtenons exactement le même résultat de précédemment.<br/><br/><br/><strong>IV - Les includes.</strong><br/><br/> Avant de commencer avec les includes, sachez que tout ce qui commence par un # sera une commande interprétée par le compilateur.<br/><br/> Les includes permettent d'inclure (logique) le contenu d'un fichier. Il est utilisé pour inclure les .h (headers) dans les fichiers.<br/><br/> Par exemple, la fonction "write" est disponible car le système nous la propose, néanmoins, elle n'est pas déclarée (ce qui provoque un "warning" dans votre code) pour remédier au warning, il suffira d'inclure le header unistd.h. comme ceci:<br/>  </p> <pre class="ipsCode prettyprint"> #include <unistd.h></pre> <p>Les includes system se font avec des <> alors que les includes locales se font avec des "".<br/><br/><br/> Ainsi ma fonction est déclarée, le compilateur sait qu'elle existe, je peux donc l'utiliser sans soucis!<br/><br/><br/><strong>V- Allons un peux plus loin.</strong><br/><br/><br/> A present, affichons notre HelloWorld avec une boucle (je vous laisse la joie de découvrir le fonctionnement de la boucle en cherchant sur le net):<br/>  </p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } int main() { char mon_mot[] = "HelloWorld"; int i = 0; while(mon_mot[i] != '\0') { my_putchar(mon_mot[i]); i = i + 1; } }</pre> <p>Voila! Nous venons de réafficher "HelloWorld". Pourquoi je vérifie la valeur de "mon_mot" dans le while? C'est très simple. Ce qui définit la fin d'une chaine de caractères, c'est le caractère '\0' qui est égal à 0. Or, si un while reçoit 0 en paramètre, il s'arrête. Le while va donc continuer, jusqu'à la fin de la chaine!<br/><br/><br/> Voilà, je ne vous en dirrais pas plus sur ce cours, le but étant de vous donner envie d'en savoir plus par vous même.<br/><br/><br/> A bientôt pour le prochain cours!<br/><br/><br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr<br/>  </p>
  • Commencer la programmation en C

    Pinned
    4
    0 Votes
    4 Posts
    3k Views
    AzadA
    <p>Bonjour,</p> <p> </p> <p>Si vous ne connaissez rien au langage de programmation en C, voici un tutoriel sur le Site du Zéro (aka Openclassroom) très bien rédigé et assez complet pour s'initialiser dans la programmation en langage C :</p> <p> </p> <p><a data-ipb="nomediaparse" href="http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-c" rel="external nofollow">Apprendre à programmer en C</a></p> <p> </p> <p>Je vous invite également à poster un sujet dans ce forum pour donner le résultat de votre apprentissage, vos questions, vos codes ou tout autres résultantes de la lecture de ce tutoriel.</p>
  • "else if" dans une boucle

    13
    0 Votes
    13 Posts
    3k Views
    C
    <p></p><pre class="ipsCode prettyprint"> if (variable >= 0) { } for (index = 0 ; index < 150 ; index++) { else if (untableau[index] == 0) { } } else { } </pre> <p>bonjour à tous,</p> <p>voici un exemple pour illlustrer mon cas.</p> <p> </p> <p>dans l'exemple ci-dessus, le compilateur n'est pas content.</p> <p>mais comment éviter une cascade de "else if" ?</p><p></p><p> des avis ? </p>
  • Cours #4 - Récursivité et stack

    6
    0 Votes
    6 Posts
    6k Views
    AlexMogA
    <p>Bonjour à tous,<br/> Nous passons encore à un autre niveau aujourd'hui, et nous allons voir ensemble la Récursivité, et la notion de Stack.</p> <p><strong>I- La récursivité, c'est quoi?</strong><br/> La récursivité, c'est un autre moyen de provoquer une "boucle" dans une fonction.<br/> C'est totalement différent de ce que je vous ai expliqué avant. Nous avions vu la partie "itérative" du C, qui corresponds à exécuter un programme, ligne par ligne. Ici, nous allons apprendre un peux plus les fonctions de la récursivité, et comment elle réagit sur la stack.<br/> C'est une façon de faire, pour qu'une fonction se rappelle elle-même.</p> <p>Prenons l'exemple suivant:</p> <pre class="ipsCode prettyprint"> int test(int a) { a++; if (a < 12) test(a); return (a); } int main(void) { my_putnbr(test(1));// my_putnbr est une fonction permettant d'afficher une valeur numérique. Vous devez la re-créer ou utiliser printf (ce qui est interdit par la norme! Re-créez la, ça vous apprendra pas mal de choses!) }</pre> <p>La fonction "test" est ici récursive.<br/> Ce code nous affichera: 12<br/> Vous l'aurez compris, la récursivité peut être utile dans plusieurs cas (pour annecdote, my_putnbr peut être codé en 3 lignes avec de la récursivité).<br/> Les fonctions récursives peuvent êtres comparées à des poupées russes s'emboitant.<br/> Ne vous perdez pas! Et ne vous inquiétez pas! Je vais mieux vous l'expliquer en vous expliquant le fonctionnement de la stack.</p> <p><strong>II- La stack? DAFUQ?</strong><br/> Je vais pouvoir vous expliquer une notion qui est assez floue dans le cerveau de beaucoup de développeurs: la stack.<br/> La stack est une mémoire assignée à votre programme pour la prise en charge de tout ce qui est "static" dans votre programme (d'où le nom "stack").<br/> Lors du lancement de votre programme, la stack est vide. Si vous appelez la fonction "test" celle-ci va se rajouter dans la stack. Si, de la fonction "test", vous appelez la fonction "my_putstr" celle-ci va se rajouter dans la stack, de même pour la fonction "my_putchar" contenue dans la fonction "my_putstr" qui fera elle-même appel à la fonction "write" qui se rajoutera à son tour à la stack.<br/> La stack a donc constitué une liste d'exécution. On peut re-définir l'ordre d'exécution précédent<br/> comme ceci:<br/>  </p> <blockquote class="ipsQuote" data-ipsquote=""><div>write - my_putchar - my_putstr - test. <p> </p> </div></blockquote> <p>Il ne faut pas oublier que la stack est une mémoire, et qu'elle va stocker tout ce qui est statique dans notre programme. Donc, si nous la sur-utilisons (une boucle infinie de fonctions par exemple: surempiler les poupées russes), nous risquons de faire segfault (segmentation fault) notre programme (C'est souvent une explication pour les programme qui segfault sans raisons).<br/> Lorsqu'une fonction finit son exécution, elle est supprimée de la stack.<br/> Pour vous faire un schéma, imaginez un tas de vaisselle: à chaque fois, vous rajoutez une assiette sale sur le tat, et lorsque vous faites la vaiselle, vous enlevez vos assiettes dans l'ordre contraire de celui de l'empilation.</p> <p>Reprenons la théorie: Une fonction récursive est une fonction qui se rappelle elle-même. Elle se rajoute donc sur la stack, puis se rappelle. Elle se rajoute donc encore une fois sur la stack, puis se rappelle...etc...<br/> Et là, deux choses peuvent avoir lieu: Soit on atteint la taille maximum de la stack (définie par le système), et on provoque un segfault, sinon, et c'est ce que vous devrez faire la plupart du temps en utilisant les récursifs, vous devez prévoir une condition d'arrêt du rappel de cette fonction, donc à un moment de votre récursivité, vous dites STOP, cette fois je ne me rappelle pas, car mon rôle est terminé. A ce moment là, vous allez libérer la stack de toutes les fonctions que vous avez au préalable ajouté.</p> <p>Le mieux, reste encore de vous montrer un exemple de ce qu'il ne faut pas faire:<br/> Créons un programme qui va afficher "hello" indéfiniment:</p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); } void fg() { my_putchar('h'); my_putchar('e'); my_putchar('l'); my_putchar('l'); my_putchar('o'); my_putchar('\n'); fg(); } int main(void) { fg(); }</pre> <p>Effectivement, on voit "hello" s'afficher plusieurs fois, mais si on laisse tourner notre programme jusqu'à ce que la stack soit remplie, on remarque de notre programme crash, et qu'un segfault est apparu.<br/> C'est l'exemple typique de ce que l'on peut attendre au niveau des problèmes liés à la récursivité.<br/> Un autre exemple, c'est notre légendaire my_putnbr:</p> <pre class="ipsCode prettyprint"> void my_put_nbr(int nb) { if (nb <= 9 && nb >= 0) my_putchar(nb + '0'); else { my_put_nbr(nb / 10); my_put_nbr(nb % 10); } }</pre> <p>c'est typiquement la bonne utilisation de la récursivité.<br/> Voilà, j'espère vous avoir encore aidé au niveau de votre apprentissage avancé du C.<br/> Rendez-vous au prochain cours!<br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr</p>
  • [Fonction utilitaire] explode (ouioui, comme en php ;))

    4
    0 Votes
    4 Posts
    2k Views
    AlexMogA
    <p>Bonjour à tous,</p> <p>Je vais vous fournir une fonction "explode" qui vous permettra de découper une chaine de caractères grâce à un délimiteur.</p> <p> </p> <p><strong>I - Manuel de "explode":</strong></p> <p><strong>NOM:</strong></p> <p>explode - découpage de chaine de caractères.</p> <p> </p> <p><strong>SYNOPSYS:</strong></p> <p>char **explode(char *chaine, char delimiteur);</p> <p> </p> <p><strong>DESCRIPTION:</strong></p> <p>La fonction <strong>explode</strong> vous permettera de découper la chaine "<em>chaine</em>" grâce au délimiteur "<em>delimiteur</em>". Plusieurs délimiteurs peuvent être utilisés en les mettant l'un à côté de l'autre (ex: " \t.,") ou un mot complet (ex: "coucou").</p> <p>Attention: la chaine "<em>chaine</em>" sera modifiée après l'utilisation de <strong>explode</strong>. Si vous souhaitez la garder, pensez à la stocker! (ex: strdump).</p> <p> </p> <p><strong>VALEUR RENVOYÉE:</strong></p> <p>La fonction <strong>explode</strong> renverra un tableau de chaines de caractères contenant, dans chacune des cases, une des itérations trouvées.</p> <p>Si aucune itérations n'a été trouvée, <strong>explode </strong>renverra une version dumpée de la chaine <em>chaine</em>.</p> <p>Si une erreur survient, <strong>explode</strong> renverra <strong>NULL.</strong></p> <p> </p> <p><strong>VOIR AUSSI:</strong></p> <p><a href="http://manpagesfr.free.fr/man/man3/strtok.3.html" rel="external nofollow">strtok(3)</a></p> <p> </p> <p><strong>COPYRIGHT:</strong></p> <p>La fonction <strong>explode</strong> a été crée par AlexMog ainsi que cette page de manuel.</p> <p> </p> <p><strong>II - Le code:</strong></p> <pre class="ipsCode prettyprint"> / ** Code created by AlexMog ** Created the 10/04/2014 at 05:42pm. ** Last update by AlexMog the 10/04/2014 at 05:56pm. ** Please, leave the copyright. */ #include <string.h> char **explode(char *chaine, char *delimiter) { char **ret; char *word; int size; ret = NULL; word = strtok(chaine, delimiter); size = 0; while (word != NULL) { ret = realloc(ret, (size + 2) * sizeof(char*)); if (ret == NULL) return (NULL); strcpy(ret[size], word); word = strtok(NULL, delimiter); ++size; } if (ret != NULL) ret[size] = NULL; return (ret); } </pre> <p>J'espère que vous ferrez bon usage de ce code .</p> <p> </p> <p>N'hésitez pas à me faire vos retours en cas de bugs.</p> <p> </p> <p>Enjoy programming </p> <p> </p> <p>Cordialement,</p> <p>AlexMog.</p>
  • Cours #3 - Pointeurs, tableaux et chaines de caractères

    7
    0 Votes
    7 Posts
    5k Views
    AlexMogA
    <p>Bonjour à tous,<br/> Aujourd'hui, nous allons apprendre à assimiler la notion de pointeurs, de tableaux et de chaines de caractères.</p> <p>Je vais tenter de vous expliquer le fonctionnement d'un pointeur par des exemples variés. Pourquoi?<br/> Eh bien, par mon expérience, la notion de pointeurs est une chose qui m'a fait fuir à l'époque ou j'avais commencé le C, mais uniquement à cause de la difficulté à comprendre le principe. Je vais donc essayer d'être le plus claire possible.<br/> Ce qui nous amène donc à la première partie:</p> <p><strong>I- Un pointeur, Kesako?</strong><br/> Alors, un pointeur, ça n'a rien de bien méchant. C'est une variable, comme les autres, qui permet de contenir une adresse (généralement, l'adresse d'une autre variable, on parle bien sur des adresses MEMOIRE)<br/> Pour mieux comprendre, voyons ce qui se passe lors de la création d'une variable.<br/> Lorsque vous créez une variable, de type char par exemple, lors de l'exécution de votre programme, votre programme va prévoir une place en mémoire pour contenir votre variable. Cette place va être reconnue grâce à une adresse, qui peut être contenue dans un pointeur.<br/> Il faut se dire qu'un type char permet de contenir 8 bit de données (soit en valeur maximale<br/> numérique de 255), et qu'un type int peut contenir jusqu'à 32 bits de données (en fonction de la<br/> version de votre machine, sur un 64 bits, il aura 64 bits).<br/> (Vous comprenez mieux pourquoi les typages ont été inventés, et pourquoi il est important de bien<br/> choisir son type de variable).<br/> Donc, lorsque vous lancer votre programme, la machine va allouer un endroit dans la mémoire et lui donner une adresse qui permettera de dire "ICI, la variable X est stockée".<br/> Un pointeur va donc contenir l'adresse d'une variable, pour pouvoir modifier le contenu de la dite variable (vous verrez que la gestion d'adresses est importante lorsqu'on va jouer avec les tableaux).<br/> Donc, comprenons par l'exemple. Je vais créer un programme, qui définit une variable de type char a, et une autre variable b, qui sera un pointeur sur la variable a.</p> <pre class="ipsCode prettyprint"> void my_putchar(char c) { write(1, &c, 1); // Voir cours 1 pour cette fonction } int main(void) { char a; // Déclaration de la variable a char *b; // Déclaration du pointeur B, le * permet de définir au PC qu'il s'agit d'un pointeur. a = 'b'; // On assigne une valeur à la variable a. my_putchar(a); // ceci affichera: b b = &a; // On assigne à b l'adresse de a, le signe & permet de définir que l'on récupère l'adresse de a dans b b = 'c' // On assigne enfin à l'adresse choisie la valeur 'c'. le * définit que l'on modifie le contenu de l'adresse mémoire et NON PAS l'adresse en elle même! my_putchar(; // On affiche la valeur de b my_putchar(a); // On affiche la valeur de a, et on se rends bien compte qu'elle a changée! return (0); }</pre> <p>Vous savez à présent ce qu'est un pointeur et comment l'utiliser.</p> <p><strong>II- Les tableaux statiques: WTF is that shiet?</strong><br/> Pour faire simple, un tableau, c'est un "regroupement" de variables du même typage, dont les adresses sont suivies les unes après les autres.<br/> Prenons pour exemple une "mémoire" vide:<br/> |00| |01| |10| |11|<br/> | | | | | | | |<br/> Pour l'instant elle ne contient aucune données, déclarons alors notre tableau de char, et ayant 3 de grandeur<br/> |00| |01| |10| |11|<br/> |yy| |xx| |xx| | |<br/> Dans notre cas, yy corresponds au début du tableau, et les xx représentent les valeurs contenues dans ce tableau. Comme vous pouvez le constater, les valeurs se suivent.<br/> Donc, en théorie, si on a un pointeur qui pointe sur l'adresse de yy, on peut parcourir notre tableau.<br/> On peut donc affirmer qu'un tableau n'est rien d'autre qu'un pointeur qui pointe sur la première valeur de celui-ci.<br/> Pour mieux comprendre, imaginons que je déclare un tableau comme ceci:</p> <pre class="ipsCode prettyprint"> char tab[3];</pre> <p>Lorsque je vais tenter d'accéder à la première valeur, je vais donc faire ceci:</p> <pre class="ipsCode prettyprint"> tab[0];</pre> <p>Eh bien, vous pouvez aussi y accéder en utilisant directement l'adresse de ce tableau</p> <pre class="ipsCode prettyprint"> *(tab + (0 * sizeof(char));</pre> <p>Je viens donc de vous démontrer que le contenu des [] n'est que le multiplicateur d'accès à la "case" du tableau. Il suffit d'ajouter à notre pointeur un multiple de la taille de son typage pour accéder à la valeur suivante!<br/> La démonstration est faite: Un tableau est un pointeur. Mais attention! Un tableau est un pointeur, mais un pointeur n'est PAS toujours un tableau.</p> <p><strong>III- Les chaines de caractères: Tu voulais pas plutôt dire chaines de vélo?!</strong><br/> Nous allons essayer de comprendre ensemble comment fonctionne une chaine de caractères. Et il n'y a pas de meilleurs langages que le C pour vous expliquer le principe même d'une chaine de caractères.<br/> Nous avions déjà vu dans le cours #1 qu'une chaine de caractères n'était rien d'autre qu'un tableau contenant, dans chacune de ses cases, un caractère.<br/> Par exemple:</p> <pre class="ipsCode prettyprint"> char tab[6]; tab[0] = 'c'; tab[1] = 'o'; tab[2] = 'u'; tab[3] = 'c'; tab[4] = 'o'; tab[5] = 'u';</pre> <p>le tableau que je viens de déclarer contiendra "coucou".<br/> La déclaration ci-dessus est fausse. Le problème étant que lorsqu'on va vouloir afficher cette chaine, on ne saura JAMAIS lorsqu'elle va s'arrêter, et donc, on risquera de provoquer ce qu'on appelle un "segfault" ou "segmentation fault" (ce qui corresponds à une tentative d'accès mémoire qui n'appartiens pas à votre logiciel).<br/> Il est donc primordial de dire à votre programme quand est-ce que cette chaine s'arrête.<br/> C'est en faite très simple à mettre en place, il suffit de rajouter, dans la dernière case, le caractère '\0' (qui signifie 0 en valeur numérique).<br/> Par exemple:</p> <pre class="ipsCode prettyprint"> char tab[7]; tab[0] = 'c'; tab[1] = 'o'; tab[2] = 'u'; tab[3] = 'c'; tab[4] = 'o'; tab[5] = 'u'; tab[6] = '\0';</pre> <p>Nous venons de définir une fin à notre tableau. Il existe d'autres façon de déclarer un tableau de caractères, comme ceci:</p> <pre class="ipsCode prettyprint"> char tab[] = "coucou";</pre> <p>Vous savez à présent comment fonctionne une chaine de caractères.<br/> Allons encore plus loin à présent. Je vous ai démontré toute à l'heure qu'un tableau était un pointeur.<br/> Je peux donc affirmer que je peut utiliser l'adresse principale d'un tableau pour déclarer une chaine de caractères.<br/> Voyez plutôt:</p> <pre class="ipsCode prettyprint"> char *machaine; machaine = "coucou";</pre> <p>Que c'est il passé ici? C'est très simple. Nous avons déclaré un espace de type "tableau de char" dans notre mémoire grâce aux guillemets que nous avons ajouté lors de la définition de la valeur du pointeur "machaine". Le pointeur pointe donc sur l'adresse du premier caractère. (ici, le premier 'c')<br/> Notre pointeur va donc pouvoir se comporter comme un tableau, puisqu'un tableau est un pointeur.<br/> Voyez par exemple:</p> <pre class="ipsCode prettyprint"> machaine[0]; //renvois c machaine[4]; //Renvois o machaine[7]; // provoquera un segfault // Ici, je change la valeur d'une des cases par une autre valeur: machaine[0] = 'A';// Ma chaine vaut donc "Aoucou"! // Je peut aussi procéder comme ceci: *(machaine + (0 * sizeof(char)) = 'A';</pre> <p>Voila, je viens de vous inculquer les bases de la gestion de pointeurs et de tableaux.<br/> A bientôt pour un prochain cours!<br/> Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr</p>
  • Cours #2 - Introduction aux fonctions

    2
    0 Votes
    2 Posts
    2k Views
    NitramN
    <p style="text-align:center;">Hey tout le monde !</p> <p style="text-align:center;"> </p> <p style="text-align:center;"> </p> <p style="text-align:center;">Aujourd’hui un petit tuto concernant les bases de la programmation en C, et plus particulièrement l’introduction à l’utilisation des fonctions.</p> <p style="text-align:center;"><em>(Attention les codes présents dans ce tutoriel sont principalement en algorithmique, inutile d'essayer de les compiler)</em></p> <p style="text-align:center;"> </p> <p style="text-align:center;"><span style="color:#ff0000;"><strong>/ !\ Ce tutoriel nécessite la connaissance des grandes bases de la programmation en C, notamment les variables, les types, la fonction « main Â», les calculs simples… / !</strong></span></p> <p style="text-align:center;"> </p> <p style="text-align:center;"> </p> <p style="text-align:center;"> </p> <p style="text-align:center;">Les fonctions permettent de structurer un programme en plusieurs « morceaux », un peu comme un puzzle. Le programme est donc mieux organisé, ce qui peut se révéler très utile, par exemple, lors de la recherche d’une erreur…</p> <p style="text-align:center;"> </p> <p style="text-align:center;"> </p> <p>Alors une fonction qu’est-ce que c’est ?</p> <p> </p> <p>Une fonction est un bout de programme destiné à exécuter des actions, ces actions pouvant mener au renvoi d’un résultat, ou non.</p> <p>Un exemple sera plus parlant qu’une explication compliquée. Imaginons que l’on souhaite multiplier un nombre par 3, puis l’afficher. Voici le moyen le plus basique :</p> <p></p><p><span style="color:#0000ff;"><em>main()</em></span></p> <p><span style="color:#0000ff;"><em>{</em></span></p> <p><span style="color:#0000ff;"><em>     entier nombre = 5 ;</em></span></p> <p><span style="color:#0000ff;"><em>     nombre = nombre3 ;</em></span></p> <p><span style="color:#0000ff;"><em>     afficher nombre ;</em></span></p> <p><span style="color:#0000ff;"><em>     return 0;</em></span></p> <p><span style="color:#0000ff;"><em>}</em></span></p> <p></p><p>On crée une variable nombre, on la multiplie par trois, puis on l’affiche. Le tour est joué. Voyons maintenant le même programme mais avec une fonction (explications ensuite):</p> <p></p><p><span style="color:#0000ff;"><em>entier triple (entier nombre) // <strong>1. Création de la fonction</strong></em></span></p> <p><span style="color:#0000ff;"><em>{</em></span></p> <p><span style="color:#0000ff;"><em>     entier resultat = 0;</em></span></p> <p><span style="color:#0000ff;"><em>     resultat = nombre3 ; // <strong>2. Instructions executées par la fonction</strong></em></span></p> <p><span style="color:#0000ff;"><em>     return resultat ; // <strong>3. renvoi du resultat</strong></em></span></p> <p><span style="color:#0000ff;"><em>}</em></span></p> <p> </p> <p><span style="color:#0000ff;"><em>main()</em></span></p> <p><span style="color:#0000ff;"><em>{</em></span></p> <p><span style="color:#0000ff;"><em>     afficher triple(5); // <strong>4. Appel de la fonction</strong></em></span></p> <p><span style="color:#0000ff;"><em>     return 0;</em></span></p> <p><span style="color:#0000ff;"><em>{</em></span></p> <p></p><p><strong>1. Création de la fonction</strong></p> <p> </p> <p>Le modèle de création d'une fonction est celui-ci:</p> <p></p><p><span style="color:#0000ff;"><em>type nom_de_la_fonction (paramètre_entrant)</em></span></p> <p><span style="color:#0000ff;"><em>{</em></span></p> <p><span style="color:#0000ff;"><em>     // Instructions</em></span></p> <p><span style="color:#0000ff;"><em>}</em></span></p> <p style="margin-left:35.4pt;"> </p> <p style="margin-left:35.4pt;"> </p> <p style="margin-left:35.4pt;">- "type" correspond au type de la sortie de la fonction. Dans notre exemple, la fonction "triple" renvoie un entier.</p> <p style="margin-left:35.25pt;">- "nom_de_la_fonction" est en fait le nom que vous souhaitez donner à votre fonction. Pour notre exemple, j'ai nommé notre fonction "triple".</p> <p style="margin-left:35.25pt;">- "paramètre_entrant" correspond aux valeurs avec lesquelles la fonction va travailler. Dans l'exemple la fonction va travailler avec un nombre, j'ai donc nommé son paramètre en conséquence. Un paramètre doit être précédé de son type, dans l'exemple, un entier.</p> <p></p><p><strong>2. Instructions executées par la fonction</strong></p> <p> </p> <p>Tout bonnement des instructions qui seront par la suite executées par la fonction. Pour l'exemple, les seules instructions données consistent à tripler notre nombre de base, celui rentré en paramètre, et à le stocker dans une variable nomée "resultat".</p> <p></p><p><strong>3. Renvoi du résultat</strong></p> <p> </p> <p>Cette commande ordonne à la fonction de renvoyer la valeur de la variable "resultat" (15 dans l'exemple).</p> <p></p><p><strong>4. Appel de la fonction</strong></p> <p> </p> <p>C'est à ce moment que l'on va réellement utiliser notre fonction. Un appel de fonction suit ce shéma:</p> <p> </p> <p>nom_de_la_fonction(valeurs souhaitées en paramètre)</p> <p> </p> <p>Il suffit d'écrire le nom de la fonction, et d'entrer entre parenthèses les valeurs que l'on souhaite que la fonction traite. Pour faire simple, lorsque vous appelez une fonction, c’est comme si le programme faisait un copier-coller des instructions de la fonction.</p> <p></p><p>Donc lorsqu’on écrit « triple(5) Â», le programme calcule le triple de 5 par le biais de la fonction nommée « triple Â». Ce résultat n’est stocké nulle part par défaut, il est juste calculé. Il est donc nécessaire de soit le stocker dans une variable (pour le réutiliser plus tard), soit l’afficher directement, comme dans l’exemple.</p> <p>Et là je vous entends d’ici (si si je vous assure  ) : « Mais pourquoi se casser la tête à faire une fonction ? Dans l’exemple c’est beaucoup plus facile sans ! Â» Oui, mais là il s’agit d’une simple multiplication par trois. Certaines fonctions font des milliers de lignes ! Votre main sera donc beaucoup plus propre et compréhensible avec des fonctions ! De plus, les fonctions permettent d’exécuter plusieurs fois la même action (comme une multiplication par trois) sans avoir à retaper le code, et ce, avec autant de valeurs que l’on veut (Notre exemple multiplie 5 par 3, mais il suffit de taper « triple(20) Â» pour obtenir le triple de 20).</p> <p>Donc gain de temps et de place. En voilà un outil pratique !  </p> <p></p><p style="text-align:center;">Voilà c’est à peu près tout, il s’agit là d’un tutoriel très basique, destiné à vous faire comprendre le fonctionnement des fonctions. Si vous êtes intéressés, je vous invite à parcourir <a href="http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-c/les-fonctions-1" rel="external nofollow">ceci</a>, afin d’approfondir ces explications.</p> <p style="text-align:center;"> </p> <p style="text-align:center;"> </p> <p style="text-align:center;">Si vous avez des questions ou des suggestions pour perfectionner ce tutoriel, n’hésitez pas !  </p>
  • [Cryptage] XOR Fait maison

    9
    0 Votes
    9 Posts
    6k Views
    K
    <p>Bonjour tout le monde,</p> <p> </p> <p>Je vais vous montrer un petit programme simple qui va permettre de crypter et de décrypter un fichier à l'aide de l’algorithme XOR.</p> <p>Cet algorithme est très simple et léger, il offre une bonne protection sans plus, vous pouvez choisir la clé de cryptage que vous voulez.</p> <p> </p> <p>Commencez par créer une solution DOS Win32 en C++ sous Visual Studio (2010 pour ma part), puis dans le fichier source main (principal) mettez ceci :</p> <pre class="ipsCode prettyprint"> #include "stdafx.h" #include <stdio.h> #include <STDLIB.H> #include <string.h> /------------------------------------------------------------------/ /------------------------------------------------------------------/ /------------------------------------------------------------------/ int crypt (char *clefc,char pathc[255],char targetc[255]);/fonction de cryptage/ int decrypt (char *clefd,char pathd[255],char targetd[255]);/decryptage/ void bann();/Montre comment utiliser le programme/ void test(char *fnc,char *cl,char pathg[255],char target[255]);/permet d'analyser l'entrée en ligne de commande/ FILE *fichier; /handle vers le fichier source/ FILE *dest; /handle vers le fichier destination/ /------------------------------------------------------------------/ /------------------------------------------------------------------/ /------------------------------------------------------------------/ int main(int argc, char argv[]) { / Vérifie le nombre d'argument en ligne de commande et s'il est exact il les teste pour determiner l'action a faire*/ if (argc==1 || argc==2) bann(); else test(argv[1],argv[3],argv[2],argv[4]); return 0; } /................................................................./ void bann() { puts("\n\t\t<------------------XorCrypt-------------------->"); puts("\t\t<-------------------------------------------->\n"); puts("Fonctionnement :"); puts("xorcrypt -c nom_de_fichier clef Destination : Crypte le ficher"); puts(" -d nom_de_fichier clef Destination : Decrypte le fichier"); puts("Exemple : xorcrypt -c texte.txt clef texte2.txt\n"); system("pause"); } /................................................................./ /* Test des valeurs entrées en argument de la ligne de commande / void test(char fnc, char cl, char pathg[255],char target[255]) { if (strcmp(fnc,"-c")==0) crypt(cl,pathg,target); else if (strcmp(fnc,"-d")==0) decrypt(cl,pathg,target); else bann(); } /................................................................./ / Fonction de cryptage*/ int crypt (char clefc,char pathc[255],char targetc[255]) { int pd=0;/initialisation du compteur de la clef/ int c; int i; if (clefc!=NULL && pathc!=NULL && targetc!=NULL)/ Verification des arguments necessaires*/ { if (fichier=fopen(pathc,"rb"))/* ouverture du fichier source en mode lecture binaire / { dest=fopen(targetc,"wb");/ ouverture du fichier destination en mode ecriture binaire / puts("Fichier ouvert\n Encryption en cours..."); while((c=fgetc(fichier))!=EOF)/ En boucle jusqu'a la fin du fichier*/ { c=~c;/Réalise une inversion des bits du caractere/ c^=clefc[pd];/* Effectue un XOR sur le caractere avec un caractere de le clef / fprintf(dest,"%c",c);/ ecrit le caractere dans le fichier */ if (pd!=strlen(clefc))/*test de la clef */ {pd+=1;} else {pd=0;} } puts("Encryption effectuée"); fclose(fichier); fclose(dest); } else { puts("Impossible d'ouvrir le fichier"); } } else puts("Argument manquant"); return false; } /................................................................./ /fonction de decryptage/ int decrypt (char *clefd,char pathd[255],char targetd[255]) { int pd=0; int c; int i; if (clefd!=NULL && pathd!=NULL && targetd!=NULL) /*Test des arguments necessaires / { if (fichier=fopen(pathd,"rb"))/ ouverture du fichier source en lecture binaire / { dest=fopen(targetd,"wb"); / fichier destination en lecture binaire / puts("Fichier ouvert\n Decryptage en cours ..."); while((c=fgetc(fichier))!=EOF)/ Boucle tant que le fichier n'a pas été entierement parcouru / { c^=clefd[pd]; / applique un XOR sur un caractere avec un caractere de la clef / c=~c; / Rotation des bits */ fprintf(dest,"%c",c); /*ecriture dans le fichier destination / if (pd!=strlen(clefd)) / Test de la clef */ {pd+=1;} else {pd=0;} } puts("Decryptage effectué"); fclose(fichier); fclose(dest); } else { puts("Impossible d'ouvrir le fichier"); } } else puts("Argument manquant"); return false; } </pre> <p>Vous enregistrez, vous compilez, vous récupérez l'exe et vous le mettez dans un dossier tout seul, renommez-le en xorcrypt.exe</p> <p> </p> <p><u><strong>I. Le Cryptage</strong></u></p> <p>Ensuite vous allez créer un .bat nommé Crypt.bat, dedans vous y mettez :</p> <pre class="ipsCode prettyprint"> xorcrypt -c nocrypt.txt %CLEF% crypt.txt</pre> <p>Remplacez %CLEF% par un mot, un SHA1, un MD5, ce que vous vouez, sans espace. Et remplacez nocrypt.txt par le fichier source <u>non crypté</u>, et crypt.txt par le fichier destination <u>crypté</u>.</p> <p><em><span style="font-size:12px;">Fonctionne avec toute les extensions de fichier.</span></em></p> <p> </p> <p>Mettez-le dans le même dossier que xorcrypt.exe, et mettez le fichier .txt(ou autre) source au même endroit que les 2 fichier précédents. Lancez Crypt.bat et votre fichier va se Crypter.</p> <p> </p> <p><u><strong>2. Le décryptage</strong></u></p> <p>Créer un .bat nommé Decrypt.bat, mettez-le dans le même dossier que les 2 autres fichiers (xorcrypt et Crypt), et remplissez-le comme ceci :</p> <pre class="ipsCode prettyprint"> xorcrypt -d crypt.txt %CLEF% nocrypt.txt </pre> <p>Remplacez %CLEF% par la même clef qui a servi au cryptage de ce fichier. Et remplacez crypt.txt par le fichier source <u>crypté</u>, et nocrypt.txt par le fichier destination <u>décrypté</u>. Lancez Decrypt.bat et votre fichier va se décrypter.</p> <p> </p> <p>Le tour est joué, vous pouvez désormais crypter un fichier et le décrypter très simplement, il ne reste plus qu'à implanter le décryptage dans un programme pour pouvoir crypter le contenu (pour un jeu par exemple) </p> <p> </p> <p><em>Code fournit par <a href="http://codes-sources.commentcamarche.net" rel="external nofollow">http://codes-sources.commentcamarche.net</a> et remanié par Karles. </em></p> <p> </p> <p>Cordialement,</p> <p>Karles</p>