La valeur de s++
est la valeur d'origine de s
, avant incrément, l'incrément se produit à un moment non spécifié avant le point de séquence suivant.
D'où *s++
et *(s++)
sont équivalents: ils déréférencent tous les deux la valeur d'origine de s
. Une autre expression équivalente est *(0, s++)
et, pas pour les faibles de cœur, telle est celle-ci:0[s++]
Notez cependant que votre fonction doit utiliser type size_t
for i
et son type de retour:
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
Voici une version potentiellement plus efficace avec un seul incrément par boucle:
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
Pour ceux qui s'interrogent sur les expressions étranges du deuxième paragraphe:
0, s++
est une instance de l'opérateur virgule ,
qui évalue sa partie gauche, puis sa partie droite qui constitue sa valeur. (0, s++)
est donc équivalent à (s++)
.
0[s++]
est équivalent à (s++)[0]
et *(0 + s++)
ou *(s++ + 0)
qui se simplifie comme *(s++)
. La transposition du pointeur et des expressions d'index dans les []
expressions n'est pas très courante ni particulièrement utile mais est conforme à la norme C.
, s++
choses et les mauvaises choses arriveront:)
Dans cet exemple, les
s
points à l''a'
en"a"
. Ensuite, il est incrémenté eti
est également incrémenté. Pointez maintenants
sur le terminateur nul, eti
c'est1
. Ainsi, lors de la prochaine exécution de la boucle,*(s++)
est'\0'
(qui est0
), donc la boucle se termine et la valeur actuelle dei
(c'est1
) est retournée.Généralement, la boucle s'exécute une fois pour chaque caractère de la chaîne, puis s'arrête au terminateur nul, c'est ainsi que cela compte les caractères.
la source
s
eu lieu avant incrémenter. Ce que vous décrivez est le comportement de++s
(qui sous-compterait en effet un et invoquerait UB si une chaîne vide lui était transmise).Cela est parfaitement logique:
C'est exactement pourquoi le pointeur est incrémenté et non le caractère, disons que vous l'avez
(*s)++
, dans ce cas, le caractère sera incrémenté et non le pointeur. Le déréférencement signifie que vous travaillez maintenant avec la valeur référencée par le pointeur, pas le pointeur lui-même.Étant donné que les deux opérateurs ont la même priorité mais l'associativité de droite à gauche, vous pouvez même utiliser simplement
*s++
sans parenthèses pour incrémenter le pointeur.la source
L'opérateur de post-incrémentation augmente la valeur de l'opérande de 1 mais la valeur de l'expression est la valeur d'origine de l'opérande avant l'opération d'incrémentation.
Supposons que l'argument transmis à
str_len()
est"a"
. Dans lestr_len()
, le pointeurs
pointe vers le premier caractère de la chaîne"a"
. Dans lawhile
boucle:bien que le
s
sera incrémenté mais la valeur des
dans l' expression sera le pointeur sur le caractère vers lequel il pointe avant l'incrémentation, qui est le pointeur sur le premier caractère'a'
. Lorsque le pointeurs
est déréférencé, il donnera du caractère'a'
. Dans la prochaine itération, les
pointeur pointera vers le caractère suivant qui est le caractère nul\0
. Quands
est déréférencé, il donnera0
et la boucle sortira. Notez que,s
pointe désormais sur un élément après le caractère nul de la chaîne"a"
.la source