Article View: fr.comp.lang.c
Article #15390Re: memcpy et char
From: Charlie Gordon
Date: Sun, 25 Sep 2005 23:11
Date: Sun, 25 Sep 2005 23:11
175 lines
7559 bytes
7559 bytes
"Alain CROS" <Personne@ICI> wrote in message
news:4336f07f$0$18817$626a14ce@news.free.fr...
>
> En tous cas, merci � tous.
>
Voici mon analyse de la derniere version de ton code :
> #include <ctype.h>
>
> int convstrnum(int taille, char *c)
> /* Remplace, dans une chaine de caract�res repr�sentant un chiffre,
> la virgule par un point.
> Retourne :
> la position de ce point dans la chaine (base 1).
> 0 si pas de point.
> -1 si pas un chiffre (la chaine reste inchang�e).
> */
- Je mettrais le commentaire au dessus de la definition de la fonction, pas au
milieu.
- La chaine ne represente pas un chiffre, mais un nombre, essaie d'�tre pr�cis
dans les explications.
- c n'est pas un nom loisible pour un char *, utilise p, s, ou str.
- taille est un mot francais : essaie de ne pas melanger francais et anglais
dans le code, comme les mots-cl�s et les noms de fonction sont deja en anglais
(y compris convstrnum) tu devrais utiliser len pour ce parametre.
- convstrnum n'est pas non plus tr�s coh�rent comme nom : que penses-tu de
normalize_number_string ?
> {
> int i; /*position du char*/
> int j = 0; /*position du s�parateur d�cimal*/
> char *pch = c;
> for(i = 1; i <= taille; i++)
Cette boucle est � bannir dans un programme C. La facon standard de faire une
telle boucle est
for(i = 0; i < len; i++)
d�s que tu t'�cartes des constructions habituelles, le code devient difficile �
suivre, et les erreurs aux bornes rappliquent rapidement. En particulier dans
cette boucle, i n'est *pas* la position du caract�re point� par pch, donc le
commentaire est faux, ce qui indique souvent que le code l'est aussi.
> {
> if(!isdigit(*pch))
> switch(*pch)
> {
> case ',':
> case '.': /*si plusieurs virgules et ou points --> erreur*/
> j = (j == 0) ? i : -1;
l'utilisation de l'op�rateur ternaire rend ici le code obscur. il serait plus
facile a comprendre avec un if qui teste si on a deja vu un s�parateur d�cimal
et revoie le code d'erreur dans ce cas plutot que de stocker -1 dans j
> break;
> case '-': /*nombre n�gatif*/
> if(i == 1)
> break;
Il manque un commentaire /* FALL THRU */ ici et une explication pour le refus
des nombres comprenant un signe - ailleurs qu'au d�but.
tu peux traiter ce cas plus efficacement et plus lisiblement avant la boucle.
> default: /*mauvais caract�re --> erreur*/
> j = -1;
manque encore un break. celui-ci n'est pas strictement indispensable, mais il
est fortement recommand� de toujours terminer une clause de switch par un break
pour am�liorer la lisibilit� et �viter les erreurs lors de rajout de clauses
suppl�mentaires.
> }
> if(j == -1)
> break;
> *pch++;
pourquoi d�r�f�rencer pch ici ?
> }
> if(j > 0)
> *( c + j - 1 ) = '.' ; /*le s�parateur d�cimal devient un point*/
c[j - 1] = '.'; est plus lisible � mon sens.
> return j;
> }
Remarques g�n�rales :
Si cette fonction n'est pas appel�e pour des sous-parties de chaine, il serait
plus simple de lui passer seulement le pointeur et de boucler jusqu'au '\0' de
fin de chaine.
Retourner un nombre pr�tendument 'position de la virgule' bas� en 1 est une
h�r�sie � �viter *absolument* en C. Tot ou tard on fera la supposition que
str[pos] == '.' ou le code sera anormalement alourdi par des -1 partout.
Renvoie plutot le nombre de caract�res devant le point et -1 ou len si le nombre
n'a pas de point, et -2 en cas de caract�res interdits.
Tu pourrais aussi accepter des espaces optionnelles au d�but de la chaine, comme
le font les routines standard de conversion de nombres (strtol, atoi, strtod)
Tu devrais aussi accepter le signe +
Voici une proposition:
#include <ctype.h>
int normalize_number_string(char *s) {
char *p;
char *pdec;
/* on accepte les pointeurs NULL, mais c'est un cas d'erreur */
if (s == NULL)
return -2;
p = s;
/* on ignore les blancs en d�but de chaine */
while (isspace(*p))
p++;
/* le nombre peut commencer par un signe */
if (*p == '+' || *p == '-')
p++;
/* on reconnait la partie entiere */
while (isdigit(*p))
p++;
if (*p == '\0') {
/* a chaine est correcte, mais n'a pas de point decimal */
return -1;
}
if (*p != ',' && *p != '.') {
/* la chaine n'est pas un nombre */
return -2;
}
/* on garde la position du point decimal pour ne modifier la chaine que si
celle-ci est correcte */
pdec = p++;
/* on reconnait la partie d�cimale */
while (isdigit(*p))
p++;
if (*p == '\0') {
/* la chaine est correcte, on force le point decimal et retourne sa
position */
*pdec = '.';
return (pdec - s);
} else {
/* la chaine est incorrecte, on la laisse inchang�e */
return -2;
}
}
Si tu tiens absolument � passer len en parametre, le code sera nettement plus
lourd, et on sera tent� de ne faire qu'une seule boucle, ce qui le rendra moins
lisible.
Si tu veux conserver la s�mantique initiale, il suffit de modifier les return.
Tu remarqueras que cette implementation te permet d'affiner facilement le
comportement pour renvoyer des codes d'erreur plus explicites, detecter des
nombres potentiellement incorrects : une partie entiere ou une partie decimale
vide sont sans doute corrects, mais que dire de la chaine "." ?
Tu peux aussi facilement changer la s�mantique de cette fonction pour qu'elle
serve a analyser le d�but d'une chaine et positionne un pointeur sur le
caract�re qui suit le nombre reconnu, comme le fait strtol(). Ce
comportement-l� est beaucoup plus utile en pratique que le code d'erreur
retourn� dans l'API actuelle. On aurait alors une fonction :
int parse_number_string(char *s, char **tailp);
qui positionne tailp sur la suite de la chaine et renvoie un code indiquant le
type de nombre reconnu : pas un nombre, nombre entier, nombre avec un point
d�cimal...
--
Chqrlie.
Technical Details
Message-ID:
<dh799n$shp$1@reader1.imaginet.fr>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!195.92.193.196.MISMATCH!nntp.theplanet.net!inewsm1.nntp.theplanet.net!colt.net!fr.colt.net!writer!not-for-mailReferences:
<4333e995$0$17469$626a14ce@news.free.fr> <4335b780$0$5400$8fcfb975@news.wanadoo.fr> <4336f07f$0$18817$626a14ce@news.free.fr>Show Full Headers
Complete Article Headers
X-Google-Thread: f9822,366ad66ae342f8da X-Google-Attributes: gidf9822,public X-Google-Language: FRENCH,ASCII Path: arc1-ca.pugleaf.net!g2news1.google.com!news3.google.com!border1.nntp.dca.giganews.com!nntp.giganews.com!newsfeed00.sul.t-online.de!t-online.de!195.92.193.196.MISMATCH!nntp.theplanet.net!inewsm1.nntp.theplanet.net!colt.net!fr.colt.net!writer!not-for-mail From: "Charlie Gordon" <news@chqrlie.org> Newsgroups: fr.comp.lang.c Subject: Re: memcpy et char Date: Mon, 26 Sep 2005 01:11:10 +0200 Organization: ImagiNET / Colt Internet Lines: 177 Message-ID: <dh799n$shp$1@reader1.imaginet.fr> References: <4333e995$0$17469$626a14ce@news.free.fr> <4335b780$0$5400$8fcfb975@news.wanadoo.fr> <4336f07f$0$18817$626a14ce@news.free.fr> NNTP-Posting-Host: gw.netgem.com X-Trace: reader1.imaginet.fr 1127688311 29241 195.68.2.34 (25 Sep 2005 22:45:11 GMT) X-Complaints-To: abuse@imaginet.fr NNTP-Posting-Date: 25 Sep 2005 22:45:11 GMT X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2800.1506 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1506