FAQ CConsultez toutes les FAQ
Nombre d'auteurs : 35, nombre de questions : 194, dernière mise à jour : 18 février 2018 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .
Sur ce, je vous souhaite une bonne lecture.
Contrairement aux idées reçues, le cast du malloc() / calloc() / realloc() n'est pas obligatoire en C.
Dans les premières versions du C, le pointeur générique (void *) n'existait pas. La fonction malloc() renvoyait un pointeur de type char *, ce qui rendait le cast obligatoire lorsque le pointeur utilisé pour stocker cette valeur retournée est de type différent.
Le C ANSI a cependant introduit le type « pointeur générique » (void *) qui, au vu des conversions implicites, peut être assigné, sans cast, à un pointeur de n'importe quel type (de même, un pointeur de n'importe quel type peut être assigné, sans cast, à un pointeur générique). Depuis, il n'était donc plus nécessaire de caster malloc().
Si votre compilateur refuse de compiler votre code tant que vous ne castez pas malloc(), alors :
- soit vous utilisez un compilateur non conforme (ce qui est très peu probable de nos jours à moins que vous utilisiez un compilateur datant de l'avant-normalisation, c'est-à-dire un compilateur des années 70 ou 80…) ;
- soit vous compilez en mode « C++ », c'est-à-dire que votre compilateur (qui est donc apparemment capable de compiler aussi bien du code C que du code C++) pense que votre code est écrit en C++ (dans lequel le cast de void * vers un autre type pointeur est obligatoire) et non en C (dans lequel caster malloc() est non seulement inutile, mais aussi de mauvais style). Généralement les fichiers source C++ portent l'extension .cpp et les fichiers source C l'extension .c, mais cela peut changer d'un compilateur à un autre. Il faut donc faire bien attention sur ce point-là.
La fonction scanf() est une fonction destinée, comme le « f » dans son nom l'indique, aux saisies formatées et s'avère ainsi très peu adaptée aux saisies humaines qui peuvent présenter des erreurs de format, ces erreurs de format pouvant entraîner des débordements de tampon, des boucles infinies, des perturbations sur les saisies suivantes, etc. Il est donc conseillé de remplacer les saisies formatées effectuées avec scanf() par une lecture complète via fgets() suivie d'une analyse de la chaîne lue.
Voici par exemple un programme qui entre dans une boucle infinie si jamais l'utilisateur tape quelque chose qui commence par un caractère invalide en début d'un nombre (une lettre par exemple) :
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #include <stdio.h> int main(void) { int n = 0; while (n != 1) { printf("Tapez 1 pour quitter.\n"); scanf("%d", &n); } return 0; } |
Code : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 | Si des caractères sont présents 1. Passer tous les caractères blancs (espaces, tabulations, fins de ligne). 2. Lire les caractères présents jusqu'à la rencontre du premier caractère blanc ou invalide dans l'expression d'un nombre entier. Le caractère qui a arrêté la lecture n'est pas lu par scanf(). Il sera donc le premier caractère rencontré dans la prochaine lecture sur l'entrée standard. 3. Convertir la chaîne lue en entier et stocker le résultat à l'adresse spécifiée. Sinon - Attendre que l'utilisateur tape une ligne. - Appliquer 1, 2 puis 3. Fin Si |
L'utilisation de fgets() permet d'éliminer très simplement ce problème.
Code c : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <stdio.h> #include <string.h> #include <stdlib.h> void clean_stdin(void); /* Voir '[FAQ] Comment vider le buffer du clavier ?'. */ int main(void) { int ok = 0; /* 0 = false */ while (!ok) { char buffer[256], *p; int n; printf("Tapez 1 pour quitter.\n"); /* Lecture de la chaîne tapée. */ fgets(buffer, sizeof(buffer), stdin); /* Supprimer le '\n' de la chaîne lue s'il est présent. */ if ((p = strchr(buffer, '\n')) != NULL) *p = '\0'; else { /* Si le '\n' est absent, vider le buffer du clavier. */ clean_stdin(); } /* Analyse de la chaîne lue. */ n = strtol(buffer, &p, 10); /* strtol permet de passer de "123" (buffer) a 123 (n). */ if (*p == '\0') { /* On peut utiliser n */ if (n == 1) ok = 1; } } return 0; } |
La fonction gets() ne permet pas de spécifier la taille du tampon destiné à contenir la chaîne lue et expose donc le programme aux attaques par débordement de tampon. Cette fonction ne doit donc jamais être utilisée dans un programme digne d'être respecté.
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.