Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Probleme avec scanf

118 réponses
Avatar
Bakounine
bonjour

je suis en train de faire un petit programme client et serveur qui echange
des messages. Dans cetains messages il y a deux valeur separer par des deux
points.

ex:

valeurun:valeurdeux

j'aimerais savoir si sscanf permet de gerer le separateur : ou faut il
utiliser une autre fonction? j'ai utilise sscanf("%s:%s", var1, var2); mais
ca ne marche pas.

Merci d'avance pour votre reponse.

10 réponses

Avatar
Emmanuel Delahaye
Charlie Gordon wrote on 27/04/05 :
- strncpy() ne met pas le 0 final quand il sature (chaine mal formée)


en revanche, il initialise à 0 le reste du buffer quand il ne sature pas, ce
qui est rarement utile


Mais qui n'est pas dangereux...

- strncat() est bien, à condition d'être bien révéillé. (la chaine de
destination doit être initialisée..., ne pas se tromper dans les
tailles passées en paramètre, laisser une place pour le 0 etc.). Je
m'en sert tout le temps pour faire des extractions en une ligne, ça me
va.


attention : pour strncat le parametre numerique est le nombre maximum de char
à prendre dans la source, pas la taille du tableau de destination. Ce qui
signifie qu'il faut s'assurer autrement contre la possibilité d'un
débordement de tableau, y compris par le final.


C'est ce que j'ai dit, non ? Penser à mettre son cerveau avant de
coder, c'est tout...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"There are 10 types of people in the world today;
those that understand binary, and those that dont."


Avatar
Emmanuel Delahaye
Charlie Gordon wrote on 27/04/05 :
Je ne vois pas pourquoi on utiliserait strtok() quand strtok_r() est
disponble.


Et quand il n'est pas disponible, il suffit de l'implémenteer ou un de
ses frères...

http://mapage.noos.fr/emdel/clib.htm
Module TOK

Quant à strncpy() et strncat() : relisez la spec et vous verrez qu'elles ne
font


Je suis d'accord...

pas ce que la plupart des programmeurs pensent savoir ou comprendre. Leur


Là, par contre, le langage C n'est pas responsable de la mauvaise
formation de ses utilisateurs... La définition du langage n'est pas un
cours de C.

utilisation est très souvent incorrecte, source d'inefficacité, d'erreurs ou
de debordements de tableaux (si si!) et donc à déconseiller.


C'est comme feof(). Si les gens sont mal formés, ce n'est pas la faute
du langage. Il est possible d'utiliser ces fonctions correctement. Par
contre une fonction comme gets() est clairement un bug de conception et
ne peut pas être utilisée portablement de façon sûre.

Et je pense qui est de la responsabilité morale de ceux qui savent
(nous, toi, moi) de faire en sorte que les erreurs commises par les
utilisateurs soient corrigées, mais sans crier haro sur le baudet comme
tu as trop tendance à le faire. Il est dommage que tu ne mettes pas
plus tes compétences, qui sont indédiables, au services des
utilisateurs comme beaucoup le font ici, et que tu passes, par contre,
beaucoup de temps à éructer et à vitupérer contre le C... Si tu n'aimes
pas ce langage, laisse le tranquille et cesse d'affoler le newbie... Je
ne sais pas si tu as remarqué, mais la fréquentation est en baisse
régulière. On a pas besoin de ça...


J'affirme que tout programmeur muni d'un cerveau en état de marche est
capable d'écrire du C solide, modulaire, testable et réutilisable. Le
langage n'est pas en cause (il est infiniment plus simple d'être bon en
C que bon en C++, par exemple). Comme souvent le problème est la
formation et les innombrables sites et livres qui continuent à raconter
n'importe quoi sur ce langage, au lieu de lire le K&R, la norme ou
C-Unleashed.

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"Mal nommer les choses c'est ajouter du malheur au
monde." -- Albert Camus.

Avatar
Charlie Gordon
"Emmanuel Delahaye" wrote in message
news:
Charlie Gordon wrote on 27/04/05 :
OK pour les remarques qui n'étaient pas directement à ton attention, et sans
doute pas dans le bon ordre, mais même si on a pas le choix du langage et
qu'on doive traiter des chaines de caractères en C (*) scanf() est une
mauvaise solution, tout comme strtok(), strncpy, strncat() et d'autres.


strncat() est utilisable si on a un cerveau en état de marche.


Je suis moins optimiste que toi : meme la description de l'open group est
confuse :

#include <string.h>

char *strncat(char *restrict s1, const char *restrict s2, size_t n);

