OVH Cloud OVH Cloud

memcpy et char

50 réponses
Avatar
Alain CROS
Bonjour.

J'ai écrit une fonction qui remplace la virgule par un point dans une chaine de caractères pour ensuite permettre de faire un
calcul.
Pour copier une chaine dans une autre chaine, j'utilise memcpy.
Est ce nécessaire d'écrire
memcpy(ch, c, sizeof(char) * taille);
ou bien je peux me contenter d'écrire
memcpy(ch, c, taille);

Toutes critiques sur la fonction seront les bienvenues.

Merci.

Alain CROS

#include <string.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).
*/
{
int i = 1, j = 0, k = 0;
char ch[taille + 1];
char *pch = ch;
memcpy(ch, c, sizeof(char) * taille);
ch[taille] = '\0';
while(*pch != '\0')
{
if((*pch < '0') || (*pch > '9'))
switch(*pch)
{
case '.':
j = (++k == 2) ? -1 : j;
break;
case ',':
*pch-- = '.';
j = i--;
break;
default:
j = -1;
}
if(j == -1)
break;
*pch++;
i++;
}
if(j != -1)
memcpy(c, ch, sizeof(char) * taille);
return(j);
}

10 réponses

1 2 3 4 5
Avatar
Stephane Legras-Decussy
Alain CROS a écrit dans le message :
4333e995$0$17469$
Est ce nécessaire d'écrire
memcpy(ch, c, sizeof(char) * taille);
ou bien je peux me contenter d'écrire
memcpy(ch, c, taille);


sizeof(char) vaut obligatoirement 1...

donc la 2eme propositions suffit...

Avatar
Alain CROS
Bonjour.

"Stephane Legras-Decussy" a écrit dans le message de news: 4333f1ef$0$5425$
| > Est ce nécessaire d'écrire
| > memcpy(ch, c, sizeof(char) * taille);
| > ou bien je peux me contenter d'écrire
| > memcpy(ch, c, taille);
|
| sizeof(char) vaut obligatoirement 1...
|
| donc la 2eme propositions suffit...

Si je comprends bien, que le char soit sur 7, 8, 9, ... bits, il correspond toujours a l'unité de base du système qui sera utilisé
par memcpy et sizeof(char) sera toujours égale à 1.

Merci.

Alain CROS

J'ai corrigé un petit bug dans ma fonction et supprimé une variable.

#include <string.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).
*/
{
int i = 1, j = 0;
char ch[taille + 1];
char *pch = ch;
memcpy(ch, c, taille);
ch[taille] = '';
while(*pch != '')
{
if((*pch < '0') || (*pch > '9'))
switch(*pch)
{
case ',':
*pch = '.';
case '.':
j = (j == 0) ? i : -1;
break;
default:
j = -1;
}
if(j == -1)
break;
*pch++;
i++;
}
if(j != -1)
memcpy(c, ch, taille);
return(j);
}
Avatar
Harpo
Alain CROS wrote:

Bonjour.

J'ai écrit une fonction qui remplace la virgule par un point dans une
chaine de caractères pour ensuite permettre de faire un calcul.
Pour copier une chaine dans une autre chaine, j'utilise memcpy.
Est ce nécessaire d'écrire
memcpy(ch, c, sizeof(char) * taille);
ou bien je peux me contenter d'écrire
memcpy(ch, c, taille);


Je l'espère...


Toutes critiques sur la fonction seront les bienvenues.



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

En fait, il semble que ce soit -1 s'il existe dans la chaîne quelque
chose qui n'est ni un chiffre ni un point.
Je n'ai pas regardé vraiment en détail, cependant le truc avec i, j, k
me semble touffu.

Il y a un moyen d'éviter de recopier la chaîne dans ch (surtout si elle
ne doit comporter qu'une virgule), cela éviterait 2 memcpy( ) et ch
deviendrait par là inutile.
Bref, la fonction pourrait s'écrire plus simplement et plus lisiblement.

Avatar
Marc Boyer
Le 23-09-2005, Alain CROS a écrit :
J'ai corrigé un petit bug dans ma fonction et supprimé une variable.

#include <string.h>


Allez, je suis pas le meilleur à ce jeu là, mais je tente.

int convstrnum(int taille, char *c)


bool convstrnum(size_t 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).
*/
{
int i = 1, j = 0;


C'est quoi 'i' et 'j' ?

char ch[taille + 1];


Souvent une mauvaise idée: si on a pas la mémoire
pour allouer taille+1, ben, ça va faire boum, et on
a pas moyen de le savoir.

char *pch = ch;
memcpy(ch, c, taille);
ch[taille] = '';
while(*pch != '')
{
if((*pch < '0') || (*pch > '9'))
switch(*pch)
{
case ',':
*pch = '.';
case '.':
j = (j == 0) ? i : -1;


Heuh ? En décripté, ça donne quoi ?

break;
default:
j = -1;
}
if(j == -1)
break;
*pch++;
i++;
}
if(j != -1)
memcpy(c, ch, taille);
return(j);
}



