-
Compteur de contenus
322 -
Inscription
-
Dernière visite
-
Days Won
34
Tout ce qui a été posté par AlexMog
-
Bonjour à tous, Dans ce cours, nous allons voir ce qu'est une liste chainées, et comment elle fonctionne. I- Liste chainée? WTF? D'après Wikipedia: "Une liste chaînée désigne en informatique une structure de données représentant une collection ordonnée et de taille arbitraire d'éléments de même type". Pour résumer, il s'agit d'une collection de données (comme un tableau, sisi), qui a une taille variable, donc on a pas besoin de connaitre la taille de la liste à l'avance (un peu comme dans le cours sur les allocations dynamiques ). Les éléments sont enregistrés les uns après les autres. C'est donc une grosse liste de données. Le premier élément pointe vers le second, le second vers le troisième, le troisième vers le quatrième etc... Comme le montre le schéma ci-dessous: (Source: Openclassroom) C'est une liste chainée simple, et nous ne verrons que celle-ci. Pour la liste chainée circulaire, ou encore double, je vous laisse chercher par vous mêmes II- Créons notre structure de données! Une liste chainées à pour but de contenir des données (c'est logique...), il faut donc créer une structure pour stocker lesdites données. Pour ma part de vais créer une liste pour stocker l'age et la taille d'un certain nombre d'utilisateurs. typedef struct s_list { int taille; int age; struct s_list *next; }t_list; Oh! c'est étrange, qu'est-ce que la variable "next" vient faire ici? Comme je l'ai dit plus haut, il s'agit du pointeur sur le prochain élément de notre liste chainée. Il va falloir penser à le mettre à NULL pour connaitre la fin de notre liste chainée! En effet, lorsqu'on sera au dernier élément, on le sera grâce au NULL. Dans ce cours, je vais uniquement vous apprendre à ajouter des éléments à votre liste, à parcourir votre liste, et enfin à supprimer votre liste. C'est à vous d'utiliser votre tête pour la suite! III- Ajouter un élément à la liste. Maintenant que notre structure est crée, nous allons créer plusieurs fonctions, pour gérer notre liste chainée. Créons tout d'abord une fonction pour ajouter un élément à la liste: int add_to_list(t_list **list, t_list *datas) { t_list *next; next = NULL; if (*list != NULL) next = *list; if ((*list = malloc(sizeof(t_list))) == NULL) return (1); (*list)->taille = datas->taille; (*list)->age = datas->age; (*list)->next =next; return (0); } Voici un exemple d'utilisation de la fonciton: int main(void) { t_list *list; t_list datas; *list = NULL; datas.age = 10; datas.taille = 180; // On ajoute à notre liste if (add_to_list(&list, &datas)) return (1); // On récupère le premier noeud pour voir ce qu'il contient printf("Age: %d, Taille: %d\n", list->age, list->taille); return (0); } III- Parcourons notre liste! Nous allons à présent parcourir notre liste. int main(void) { t_list *list; t_list datas; int i; i = -1; // On remplis notre liste avec 10 éléments while (++i < 10) { datas.age = i; datas.taille = 180 + i; if (add_to_list(&list, &datas)) return (1); } // On parcours et on affiche notre liste! while (list != NULL) { printf("Age: %d, Taille: %d\n", list->age, list->taille); list = list->next; } return (0); } IV- Vidons notre liste! (C'est important de vider la mémoire!) Pour cela, créons une fonction de vidage. void clear_list(t_list **list) { t_list *elem; t_list *next; elem = *list; while (elem) { next = elem->next; free(elem); elem = next; } *list = NULL; } Exemple d'utilisation: int main(void) { t_list *list; t_list datas; int i; i = -1; // On remplis notre liste avec 10 éléments while (++i < 10) { datas.age = i; datas.taille = 180 + i; if (add_to_list(&list, &datas)) return (1); } // On parcours et on affiche notre liste! (on utilise un pointeur annexe pour ne pas perdre le noeud mère) list *elem = list; while (elem != NULL) { printf("Age: %d, Taille: %d\n", elem->age, elem->taille); elem = elem->next; } clear_list(&list); return (0); } Je vous laisse la joie d'analyser le code, à ce stade des cours (et si vous avez bien tout suivi) vous savez analyser le code, je vous laisse donc le comprendre par vous mêmes! Je reste disponible pour répondre à vos questions! A bientôt pour un prochain cours!
-
J'ai fait une màj rapide pour la sécu du serveur.
-
OK, amusant, je part du principe qu'on a le droit aux fonctions de la libc, ce qui donnerais: #include <stdlib.h> int strend(char *s, char *t) { char *tmp; tmp = s; while ((tmp = strstr(tmp, t)) != NULL); return (tmp != NULL && strlen(tmp) == strlen(t)); }
-
Nice ana
-
Je me suis mal exprimé, je veux dire qu'avec de la SDL, tu peux gérer les fenetres pour ajouter OpenGL (puisque SDL utilise OpenGL, alors tu peux appliquer OpenGL sur SDL ). OpenGL est un simple outil de calcul, ce n'est pas lui qui fait le fenetrage
-
OpenGL est encore plus bas niveau, puisque la SDL se base sur openGL. (On peut utiliser la SDL uniquement pour du fenêtrage OpenGL d'ailleurs!)
-
Le tchat est à présent en version 092. Merci de tester
-
A SAVOIR: tu as cité ici des variétés qui utilisent le LUA, sauf que le LUA n'est pas du tout utilisé dans WoW (hors serveurs privés, je parle ici de WoW officiel). WoW utilise des librairies externes pour gérer les IA et les adaptations serveur (le serveur n'étant qu'un core qui load les librairies => Plus performant que le LUA => Un seul chargement => Pas d'interprétation => Tous les développeurs crée leur "brique" et le core les lie en les chargant.) Le LUA est très souvent utilisé pour les IA, ou encore la gestion onRun. Je m'explique: le LUA est un langage de script utilisé dans plusieurs programmes. Celui-ci est principalement apprécié car le programme n'a pas forcémment besoin d'être re-démarré pour lire les fichiers. Du côté serveur, il est donc très appréciable. Ensuite, comment il foncitonne? En LUA, vous pouvez utiliser tout ce qui vous passe par l'espris (héoui, c'est du scripting interprété par votre exécutable) et donc, gérer les objets du core par exemple. Le "core" (donc, le logiciel qui va utiliser le LUA) va donc appeller des fonctions du LUA (que vous aurez programmé en LUA) exactement comme des fonctions dans son propre langage! Ce qui permet de faire énormément de choses! Voilà, j'espère que vous vous y intéresserez. Je travaille sur un projet qui pourrait vous faire apprécier le LUA, mais chut, je le publierais peut être . Cordialement, Alexmog.
-
Salut pas mal comme cours, mais sache que tu peux très bien faire un typedef directement sur ta scruct: typedef struct ma_struct { }t_ma_struct; C'est utile de le faire avant uniquement si il est utilisé dans la structure ^^. Sinon, c'est effectivement une IA assez basique, on voit des IA balaises de temps en temps, mais là, c'est vraiment l'IA classique des jeux-vidéos. Bien joué
-
L'utiliser pour les memory leaks et aussi très intéréssente . J'ai déjà cité Valgrind dans le cours #0 justement . GDB est aussi parfait pour ce genre de travail.
-
Toutes les applications qui nécessitent de vérifier des chaines (par exemple, un lexeur parseur ). Pour exemple, j'en utilise une au niveau du serveur du Melichat. Ça simplifie pas mal le code.
-
Sortie du site de la doc C99: "The #ifndef/#define/#endif trick works on any C compiler, and on some of them it speeds up the compilation process. The #pragma trick is non-standards, and only works on few C compilers, and may result in different semantics in those that do not support it.". Pour résumer, #pragma n'est pas standard. Et n'est pas définit dans la C99. Il n'est donc pas conseillé de l'utiliser.
-
Bonjour à tous, 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. I- Pointeur sur fonction? Kesako? Un pointeur sur fonction, c'est simplement une manière d'appeler une fonction, en passant par un pointeur. Par exemple: void (*function_pointer)(char); function_pointer = &my_putchar; // Vous pouvez retrouver la fonction my_putchar sur le cours #1. function_pointer('A'); 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). Il affiche 'A'. II- Utilité? 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. Exemple de tableau de pointeurs sur fonction: #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); } III- Déclaration et appel. Enfin, voyons comment déclarer un pointeur sur fonction, puis comment lui définir une fonction. Déclarons notre pointeur. Forme de déclaration: typage_renvoyé_par_la_fonction (*nom_pointeur)(arguments_pris_par_la_fonction); Par exemple, pour printf: 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"); Voilà. 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. Je vous dis a bientôt pour un prochain cours! Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr
-
Bonjour à vous, Dans ce cours, nous allons voir à quoi corresponds un fichier header, ainsi que comment créer une librairie, et enfin, les structures! I- Qu'est-ce qu'une lib? Une lib, aussi nommée librairie (dynamique ou statique) est un fichier binaire contenant une liste de fonctions prédéfinies. Je vais vous donner un exemple de son utilisation, et pourquoi il est bon de créer une lib! 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. 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. Pour mieux vous faire comprendre tout cela, créons trois fichiers distincts: main.c: 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++)); } Tentons à présent de compiler main.c: 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. Maintenant, tentons de compiler tous nos fichiers en même temps: 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! 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? 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). Créons donc nos .o! (man cc pour plus d'informations) 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. 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. 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. Nous l'appellerons libmy.a: Pour créer notre lib, voici la commande linker (je vous laisse le soin de lire le man de celle-ci): 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. 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): Hop! Nous avons notre a.out fonctionnel! Vous savez à présent créer vos propres librairies! II- Les fichiers Header 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. 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). Un header, c'est donc un fichier de préparation à la compilation. Il contiendra ainsi les prototypes des fonctions utilisées dans notre programme. Vous pouvez trouver des exemples de headers dans les librairies que nous avions déjà utilisé! Souvenez-vous: Nous avions utilisé: #include <unistd.h> qui corresponds à inclure le fichier .h de la libraire unistd. les <> signifient que le header se trouve dans le dossier include de notre compilateur. Pour inclure un fichier local, il suffit de faire tout simplement! Donc revenons sur notre histoire de warnings, nous allons créer un .h pour la lib précédente que nous avons créé: #ifndef _MY_H_ #define _MY_H_ void my_putchar(char); void my_putstr(char *); #endif /* _MY_H_ */ Je vais vous expliquer le fichier lignes par lignes. Mais avant cela, je vais vous expliquer ce qu'est un define. 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. Voici un exemple simple: #define VERSION "1.0.0" J'ai définit VERSION comme ayant comme value 1.0.0 Je peux le ré-utiliser dans mon code, si j'inclus le fichier .h qui contient ce define, comme ceci: int main(void) { my_putstr(VERSION); return (0); } ATTENTION: il ne s'agit pas d'une variable. Un define est remplacé par le compilateur par la valeurqui lui est destinée! J'espère que vous m'aurez compris... Passons donc à la définition de notre fichier .h: #ifndef _MY_H_ 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. #define _MY_H_ Si notre fichier n'a jamais été inclus, nous définissons qu'il l'a à présent été void my_putchar(char); void my_putstr(char *); On y ajoute ensuite les prototypes des fonctions utilisées... #endif /* _MY_H_ */ Enfin, on ferme notre "#ifndef" (if not defined). Nous y sommes, revoyons notre main à présent: #include "my.h" int main(void) { my_putstr("coucou\n"); return (0); } Compilons le: Et voilà! Plus aucun warnings ou erreurs! Nous pouvons passer à la suite! III- Les Structures. 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). Construction d'une structure: struct s_nom_de_ma_struct { int valeur_numerique; char valeur_caractere; typpage valeur_n'importe_quel_typpage; }; C'est aussi simple que cela. 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 chaine de caractère "texte": struct s_mastruct { char *pseudo; char *texte; }; Nous allons afficher les données de notre structure: 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); } Ce code nous affichera: A SAVOIR: lorsque vous utilisez un pointeur sur structure (comme dans la fonction set_structure) les "." sont remplacés par "->". 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! Rendez-vous dans le .h: struct s_mastruct { char *pseudo; char *texte; }; et créons notre nouveau typage: typedef struct s_mastruct { char *pseudo;char *texte; } t_mastruct; Nous pouvons à présent déclarer nos structures comme ceci: Cool n'est-ce pas ? 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)). Voilà! A très bientôt pour un prochain cours! Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr
-
Bonjour à tous, Bienvenue dans ce 4ième cours sur la programmation en C. Aujourd'hui, nous allons voir un point intéréssent de notre programme, et un point clé en C: les Arguments de lancement, et les allocations dynamiques. I- Qu'est-ce qu'un argument de lancement? 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). Ainsi, si je lance le programme avec cette ligne de commande: mon programme recevra comme argument 1 : "mon_argument". (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). Quelques exemples d'utilisations d'arguments: Les commandes unix utilisent très souvent les arguments: 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: II- Récupérer des arguments de lancement Nous avions vu la structure basique d'un main en C: int main(void) { } Eh bien, je ne vous ai pas dit la vérité sur cette fonction! En effet, main peut prendre un void pour argument (et donc ne prendre aucun arguments), ou bien prendre un int, et un char **. Le véritable prototypage de la fonction main est donc: int main(int argc, char **argv) { } En voyant ça, vous allez me dire "dis donc, j'ai mal à la tête, y'a un ** dans ton code!" Eh bien ne vous inquiétez pas, il s'agit d'un tableau de chaines de caractères.Prenons pour exemple ce programme lancé comme ceci: coucou arg1 arg2 arg3 je suis fou Eh bien, nous pouvons récupérer les arguments de ce programme de la façon suivante: /* ** 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); } Nous butons à présent sur un problème, ré-utilisons le programme précédent, mais supprimons tous, ou un des arguments: 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. Pour remédier à cela, les développeurs nous ont rajoutés "argc". Pour mieux vous faire comprendre, je vais vous définir exactement ce que signifie argc et argv: 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. ArgV est un couplage entre les mots: Argument et Value, il s'agit donc des valeurs de ces dits arguments. Maintenant que vous avez le nombre d'arguments, vous pouvez vérifier que le nombre d'arguments est correcte avant de l'afficher: int main(int argc, char **argv) { if (argc > 1) my_putstr(argv[1]); return (0); } 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). Passons à présent à la partie complexe de ce cours: les allocations dynamiques. III- Les allocations dynamiques L'allocation dynamique, c'est l'art de savoir utiliser sa RAM et les répercussions de l'alloc sur celle-ci. 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. Comme ceci: char mon_tableau[talle_de_mon_tableau]; Là est le problème, imaginons que nous devions modifier notre chaine, en lui imposant une taille plus grande: SegFault. 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)) 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! Prenons un exemple simple: J'ai un programme qui connaît la taille d'une chaine de caractère, et je dois la stocker dans une variable: int main(void) { int lenght = 300000; // Oui, notre chaine est très longue } 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. C'est problématique, en effet. Tentons donc d’allouer un emplacement dans la ram pour cette chaine: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); } Tiens, ça marche! Lisons un peu mieux le man de malloc: en cas d'erreur, malloc retourne NULL. Nous allons donc vérifier si il y a eu une erreur (pour éviter le segfault): int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } } 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! Nous pouvons donc remplire "ptr" exactement comme un tableau (case par case, voir cours sur les chaines de caractères). ATTENTION: ptr est un POINTEUR. Si vous modifiez son adresse, vous perdez l'ancienne adresse allouée! Donc ceci: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } ptr = "coucou"; } est interdit et stupide (ne rigolez pas, les profs de programmation font souvent l'erreur!). 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! Pour la vider, la fonction "free" est là pour nous aider! Voilà mon programme une fois la fonction "free" utilisée: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } free(ptr); } Tout marche! Cool! ATTENTION: pour bien vous montrer que modifier un pointeur est une mauvaise idée, tentez de faire ceci: int main(void) { char *ptr; ptr = malloc(300000 * sizeof(char)); if (ptr == NULL) { my_putstr("Erreur malloc\n"); return ; } ptr = "coucou"; free(ptr); } 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 allouée. Pour vous montrer que mon code fonctionne, je vais afficher ma chaine de caractère, qui fera l'alphabet avec 300 000 lettres! 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); } Et voilà, vous savez à présent utiliser les allocations dynamiques! A bientôt pour le prochain cours! Cours écrit par AlexMog. Contact: alexmog [at] live [point] fr
-
ATTENTION: Ici, tu passe la map en COPIE! C'est pas du tout propre, et tu fais très très mal à ta stack (tu copie toute la map dans ta stack, donc, si tu as une map trop grande, PAFF! Segfault.) Envois plutot un int **map au lieu d'un int map[][haueur] .
-
Je préviendrais dès que j'aurai sorti une version compatible Windows
-
Salut à tous, Je suis en train de revoir totalement ma lib réseau. J'ai changé pas mal de principes. Entres autre, j'ai ajouté la possibilité d'avoir de l'Asynchrone, ce qui n'était pas possible avec l'ancienne lib. La nouvelle lib est faite pour fournir plusieurs outils, et pour fonctionner aussi bien sur Linux que sur Mac et Windows! Pour l'instant elle est en état de développement, mais plusieurs objets sont déjà fonctionnels. Voici le nouveau git qui lui est dédié: https://github.com/AlexMog/LibNet Une documentation HTML et LaTeX est disponible dans le dossier doc ou ici: http://alexmog.labs-epimars.eu/projets/mognetwork-doc/doc/html/ N'hésitez pas à la tester et à me faire des retours! Enjoy! Mog.
-
[Recherche] Personne à l'aise avec le HTML/CSS/Javascript (websockets)
topic a répondu à un AlexMog de AlexMog dans Discussions générales
Normal, je suis un flemmard ._. -
keya?
-
La présentation d'un homme qui voulait se présenter sans y être forcé.
topic a répondu à un Danalieth de AlexMog dans Présentation des membres
Bienvenue -
Attention tout de même , le serveur est encore en 086, la version en dev est 092
-
[Recherche] Personne à l'aise avec le HTML/CSS/Javascript (websockets)
topic a répondu à un AlexMog de AlexMog dans Discussions générales
Petite mise à jour du protocole. (Ajout de la commande LOG) -
[Recherche] Personne à l'aise avec le HTML/CSS/Javascript (websockets)
topic a répondu à un AlexMog de AlexMog dans Discussions générales
j'ai clean le protocole, et je l'ai mis sur une page dédiée: http://labs-epimars.eu/alexmog/projets/melichat/protocole.html
