char
(et vice-versa) ?sizeof(char)
?sizeof('a')
ne vaut pas 1 ?gets()
?scanf()
?strcmp()
, et non l'opérateur
==
. Celui-ci comparera les pointeurs entre eux, ce qui
n'est probablement pas ce qui est voulu !
const char * sz = "non";
if(strcmp(sz, "oui") == 0) {
/* sz et "oui" sont egaux */
}
Il existe aussi la fonction strncmp()
qui permet de
contrôler la longueur de comparaison.
strcpy()
,
et non l'opérateur d'affectation =
.
Il faut s'assurer que l'on dispose d'espace suffisant dans la
chaîne cible avant d'utiliser strcpy()
, qui ne fait
aucun contrôle de débordement.
Pour une copie plus sécurisée, on préférera la fonction
strncpy()
.
fgets()
.
char tab[20];
fgets(tab, sizeof tab, stdin);
Voici un exemple complet d'utilisation propre de
fgets()
pour la lecture d'une ligne, avec un contrôle
d'erreurs. Cette fonction est fournie par Emmanuel Delahaye.
#include <stdio.h>
#include <string.h>
int get_line(char *buf, size_t size) {
int ret; /* 0=Ok 1=Err 2=Incomplet
* On peut aussi definir des constantes. (Macros, enum...)
*/
if (fgets(buf, size, stdin) != NULL) {
char *p = strchr(buf, '\n'); /* search ... */
if (p != NULL) {
*p = 0; /* ... and kill */
ret = 0;
}
else {
ret = 2;
}
}
else {
ret = 1;
}
return ret;
}
Il peut être intéressant dans certains cas de faire un traitement particulier dans le cas 2 (lecture incomplète), comme vider le buffer du flux ou redimentionner la zone de réception (voir la question 14.5).
La fonction gets()
est à proscrire, car il n'y a aucun
contrôle de débordement, ce qui peut engendrer de nombreux bugs
(stack overflow) (cf. 8.7).
char
(et vice-versa) ?char
est un petit entier. Il n'y a donc aucune
conversion à faire. Quand on a un char
, on a aussi sa
valeur, et vice-versa.
sizeof(char)
?char
vaut et vaudra toujours 1 indépendamment de
l'implémentation. En effet, les tailles d'allocation en C se
calculent en char
(size_t
). Or, un char
a une taille de 1 char
. Donc
sizeof(char) == (size_t) 1
Pour autant, un char
ne fait pas forcément 8 bits (un
octet) (voir aussi 16.2).
sizeof('a')
ne vaut pas 1 ?int
, et non des
char
. Ainsi,
sizeof('a') == sizeof(int)
ce qui peut valoir 2 ou 4 sur votre machine, ou autre chose.
gets()
?
#include <stdio.h>
int main(void)
{
char chaine[16];
printf("Tapez votre nom :\n");
gets(chaine);
printf("Vous vous appelez %s.\n",chaine);
return 0;
}
Quand on tape une chaîne de plus de 15 caractères, rien ne va plus :
gets()
accepte sans broncher la chaîne mais lorsqu'il
est question de la stocker dans
char chaine[16]
on peut obtenir un magnifique Segmentation fault (core dumped). Dans certains cas, avec certains compilateurs sur certaines machines et certains OS, il est possible que ça passe. Mais attention ! C'est un leurre, et le changement de cible démontrera la malfaçon.
scanf()
?scanf()
est une fonction de la bibliothèque standard, qui est
souvent la première que l'on apprend pour lire des données au clavier.
Cette fonction n'est pas plus dangereuse qu'une autre, à condition de
bien savoir l'utiliser, ce qui n'est pas donné à tout le monde.
Par exemple, regardez le programme suivant donné par Serge Paccalin :
#include <stdio.h>
int main(void) {
int val = 0;
while (val != 1){
printf("Tapez un nombre"
"(1 pour arreter le programme) :\n");
scanf(" %d",&val);
printf("Vous avez saisi %d.\n",val);
}
return 0;
}
Et il explique : « Quand le programme demande un nombre, taper
"toto"
suivi de la touche
Entrée. Le programme part en boucle parce que tous les
scanf()
successifs butent sur "toto"
qui reste
indéfiniment dans stdin
. »
Dans la plupart des cas, l'utilisation de la fonction fgets()
sera plus simple et moins risquée.
scanf()
est une fonction qui peut être utilisée dans
certaines conditions, et à condition de bien savoir ce que l'on
fait. L'utilisation de scanf()
pour la lecture de
nombres (entiers ou flottants) est l'une des plus acceptable.
Par contre, la lecture d'une chaîne avec scanf()
sans
contrôle de format est aussi dangereux que gets()
.
scanf("%s", astring) ;
est donc a proscrire.
scanf()
n'est préférable à fgets()
que dans
le cas ou l'on veut lire mot par mot et non ligne par ligne,
et conserver le reste dans le buffer du flux
d'entrée.
Sinon, lire un mot avec fgets()
ne pose pas de problème
et est même plus simple.
scanf("%4s", astring) ;
Cette construction, par exemple, ne pose pas les problèmes cités plus haut (si le contrôle d'erreurs est fait), et est parfois utile.
Voir aussi les questions 8.7 et 8.3
faq-fclc 5/3/2002 (8h 59:04)