--
À vélo, prendre une rue à contre-sens est moins dangeureux
que prendre un boulevard dans le sens légal. À qui la faute ?

Avatar
Targeur fou
Alain CROS wrote:
Bonjour.


Bonjour,


J'ai écrit une fonction qui remplace la virgule par un point dans une c haine de caractères pour ensuite permettre de faire un
calcul.
Pour copier une chaine dans une autre chaine, j'utilise memcpy.
Est ce nécessaire d'écrire
memcpy(ch, c, sizeof(char) * taille);
ou bien je peux me contenter d'écrire
memcpy(ch, c, taille);


sizeof(char) == 1 par définition, donc seconde forme pour moi. Ceci
dit, si tu dois un jour copier avec memcpy() des données d'un autre
type, utiliser sizeof(type)*taille est une bonne pratique, notamment
avec les tableaux. Pour ne pas se tromper, utiliser l'opérateur sizeof
sur la donnée elle-même (de type bien défini) plutôt que de passer
un type n'est pas mal non plus. Je privilégie le premier cas si je
travaille avec des tableaux, le second si je travaille avec des
pointeurs, pas bien dur de voir le pourquoi. Si je travaille avec le
type char, pointeur ou tableau, je ne précise que la taille.

exple :
#define SIZE_ARR 50
double arr1[SIZE_ARR];
double arr2[SIZE_ARR];
double * pData1;
double * pData2;
/* ... */
/* with arrays */
memcpy(arr2, arr1, sizeof(double)*SIZE_ARR);
/* with pointers */
memcpy(pData2, pData1, sizeof(*pData1)*SIZE_ARR);


Toutes critiques sur la fonction seront les bienvenues.

Merci.

Alain CROS

#include <string.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).
*/
{
int i = 1, j = 0, k = 0;
char ch[taille + 1];


Attention, C99 ;-).

char *pch = ch;
memcpy(ch, c, sizeof(char) * taille);


/* Copie chaine source */
memcpy(ch, c, taille);

ch[taille] = '';
while(*pch != '')
{
if((*pch < '0') || (*pch > '9'))


/* Inclure ctype.h et profiter des fonctions de
classification */
if (!isdigit(*pch)) {

switch(*pch)
{
case '.':
j = (++k == 2) ? -1 : j;
break;
case ',':
*pch-- = '.';
j = i--;
break;
default:
j = -1;
}
if(j == -1)
break;


}

*pch++;
i++;
}
if(j != -1)
{

memcpy(c, ch, sizeof(char) * taille);
}


return(j);


return j; /* tout court*/

}


Note : plus d'accolades avec les if ne ferait pas de mal. Je pense
aussi que tu as un pointeur en trop (pch) : tupeux très bien
sauvegarder la chaine à traiter, travailler directement dessus, puis
la restaurer en cas de besoin.

Ma version serait quelquechose du genre :

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

int isCharValid(char c)
{
return ( (isdigit(c) || c == '.' || c == ',') ? 1 : 0 );
}

/**
* comma2dot
* Remplace la virgule par le point comme séparateur dans une chaine
numérique
* @param[in] s chaine à traiter
* @return rc
* 0 : succes
* -1 : argument nul
* -2 : pb allocation
* -3 : chaine fournie non valide
*/
int comma2dot(char * s)
{
int rc = 0;

if (s != NULL) {

size_t lg = strlen(s);
char * tmp = malloc(lg+1);

if (tmp != NULL) {

int cptDot = 0;
memcpy(tmp, s, lg+1);

/* boucle de traitement */
/* on remplace toutes les virgules rencontrées par des
points */
/* on se préoccuppera plus tard de la validité de la
chaine */
/* avec le nb de points insérés */
while(*s != '') {
if (isCharValid(*s)) {
if (*s == '.') { ++cptDot; }
if (*s == ',') { *s = '.'; ++cptDot; }
}
else {
rc = -3;
break;
}
++s;
}

/* plus de 1 separateur rencontres, ca va pas */
rc = (cptDot > 1) ? -3 : rc;

/* restauration de la chaine initiale si pas bon */
if (rc == -3) {
memcpy(s, tmp, lg+1);
}

free(tmp);

}
else { rc = -2; }
}
else { rc = -1; }

return rc;

}

A+
Regis

Avatar
Alain CROS
Bonjour.

Merci pour les nombreuses réponses.
J'analyse tous ça pour essayer d'en tirer de bonnes pratiques.

Alain CROS
Avatar
Harpo
Targeur fou wrote:


exple :
#define SIZE_ARR 50
double arr1[SIZE_ARR];
double arr2[SIZE_ARR];
double * pData1;
double * pData2;
/* ... */
/* with arrays */
memcpy(arr2, arr1, sizeof(double)*SIZE_ARR);