The strncat() function shall append not more than n bytes (a null byte and bytes
that follow it are not appended) from the array pointed to by s2 to the end of
the string pointed to by s1. The initial byte of s2 overwrites the null byte at
the end of s1. A terminating null byte is always appended to the result. If
copying takes place between objects that overlap, the behavior is undefined.

C'est pas franchement explicite que le n'est pas compté dans les n char
copiés.

Or la taille du tableau de destination doit faire au moins strlen(s1) + min(n,
strlen(s2)) + 1

------------
Un autre exemple extrait des sources de la glibc 2.3.2 :

manual/examples/strncat.c:

#include <string.h>
#include <stdio.h>

#define SIZE 10

static char buffer[SIZE];

main ()
{
strncpy (buffer, "hello", SIZE);
puts (buffer);
strncat (buffer, ", world", SIZE - strlen (buffer) - 1);
puts (buffer);
}

on remarque que ce bout de code historique n'est pas très propre, et qu'il n'a
aucune chance de fonctionner correctement si on réduit SIZE en dessous de 6,
aussi bien à cause de strncpy() que de strncat(), alors qu'à l'évidence les
fonctions que le programmeurs aurait voulu utiliser sont une copie avec
troncature à sizeof(buffer)-1 et une concaténation avec également contrôle du
dépassement du tableau de destination.

-----------------

Prenons un exemple encore plus gros : dans les sources de perl 5.8.6: strncat
est utilisé 2 fois en 50 MO de source et comme par hasard, y a un bug :

vms/vms.c: lignes 2266 et suivantes:

if (vmspipe_file_status == 0) {
char file[NAM$C_MAXRSS+1];
pPLOC p = head_PLOC;

while (p) {
strcpy(file, p->dir);
strncat(file, "vmspipe.com",NAM$C_MAXRSS);
file[NAM$C_MAXRSS] = '';
p = p->next;

if (!do_tovmsspec(file,vmspipe_file,0)) continue;

if (cando_by_name(S_IRUSR, 0, vmspipe_file)
&& cando_by_name(S_IXUSR, 0, vmspipe_file)) {
vmspipe_file_status = 1;
return vmspipe_file;
}
}
vmspipe_file_status = -1; /* failed, use tempfiles */
}


Outre le fait que le $ semble être admis dans les identificateurs pour plaire
aux afficionados de VMS et que strcpy n'est pas contrôlé, le programmeur n'a pas
compris la sémantique de strncat(), dont l'usage ici est faux et sans intérêt.

---------------

Autres exemples dans les sources de gcc 4.0.0 qui vient de sortir :

ada/adaint.c:2129: strncat (buff, "*.dir", MAXPATH);
ada/adaint.c:2213: strncat (new_canonical_dirspec, "/", MAXPATH);
ada/adaint.c:2283: strncat (new_canonical_pathspec, next_dir,
MAXPATH);
ada/adaint.c:2287: strncat (new_canonical_pathspec, ":",
MAXPATH);
ada/adaint.c:2299: strncat (new_canonical_pathspec, ":", MAXPATH);
ada/adaint.c:2345: strncat (new_host_pathspec, __gnat_to_host_dir_spec
(buff, 0), MAXPATH);
ada/adaint.c:2348: strncat (new_host_pathspec, ",", MAXPATH);
ada/cstreams.c:198: strncat (buffer, "/", __gnat_max_path_len);
ada/cstreams.c:199: strncat (buffer, nambuffer, __gnat_max_path_len);

Le contexte n'est meme pas nécessaire pour voir que le programmeur n'a pas
compris le fonctionnement de strncat()
Bien entendu, il fait la meme erreur avec strncpy().

--------------------

J'ai pris ces projets au hasard, mais c'est symptomatique.
Essayez avec vos propres projets, ou ceux dont vous avez les sources sous la
main, c'est rare que strncpy ou strncat n'y soit pas utilisé de façon erronée.

Chqrlie.


Avatar
Charlie Gordon
"Emmanuel Delahaye" wrote in message
news:
Charlie Gordon wrote on 27/04/05 :
Je ne vois pas pourquoi on utiliserait strtok() quand strtok_r() est
disponble.


Et quand il n'est pas disponible, il suffit de l'implémenteer ou un de
ses frères...

http://mapage.noos.fr/emdel/clib.htm
Module TOK

Quant à strncpy() et strncat() : relisez la spec et vous verrez qu'elles ne
font


Je suis d'accord...

pas ce que la plupart des programmeurs pensent savoir ou comprendre. Leur


Là, par contre, le langage C n'est pas responsable de la mauvaise
formation de ses utilisateurs... La définition du langage n'est pas un
cours de C.

utilisation est très souvent incorrecte, source d'inefficacité, d'erreurs ou
de debordements de tableaux (si si!) et donc à déconseiller.


