FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 27, nombre de questions : 175, dernière mise à jour : 17 décembre 2010  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.


SommaireDivers bisBonnes pratiques (3)
précédent sommaire suivant
 

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 sources C++ portent l'extension .cpp et les fichiers sources C l'extension .c, mais cela peut changer d'un compilateur à un autre. Il faut donc faire bien attention sur ce point là.

Mis à jour le 20 septembre 2004 gl Pouet_forever

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; 
}
En effet, le spécificateur de format %d indique que scanf() doit effectuer la lecture des caractères à partir de la position courante dans le tampon de lecture de l'entrée standard avec les règles suivantes :

Code c : 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
Ainsi, en tapant "ab12" par exemple, 'a' étant un caractère invalide dans l'expression d'un entier, le curseur de scanf() n'avancera jamais (il restera éternellement bloqué face à ce caractère !).

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
43
44
45
46
47
#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 chaine tapee. */ 
  
        fgets(buffer, sizeof(buffer), stdin); 
  
        /* Supprimer le '\n' de la chaine 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 chaine 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; 
}

Mis à jour le 20 septembre 2004 Emmanuel Delahaye gl

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

Mis à jour le 20 septembre 2004 Emmanuel Delahaye gl

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2016 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.

 
Contacter le responsable de la rubrique C