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);
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.
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.
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.
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...
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...
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...
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
Le 12-12-2005, loufoque <loufoque@remove.gmail.com> 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
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
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
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).
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...
In news:439b4a13$0$6677$8fcfb975@news.wanadoo.fr, 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.
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 ?
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 ?
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
[...]
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.
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
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
In news:439dcb14$0$19723$8fcfb975@news.wanadoo.fr, 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.
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
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
In news:439dc00e$0$4358$626a54ce@news.free.fr, 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().
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().