C'est comme feof(). Si les gens sont mal formés, ce n'est pas la faute
du langage. Il est possible d'utiliser ces fonctions correctement. Par
contre une fonction comme gets() est clairement un bug de conception et
ne peut pas être utilisée portablement de façon sûre.

Et je pense qui est de la responsabilité morale de ceux qui savent
(nous, toi, moi) de faire en sorte que les erreurs commises par les
utilisateurs soient corrigées, mais sans crier haro sur le baudet comme
tu as trop tendance à le faire. Il est dommage que tu ne mettes pas
plus tes compétences, qui sont indédiables, au services des
utilisateurs comme beaucoup le font ici, et que tu passes, par contre,
beaucoup de temps à éructer et à vitupérer contre le C... Si tu n'aimes
pas ce langage, laisse le tranquille et cesse d'affoler le newbie... Je
ne sais pas si tu as remarqué, mais la fréquentation est en baisse
régulière. On a pas besoin de ça...


Je ne vitupère pas contre le langage C, j'aime le C, mais je connais ses
défauts.
Je mets en garde contre un certain nombre de problèmes qui sont pour la plupart
dans la librairie standard et pour lesquels la solution est très simple : il
suffit de ne pas utiliser ces fonctions problématiques.

J'affirme que tout programmeur muni d'un cerveau en état de marche est
capable d'écrire du C solide, modulaire, testable et réutilisable. Le
langage n'est pas en cause (il est infiniment plus simple d'être bon en
C que bon en C++, par exemple). Comme souvent le problème est la
formation et les innombrables sites et livres qui continuent à raconter
n'importe quoi sur ce langage, au lieu de lire le K&R, la norme ou
C-Unleashed.


Tu as raison, mais il faut être pragmatique : quand un OP demande comment
utiliser scanf() pour faire un split() de chaines, je ne suis pas de ceux qui
proposent le format %[^:] , je préconise d'utiliser strchr() et d'éviter
scanf().
Evidemment les défenseurs béats de la norme s'emballent et proposent des
"solutions" à base de scanf() toutes plus en ou moins bancales. Je démontre
(laborieusement) les limitations et la vanité de ces efforts, et en chemin,
c'est sûr les newbies se sont perdus.

Mais à chaque fois, j'espère avoir convaincu quelques programmeurs de plus
d'éviter ou de se méfier de ces fonctions pourtant normatives :
scanf, strtok, strncpy, strncat...

Chqrlie.


Avatar
Harpo
Emmanuel Delahaye wrote:


Pour strtok, je savais, elle est quand même limite utilisable quand
on sait ce qu'on fait, pour strncpy et strncat, je ne vois pas ce que
vous leur reprochez.


- strncpy() ne met pas le 0 final quand il sature (chaine mal formée)


Ok, j'utilise suffisamment peu ces fonctions pour devoir regarder le
manuel à chaque fois.
C'est n'est pas vraiment un problème quand on connaît ce comportement.

- strncat() est bien, à condition d'être bien révéillé. (la chaine de
destination doit être initialisée...,


Lr premier byte à 0 n'est pas excessivement couteux.

ne pas se tromper dans les
tailles passées en paramètre, laisser une place pour le 0 etc.). Je
m'en sert tout le temps pour faire des extractions en une ligne, ça me
va.


Il faut se dire qu'il faut se débrouiller avec, ce sont des fonctions
que l'on doit connaître lorsqu'on les utilise souvent, j'utilise plus
facilement memcpy lorsque je le peux.
Tout ça pour dire que c'est quand même moins compliqué que scanf.


Avatar
Harpo
Charlie Gordon wrote:


Je ne vois pas pourquoi on utiliserait strtok() quand strtok_r() est
disponble.


Ok, mais très généralement on s'en fout quand il s'agit de mémoire
allouée dans le tas sur lequel il n'y a pas de problème de concurrence.
C'est typiquement un faux problème, il suffit de connaître le
comportement de la fonction. Faire un malloc_r() serait plus séieux.

Quant à strncpy() et strncat() : relisez la spec et vous
verrez qu'elles ne font
pas ce que la plupart des programmeurs pensent savoir ou comprendre.


Il y a la doc, s'ils ne la comprennent parfois un peu de travers comme
moi ce n'est pas un problème, comme ils font des tests exhaustifs ils
finissent par comprendre ce qu'ils font.

Avatar
Harpo
Emmanuel Delahaye wrote:


C'est comme feof(). Si les gens sont mal formés, ce n'est pas la faute
du langage. Il est possible d'utiliser ces fonctions correctement. Par
contre une fonction comme gets() est clairement un bug de conception
et ne peut pas être utilisée portablement de façon sûre.