Je préfèrerais écrire
memcpy( arr2, arr1, sizeof( * arr1 ) * SIZE_ARR ) ;

car si on change le type de '* arr1' en disons triple, il n'est pas
nécessaire de changer cette instruction.

Avatar
Emmanuel Delahaye
Alain CROS wrote on 23/09/05 :
J'ai écrit une fonction qui remplace la virgule par un point dans une chaine
de caractères pour ensuite permettre de faire un calcul.
Pour copier une chaine dans une autre chaine, j'utilise memcpy.
Est ce nécessaire d'écrire
memcpy(ch, c, sizeof(char) * taille);


Redondance inutile. Par contre

memcpy(ch, c, sizeof *ch * taille);

si le type est appelé à changer (char -> wchar_t, par exemple) et que
la taille est un nombre d'éléments...

ou bien je peux me contenter d'écrire
memcpy(ch, c, taille);


Oui, ou mieux

memcpy(ch, c, sizeof ch);

si ch est un tableau. Evidemment, si c'est un pointeur, il vaut mieux
oublier (pas dangereux, mais sérieusement limité...)

#include <string.h>

int convstrnum(int taille, char *c)


La chaine initiale est donc modifiable. Je recommande size_t pour la
taille. Si 'c' est l'adresse d'une chaine conforme, à quoi sert la
taille ?

/* 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).
*/
{
int i = 1, j = 0, k = 0;


Je recommande size_t pour i.

char ch[taille + 1];


[C99] VLA ? Je ne connais pas d'implémentation conforme. Qu'est-ce qui
ne va pas avec malloc() ?

char *pch = ch;
memcpy(ch, c, sizeof(char) * taille);
ch[taille] = '';


Sécurité ?

while(*pch != '')
{
if((*pch < '0') || (*pch > '9'))
switch(*pch)
{
case '.':
j = (++k == 2) ? -1 : j;
break;
case ',':
*pch-- = '.';
j = i--;
break;
default:
j = -1;
}
if(j == -1)
break;
*pch++;
i++;
}
if(j != -1)
memcpy(c, ch, sizeof(char) * taille);
return(j);
}


Ca me parait hyper compliqué! Si la chaine initiale est modifiable, il
suffit de la modifier directement.

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

/* 0 | 1 */
#define ED 0

#if !ED
static 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).
*/
{
int i = 1, j = 0, k = 0;
char ch[taille + 1];
char *pch = ch;
memcpy (ch, c, sizeof (char) * taille);
ch[taille] = '';
while (*pch != '')
{
if ((*pch < '0') || (*pch > '9'))
switch (*pch)
{
case '.':
j = (++k == 2) ? -1 : j;
break;
case ',':
*pch-- = '.';
j = i--;
break;
default:
j = -1;
}
if (j == -1)
break;
*pch++;
i++;
}
if (j != -1)
memcpy (c, ch, sizeof (char) * taille);
return (j);
}
#else
/* Remplace, dans une chaine de caractères représentant un nombre,
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 nombre (la chaine reste inchangée).
*/
static int convstrnum (char *c)
{
int n = -1;
char *p = c;

while (*p != 0)
{
if (n == -1)
{
if (isdigit (*p) || *p == '-')
{
n = 0;
}
else
{
break;
}
}
else
{
if (*p == ',')
{
*p = '.';
n = (int) (p - c) + 1;
}
}

p++;
}
return n;
}
#endif

int main (void)
{
char as[][32] {
"",
"abc",
"123",
"-123",
"123,456",
"-123,456",
};
size_t i;

for (i = 0; i < sizeof as / sizeof *as; i++)
{
char *s = as[i];
printf ("'%s' -> ", s);
{
#if !ED
int n = convstrnum ((int) strlen (s), s);
#else
int n = convstrnum (s);
#endif
printf ("'%s' (%d)n", s, n);
}
}
return 0;
}

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

.sig under repair

Avatar
Emmanuel Delahaye
Alain CROS wrote on 23/09/05 :
J'ai corrigé un petit bug dans ma fonction et supprimé une variable.


Ne traite toujours pas les nombres négatifs...

--
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
Targeur fou wrote on 23/09/05 :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int isCharValid(char c)
{
return ( (isdigit(c) || c == '.' || c == ',') ? 1 : 0 );


COmpliqué...

return (isdigit(c) || c == '.' || c == ',');
}

/**
* comma2dot
* Remplace la virgule par le point comme séparateur dans une chaine
numérique
* @param[in] s chaine à traiter
* @return rc
* 0 : succes
* -1 : argument nul
* -2 : pb allocation
* -3 : chaine fournie non valide
*/
int comma2dot(char * s)
{
int rc = 0;

if (s != NULL) {

size_t lg = strlen(s);
char * tmp = malloc(lg+1);


Ca fout la trouille!


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

.sig under repair

1 2 3 4 5