OVH Cloud OVH Cloud

copie de chaine

24 réponses
Avatar
Matt
Bonjour,

Je vais bientot passer un exam et je suis en train de réviser et je me
pose une question : comment copier une chaine dans une autre ?
par exemple

/* fonction recuperee sur l'excellente faq */
int get_line(char *buf, size_t size)
{
int ret;
if (fgets(buf, size, stdin) != NULL)
{
char *p = strchr(buf, '\n');
if (p != NULL)
{
*p = 0;
ret = 0;
}
else {
ret = 2;
}
}
else
{
ret = 1;
}
return ret;
}

/* fonction qui ne fait rien a part de la copie */
void maFonction(char *pChaine)
{
char pMaChaine[256];
/* comment faire pour le mieux ou une autre solution */
strcpy(pMaChaine, pChaine);
strncpy(pMaChaine, pChaine, strlen(pChaine));
memcpy(pMaChaine, pChaine, strlen(pChaine));
return;
}

int main(int argc, char** argv)
{
char pChaine[256];

printf("Entrez une chaine : ");
get_line(pMaChaine, 255);
maFonction(pMaChaine);

return 0;
}

merci pour vos réponses,

Matt...

10 réponses

1 2 3
Avatar
loufoque

memcpy(pMaChaine, pChaine, strlen(pChaine));


Deux parcours de la chaine quand un seul suffit.


Il me semble que dans la plupart des implémentations memcpy ne copie pas
octet par octet (ce qui se fait par un parcours de la chaîne) mais
utilise des optimisations bas niveau pour minimiser le nombre d'opérations.


Avatar
Harpo
loufoque wrote:


memcpy(pMaChaine, pChaine, strlen(pChaine));


Deux parcours de la chaine quand un seul suffit.


Il me semble que dans la plupart des implémentations memcpy ne copie
pas octet par octet (ce qui se fait par un parcours de la chaîne) mais
utilise des optimisations bas niveau pour minimiser le nombre
d'opérations.


Cela dépend de la machine, mais une implémentation courante est de
copier mot à mot, genre load store avec incrementation et un traitement
différent pour les octets résiduels avant et après.
strlen, je ne connais pas mais j'aimerais qu'on me dise somment on peut
l'optimiser...



Avatar
Marc Boyer
Le 12-12-2005, loufoque a écrit :

memcpy(pMaChaine, pChaine, strlen(pChaine));


Deux parcours de la chaine quand un seul suffit.


Il me semble que dans la plupart des implémentations memcpy ne copie pas
octet par octet (ce qui se fait par un parcours de la chaîne) mais
utilise des optimisations bas niveau pour minimiser le nombre d'opérations.


Quel genre ? Qu'il optimise pour ne pas faire des acces char par char,
je veux bien, mais ensuite ? Il faut bien déplacer un bout de mémoire ?
Et puis même si, parfois, il juste un peu plus qu'un parcours, pourquoi
ne pas faire simplement un parcours ?

Marc Boyer
--
Entre le fort et le faible, c'est la liberte qui opprime et le droit
qui libere. Henri Lacordaire, Dominicain



Avatar
Emmanuel Delahaye
C'est pas strdup ca ?


Si, mais strdup() n'est pas standard C. (Mais il fait partie de POSIX,
ce qui le rend très portable).

--
A+

Emmanuel Delahaye

Avatar
Emmanuel Delahaye
strncpy(pMaChaine, pChaine, strlen(pChaine));


DANGEREUX (au fou !)


Oui, ça devrait plaire à Charlie.

--
A+

Emmanuel Delahaye


Avatar
Matt
In news:439b4a13$0$6677$, Matt va escriure:

/* fonction qui ne fait rien a part de la copie */



Autrement dit, un compilateur un peu fin va supprimer entièrement la
fonction... Mauvais pari avec les compilateurs d'aujourd'hui.



void maFonction(char *pChaine)
{
char pMaChaine[256];



Non initialisé... autrement dit rempli de valeurs aléatoires.



strncpy(pMaChaine, pChaine, strlen(pChaine));



DANGEREUX (au fou !)

Révise bien ce que fait cette fonction (et strlen()), et essaye de
comprendre ce que fait en réalité cette ligne.
Si tu comprends cela (et pas seulement le +1), tu n'auras pas perdu ton
temps de révision.



Bonsoir,

Ok, il me semble que j'ai compris
strncpy copie n caractere de pChaine dans pMachaine.
si pMachaine vaut pas exemple (non initialisée -> valeurs aleatoires) :
123456789123456789
et si pChaine vaut ABCD alors ce que je fesais
pMaChaine contenait ABCD56789123456789
par contre si je fais strlen() + 1 alors je copie aussi le zéro terminal
de pChaine, donc pMaChaine devient ABCD''6789123456789

quand je dis fonction qui ne fait rien, c'etait pour l'exemple bien sur...

Il faut donc preferer strcpy a strncpy quand c'est juste une recopie de
chaine ?

Merci pour vos réponses,

Matt...


Avatar
Matt
Bonsoir,

Je vous remercie pour vos réponses.

Y a encore du boulot...

Matt...
Avatar
Pierre Maurette
[...]
Ok, il me semble que j'ai compris
Peut-être pas encore tout à fait ...


strncpy copie n caractere de pChaine dans pMachaine.
si pMachaine vaut pas exemple (non initialisée -> valeurs aleatoires) :
123456789123456789
1234567890123456789012 ....

plus facile pour compter ;-)

