[C++] Pointeur char*, priorité d'opérateur
Fermé
the_spectre
Messages postés
1
Date d'inscription
dimanche 25 février 2001
Statut
Membre
Dernière intervention
15 septembre 2006
-
15 sept. 2006 à 17:36
mamiemando Messages postés 33401 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 28 novembre 2024 - 24 juin 2007 à 21:34
mamiemando Messages postés 33401 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 28 novembre 2024 - 24 juin 2007 à 21:34
A voir également:
- [C++] Pointeur char*, priorité d'opérateur
- Coco char - Accueil - Réseaux sociaux
- 0650 quel opérateur - Forum Opérateurs & Réseaux mobiles
- 0473 quel opérateur - Forum Loisirs / Divertissements
- Pointeur souris disparu windows 10 - Guide
- 0758 quel opérateur - Forum Opérateurs & Réseaux mobiles
6 réponses
mamiemando
Messages postés
33401
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
28 novembre 2024
7 804
16 sept. 2006 à 02:28
16 sept. 2006 à 02:28
Tu peux interrompre une boucle avec l'instruction break :
Bonne chance
bool bStop = false; while(!bStop){ if(*pSrc) break; bStop = (*pDst++ = *pSrc++) == _T('\0'); } *pDst++ = _T('\0');
Bonne chance
Je me suis retrouvé ici par hasard :) Le sujet est passé depuis pas mal de temps mais je tenais à "hurler" face à la solution donnée.
Je ne pense pas que cette solution soit celle recherchée. Là c'est créer une ligne de plus pour le plaisir d'en créer une de plus. De plus, en algorithmie, les ruptures de boucles dans le bloc n'existent pas (ça correspond à du goto et c'est très mauvais de programmer ainsi).
La ligne qu'il fallait éclater est : bStop = (*pDst++ = *pSrc++) == _T('\0');
(il a bien dit à l'intérieur du while ;-) )
J'ai un peu de mal avec les post et pré incrémentations (je les évite un maximum à l'intérieur d'une expression qui est tout sauf simple -pas de problème dans une instruction d'affichage ou d'affectation toute simple et non combinée-) donc je vais juste donner une ébauche de solution :
*pDst++ = *pSrc++
if(*pDst == _T('\0')) bStop = true; else bStop = false;
L'opérateur ++ (ici en post-incrémentation) a une priorité plus forte que le *. Donc, en utilisant les parenthèses on détermine que :
*pSrc++ c'est le même que *(pSrc++).
*pDst++ c'est le même que *(pDst++).
Pourtant, si on se réfère à la définition de la post incrémentation on trouve que l'incrémentation est effectuée après le calcul de l'expression. Par exemple :
int a=5;
printf("%d", a++); // imprime 5 (post incrémentation. "a" vaudra 6 après l'instruction d'affichage).
printf("%d", ++a); // imprime 6 (pré-incrémentation)
Ce qui voudrait dire qu'avant l'affectation, le pointeur est porté sur pSrc et non pas sur pSrc+1. Je me trompe ? (sinon on aurait écrit *++pSrc, qui revient à écrire *(++pSrc) ou *(pSrc+1), ce qui n'est pas notre cas à cause de la post incrémentation.)
Donc ça reviendrait à faire :
*pDst = *pSrc;
pDst++ ;
pSrc++ ;
(Si je comprends l'intention du code, c'est de copier des valeurs sources vers des espaces mémoire destination, parallèlement... Une copie pure et simple de valeurs de pointeurs. Si ce n'est pas ça c'est que je me suis planté).
Je ne pense pas que cette solution soit celle recherchée. Là c'est créer une ligne de plus pour le plaisir d'en créer une de plus. De plus, en algorithmie, les ruptures de boucles dans le bloc n'existent pas (ça correspond à du goto et c'est très mauvais de programmer ainsi).
La ligne qu'il fallait éclater est : bStop = (*pDst++ = *pSrc++) == _T('\0');
(il a bien dit à l'intérieur du while ;-) )
J'ai un peu de mal avec les post et pré incrémentations (je les évite un maximum à l'intérieur d'une expression qui est tout sauf simple -pas de problème dans une instruction d'affichage ou d'affectation toute simple et non combinée-) donc je vais juste donner une ébauche de solution :
*pDst++ = *pSrc++
if(*pDst == _T('\0')) bStop = true; else bStop = false;
L'opérateur ++ (ici en post-incrémentation) a une priorité plus forte que le *. Donc, en utilisant les parenthèses on détermine que :
*pSrc++ c'est le même que *(pSrc++).
*pDst++ c'est le même que *(pDst++).
Pourtant, si on se réfère à la définition de la post incrémentation on trouve que l'incrémentation est effectuée après le calcul de l'expression. Par exemple :
int a=5;
printf("%d", a++); // imprime 5 (post incrémentation. "a" vaudra 6 après l'instruction d'affichage).
printf("%d", ++a); // imprime 6 (pré-incrémentation)
Ce qui voudrait dire qu'avant l'affectation, le pointeur est porté sur pSrc et non pas sur pSrc+1. Je me trompe ? (sinon on aurait écrit *++pSrc, qui revient à écrire *(++pSrc) ou *(pSrc+1), ce qui n'est pas notre cas à cause de la post incrémentation.)
Donc ça reviendrait à faire :
*pDst = *pSrc;
pDst++ ;
pSrc++ ;
(Si je comprends l'intention du code, c'est de copier des valeurs sources vers des espaces mémoire destination, parallèlement... Une copie pure et simple de valeurs de pointeurs. Si ce n'est pas ça c'est que je me suis planté).
Il me semblait bien, je me suis planté ! Toutes mes excuses.
L'erreur se situe au niveau de l'affirmation des priorités des opérateurs. Le tableau sur lequel je m'étais basé n'était pas complet et ne présentait pas les opérateurs unaires (pour ça que je ne voyais pas l'opérateur de pointeur que j'ai confondu avec celui de multiplication).
Ils ont donc la même priorité que les opérateurs d'incrémentation/décrémentation et, à même priorité, l'évaluation se fait de droite à gauche ; cela dit ça reste une post incrémentation et donc fidèle à sa réputation (parenthèses ou pas ça ne change rien dans ce cas précis, l'incrémentation est effectuée après).
Minute je teste ainsi on sera fixés...
... Ok, j'ai testé :
char *a = "ABCDEF";
printf("%c", *++a); // Affiche "B" (pré incrémentation)
printf("%c", *a++); // Affiche "A" (post incrémentation, le pointeur "a" n'a pas été incrémenté avant affichage).
(Bien entendu, comme l'exemple sur ma réponse précédente, les printf() ont été lancés un par un, sinon on obtient évidemment "B" dans les deux cas et la variable "a" contiendra l'adresse où est situé le caractère "C".)
Ma précédente solution tient donc toujours debout mais oubliez le passage sur la priorité des opérateurs.
Conclusion : A utiliser avec BEAUCOUP de précaution. Je fais du C depuis pas mal de temps et je n'ai toujours pas la maîtrise de ces pratiques farfelues. On n'est jamais certain de la définition de "expression" et vous pouvez vous en aperçevoir si vous essayez d'imprimer a, *a, *a++ et *++a dans un seul printf("%s%c%c%c"). Ca donne CDEF - C - B - B. Là si quelqu'un voulait bien m'expliquer je suis preneur ^^
Je tente : Si on estime qu'il imprime de droite à gauche : Il incrémente le pointeur "a" (il pointe vers la valeur "B" => pré incrémentation). Ok ensuite il fait *a++, ce qui imprime "B" mais incrémente le pointeur après affichage (post incrémentation) qui pointe maintenant vers la valeur "C" et... ok, ça tient la route. printf fonctionne de droite à gauche, je ne le savais pas.
L'erreur se situe au niveau de l'affirmation des priorités des opérateurs. Le tableau sur lequel je m'étais basé n'était pas complet et ne présentait pas les opérateurs unaires (pour ça que je ne voyais pas l'opérateur de pointeur que j'ai confondu avec celui de multiplication).
Ils ont donc la même priorité que les opérateurs d'incrémentation/décrémentation et, à même priorité, l'évaluation se fait de droite à gauche ; cela dit ça reste une post incrémentation et donc fidèle à sa réputation (parenthèses ou pas ça ne change rien dans ce cas précis, l'incrémentation est effectuée après).
Minute je teste ainsi on sera fixés...
... Ok, j'ai testé :
char *a = "ABCDEF";
printf("%c", *++a); // Affiche "B" (pré incrémentation)
printf("%c", *a++); // Affiche "A" (post incrémentation, le pointeur "a" n'a pas été incrémenté avant affichage).
(Bien entendu, comme l'exemple sur ma réponse précédente, les printf() ont été lancés un par un, sinon on obtient évidemment "B" dans les deux cas et la variable "a" contiendra l'adresse où est situé le caractère "C".)
Ma précédente solution tient donc toujours debout mais oubliez le passage sur la priorité des opérateurs.
Conclusion : A utiliser avec BEAUCOUP de précaution. Je fais du C depuis pas mal de temps et je n'ai toujours pas la maîtrise de ces pratiques farfelues. On n'est jamais certain de la définition de "expression" et vous pouvez vous en aperçevoir si vous essayez d'imprimer a, *a, *a++ et *++a dans un seul printf("%s%c%c%c"). Ca donne CDEF - C - B - B. Là si quelqu'un voulait bien m'expliquer je suis preneur ^^
Je tente : Si on estime qu'il imprime de droite à gauche : Il incrémente le pointeur "a" (il pointe vers la valeur "B" => pré incrémentation). Ok ensuite il fait *a++, ce qui imprime "B" mais incrémente le pointeur après affichage (post incrémentation) qui pointe maintenant vers la valeur "C" et... ok, ça tient la route. printf fonctionne de droite à gauche, je ne le savais pas.
mamiemando
Messages postés
33401
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
28 novembre 2024
7 804
22 juin 2007 à 21:13
22 juin 2007 à 21:13
En fait la question était mal posée je viens de capter que ce n'était pas le while qu'il voulait éclater mais ce qu'il y avait dans le bloc while (en tout c'est pour ça qu'à l'époque j'avais mis un break).
Pour revenir à ta remarque sur les ruptures de boucles je suis plus ou moins d'accord. Un break en début de boucle agit comme un test supplémentaire dans le while. Les "continue" entreraient également dans ce contexte mais sont équivalent à mettre ce qu'il suit dans un test "if". Bref on est loin du goto et parfois un continue et un break bien placé ne nuisent pas à la lisibilité ou à l'efficacité du code.
Dans son cas il a voulu manifestement faire une sorte de strcpy.
Voici une manière plus élégante de l'écrire
Ce qui donne bien :
La fonction my_strcpy peut aussi s'écrire ainsi
ou encore
Pour revenir aux histoires de pré et post incrémentation, la différence est simple. Une post incrémentation est évaluée après exécution de l'instruction, un pré incrémentation avant. Quand tu incrémentes une variable tu peux écrire indifferemment l'une ou l'autre.
Par contre l'exemple my_strcpy2 est un exemple clair ou il faut bien distinguer les deux :
1) on récupère la référence de *dst
2) on la passe à l'opérateur =
3) on récupère la référence de *src
4) on rentre dans le code de l'opérateur = : on affecte la valeur de *dst à *src
5) on post incrémente dst
6) on post incrémente src
Typiquement si tu préincrémentes tu vas louper le premier caractère de src et de dst.
Dans ce cas là tu vas avoir
dst = "\0apir\0" ce qui à l'affichage donnera une chaîne vide.
donne bien :
En espérant que tout ceci a éclairé ta lanterne ;)
Pour revenir à ta remarque sur les ruptures de boucles je suis plus ou moins d'accord. Un break en début de boucle agit comme un test supplémentaire dans le while. Les "continue" entreraient également dans ce contexte mais sont équivalent à mettre ce qu'il suit dans un test "if". Bref on est loin du goto et parfois un continue et un break bien placé ne nuisent pas à la lisibilité ou à l'efficacité du code.
Dans son cas il a voulu manifestement faire une sorte de strcpy.
Voici une manière plus élégante de l'écrire
#include <stdlib.h> #include <stdio.h> #include <string.h> void my_strcpy(char *dst,char *src){ while(*src != '\0'){ *dst = *src; ++src; ++dst; } } int main(){ char *src = "tapir"; char *dst = (char *)calloc((strlen(src)+1),sizeof(char)); my_strcpy(dst,src); printf("src = %s\n",src); printf("dst = %s\n",dst); free(dst); return 0; }
Ce qui donne bien :
(mando@polgara) (~) $ gcc -W -Wall plop.c (mando@polgara) (~) $ ./a.out src = tapir dst = tapir
La fonction my_strcpy peut aussi s'écrire ainsi
void my_strcpy2(char *dst,char *src){ while(*src != '\0') *dst++ = *src++; }
ou encore
void my_strcpy3(char *dst,char *src){ for(;*src != '\0';++src,++dst) *dst = *src; }
Pour revenir aux histoires de pré et post incrémentation, la différence est simple. Une post incrémentation est évaluée après exécution de l'instruction, un pré incrémentation avant. Quand tu incrémentes une variable tu peux écrire indifferemment l'une ou l'autre.
for(i=0;i<10;++i) printf("%d\n",i); for(i=0;i<10;i++) printf("%d\n",i);
Par contre l'exemple my_strcpy2 est un exemple clair ou il faut bien distinguer les deux :
1) on récupère la référence de *dst
2) on la passe à l'opérateur =
3) on récupère la référence de *src
4) on rentre dans le code de l'opérateur = : on affecte la valeur de *dst à *src
5) on post incrémente dst
6) on post incrémente src
Typiquement si tu préincrémentes tu vas louper le premier caractère de src et de dst.
void my_strcpy_bug(char *dst,char *src){ while(*src != '\0') *++dst = *++src; }
Dans ce cas là tu vas avoir
dst = "\0apir\0" ce qui à l'affichage donnera une chaîne vide.
#include <stdlib.h> #include <stdio.h> #include <string.h> void my_strcpy(char *dst,char *src){ while(*src != '\0') *++dst = *++src; } int main(){ unsigned int i; char *src = "tapir"; char *dst = (char *)calloc((strlen(src)+1),sizeof(char)); my_strcpy(dst,src); printf("src = %s\n",src); printf("dst = %s\n",dst); for(i=0;i<strlen(src);++i) printf("dst[%i]='%c'\n",i,dst[i]); free(dst); return 0; }
donne bien :
(mando@polgara) (~) $ ./a.out src = tapir dst = dst[0]='' dst[1]='a' dst[2]='p' dst[3]='i' dst[4]='r'
En espérant que tout ceci a éclairé ta lanterne ;)
Génial mamiemando ! ;-)
Ca fait plaisir de discuter avec un membre persistant de ce forum. :-)
Plus clairement expliqué que ça on ne pouvait pas faire. Ce sera utile à beaucoup de programmeurs qui passeront par là. Bravo !
Ca fait plaisir de discuter avec un membre persistant de ce forum. :-)
Plus clairement expliqué que ça on ne pouvait pas faire. Ce sera utile à beaucoup de programmeurs qui passeront par là. Bravo !
Posotaz
Messages postés
489
Date d'inscription
samedi 23 juin 2007
Statut
Membre
Dernière intervention
19 juin 2011
225
23 juin 2007 à 00:12
23 juin 2007 à 00:12
(Pour la peine je me suis inscrit ^^) Désolé pour ce post inutile mais je ne savais plus modifier le message plus haut.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
lami20j
Messages postés
21331
Date d'inscription
jeudi 4 novembre 2004
Statut
Modérateur, Contributeur sécurité
Dernière intervention
30 octobre 2019
3 569
23 juin 2007 à 03:02
23 juin 2007 à 03:02
Salut,
ou encore
ou encore
void strcpy4 (char *src, char *dst){ while ((*dst++ = *src++) != '\0') ; }ou encore
void strcpy5(char *src, char *dst){ while (*dst++ = *src++) ; }
mamiemando
Messages postés
33401
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
28 novembre 2024
7 804
24 juin 2007 à 21:34
24 juin 2007 à 21:34
Pas de soucis ;)