Bug de conception, oui, mais c'est surtout le genre de truc qu'on écrit
quand on est pressé par le temps, en étant un excellent programmeur on
peut écrire des conneries. On n'est pas responsable des conditions
qu'on dans lesquelles on écrit. C n'est pas une question très
importantes, les bugs se corrigent, le problème vient du fait que 25
ans après ces fontions soient des standarts et qu'il y ait encore des
gens qui les utilisent.

(...)


J'affirme que tout programmeur muni d'un cerveau en état de marche est
capable d'écrire du C solide, modulaire, testable et réutilisable. Le
langage n'est pas en cause (il est infiniment plus simple d'être bon
en C que bon en C++, par exemple). Comme souvent le problème est la
formation et les innombrables sites et livres qui continuent à
raconter n'importe quoi sur ce langage, au lieu de lire le K&R, la
norme ou C-Unleashed.


Je ne connais pas tous ces bouquins, mais je crois que je suis d'accord.
On peut faire beaucoup de choses en C, parfois certes au prix de
beaucoup de lignes de code pour des choses fonctionnellement simples,
mais je ne pense pas que C++ puisse apporter plus sur ce point.

Ecrire du bon code n'est pas excessivement lié au langage mais surtout à
la volonté d'en écrire, le C permet cela et il est facile voire
agréable de s'astreindre à écrire du code lisible.
La solidité, la lisibilité, la maintenabilité, la réusabilité tiennent
sans doute en partie au langage mais surtout au design et le C permet
de faire des choses claires si on veut faire un peu d'effort.
Ceci dit, il y a des langages qui permettent de le faire plus facilement
et limitent C à une niche écologique en dehors de laquelle il ne serait
pas avisé de l'utiliser.

Avatar
Harpo
Charlie Gordon wrote:


The strncat() function shall append not more than n bytes (a null byte
and bytes that follow it are not appended) from the array pointed to
by s2 to the end of the string pointed to by s1. The initial byte of
s2 overwrites the null byte at the end of s1. A terminating null byte
is always appended to the result. If copying takes place between
objects that overlap, the behavior is undefined.

C'est pas franchement explicite que le n'est pas compté dans les n
char copiés.


Si.

Avatar
Emmanuel Delahaye
Harpo wrote on 27/04/05 :
Il faut se dire qu'il faut se débrouiller avec, ce sont des fonctions
que l'on doit connaître lorsqu'on les utilise souvent, j'utilise plus
facilement memcpy lorsque je le peux.


memcpy() ne met pas de 0 final. strncat() le fait. Le jour où j'ai
découvert ça (en parcourant c.l.c, i y a 4 ou 5 ans), ma vie a changé !

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

I once asked an expert COBOL programmer, how to
declare local variables in COBOL, the reply was:
"what is a local variable?"

Avatar
Emmanuel Delahaye
Charlie Gordon wrote on 27/04/05 :
Je ne vitupère pas contre le langage C,


Tu veux que je sorte ta collection de noms d'oiseaux ?

j'aime le C, mais je connais ses
défauts.
Je mets en garde contre un certain nombre de problèmes qui sont pour la
plupart dans la librairie standard et pour lesquels la solution est très
simple : il suffit de ne pas utiliser ces fonctions problématiques.


Un peu radical. Notamment pour strncat() qui, bien utilisée, et très
pratique.

<...> il faut être pragmatique : quand un OP demande comment
utiliser scanf() pour faire un split() de chaines, je ne suis pas de ceux qui
proposent le format %[^:] , je préconise d'utiliser strchr() et d'éviter
scanf().


Ok.

Evidemment les défenseurs béats de la norme s'emballent et proposent des
"solutions" à base de scanf() toutes plus en ou moins bancales. Je démontre
(laborieusement) les limitations et la vanité de ces efforts, et en chemin,
c'est sûr les newbies se sont perdus.


Non, tu t'emballes trop. Il y a un certain courant anti scanf() (j'en
suis) et il est normal qu'il y a ait une réaction, c'est sain. J'avoue
être parfois émerveillé devant les solutions proposées ! Ca m'amuse
plutôt. Et puis si ça marche, tant mieux!

Mais à chaque fois, j'espère avoir convaincu quelques programmeurs de plus
d'éviter ou de se méfier de ces fonctions pourtant normatives :
scanf, strtok, strncpy, strncat...


Un peu d'indulgence pour strncat() please... Il n'est pas interdit de
secouer son neurone avant de s'en servir...

--
Emmanuel
The C-FAQ: http://www.eskimo.com/~scs/C-faq/faq.html
The C-library: http://www.dinkumware.com/refxc.html

"There are 10 types of people in the world today;
those that understand binary, and those that dont."