et si pChaine vaut ABCD alors ce que je fesais
pMaChaine contenait ABCD56789123456789
par contre si je fais strlen() + 1 alors je copie aussi le zéro terminal de
pChaine, donc pMaChaine devient ABCD''6789123456789
Ça va faire ça, mais ce n'est pas du tout fait pour. Le paramètre n (le

nombre de caractères maxi à copier) est plutôt à rapprocher de la
taille de la zone (ou chaîne) de destination, dans le but de ne pas
écrire au delà.

En fait, la copie de chaîne en C, c'est tout con, c'est ce qu'il y a
autour qui est un peu plus compliqué. Fondamentalement, c'est ça:
while((dest[i] = source[i]) != '')i++;
ou en version riche:
while((i < TAILLEDEST) && ((dest[i] = source[i]) != ''))i++;
A partir de là, on pourra bricoler, forcer par exemple à un '' final,
pour coller exactement à ses besoins et contraintes.
Mais on va le plus souvent utiliser les fonctions de la bibliothèque
standard, en lisant bien leur man ou la norme, c'est très court mais
chaque mot compte. Au vu des discussions que suscitent ces fonctions,
on pourrait presque se demander pourquoi les utiliser. A ce sujet,
pensez également à snprintf(), dont la valeur de retour est
intéressante.

Ça, c'est l'acte de recopie. Il nécessite un seul parcours de la chaîne
source. Mais presque tout se passe avant, y compris un éventuel
parcours "à vide" (un strlen() par exemple). Il faut se poser la
question "Que sais-je de la chaîne source ?". A partir de là et
d'autres critères, on choisira une stratégie pour la chaîne de
destination.

Le plus souvent (ce n'est pas absolu) vous maîtrisez dest et subissez
source. Si vous écrivez une fonction qui reçoit un const char*, vous
serez obligé de faire confiance à l'appelant. Vous pouvez toujours
vérifier que la paramètre n'est pas NULL, et que vous trouvez bien un
'' avant "une certaine longueur". Mais quand votre code part à la
recherche de ce '', vous ne savez et ne pouvez savoir (AMHA) où vous
mettez les pieds, en d'autres termes rien ne vous permet de savoir sur
combien de caractères après le pointeur la mémoire est valide. La
grosse erreur serait de penser que les fonction de la bibliothèque
*standard* ont quelque chose de magique qui leur permettrait de faire
mieux.

--
Pierre Maurette

Avatar
Antoine Leca
In news:439dcb14$0$19723$, Harpo va escriure:
loufoque wrote:

strlen, je ne connais pas mais j'aimerais qu'on me dise somment on
peut l'optimiser...


Une idée (non testée) est de charger un mot et de sortir de la boucle si
l'un quelconque des octets (bytes) est nul.

Pas bien sûr que cela gagne quoi que ce soit sur les processeurs type P4
actuels (parce que le mot et son entourage immédiat vont se trouver en
entier dans le cache L1 dès le début de l'opération), mais sur des
processeurs un peu moins pointu ou avec des architectures un peu zarbies
cela peut valoir le coup.


De toute manière, si tu recherches la perf', une des premières des choses
que l'on fait c'est de stocker la longueur des chaînes dans un coin, et
après d'utiliser les primitives qui manipulent des blocs (mem*()), donc
strlen() n'est probablement pas sur le chemin critique.


Antoine

Avatar
Antoine Leca
In news:439dc00e$0$4358$, loufoque va escriure:

memcpy(pMaChaine, pChaine, strlen(pChaine));


Deux parcours de la chaine quand un seul suffit.


Il me semble que dans la plupart des implémentations memcpy ne copie
pas octet par octet (ce qui se fait par un parcours de la chaîne) mais
utilise des optimisations bas niveau pour minimiser le nombre
d'opérations.


Ne change rien au principe : le résultat en temps est proportionnel à la
longueur de la chaîne (on écrit cela O(n)).


Maintenant, c'est sûr que j'ai déjà vu des implémentations de memcpy() (en
fait des trucs équivalents) qui déclenchait du DMA/blitting pour de « gros »
blocs, mais pour que ce genre de trucs soit vraiment efficace il faut un
compilateur au parfum (qui va déplacer le point de séquence le plus loin
possible, augmentant de fait le parallélisme).
Dans tous les cas, même si tu t'es « économisé » du temps d'exécution sur le
memcpy(), il faut avoir terminé le strlen() avant de lancer le memcpy() : la
remarque de Marc, c'est qu'à la place, il est plus efficace de copier
pendant la première passe, ce que fait strcpy().


Antoine



1 2 3