Wartość s++
jest pierwotną wartością s
przyrostu, przed przyrostem, występuje on w nieokreślonym czasie przed następnym punktem sekwencji.
Stąd *s++
i *(s++)
są równoważne: obaj odwołują się do pierwotnej wartości s
. Innym równoważnym wyrażeniem jest *(0, s++)
i, nie dla osób o słabym sercu, takie jest:0[s++]
Zauważ jednak, że twoja funkcja powinna używać type size_t
for i
i jej typu zwracanego:
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
Oto potencjalnie bardziej wydajna wersja z jednym przyrostem na pętlę:
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
Dla tych, którzy zastanawiają się nad dziwnymi wyrażeniami w drugim akapicie:
0, s++
jest przykładem operatora przecinka, ,
który ocenia jego lewą część, a następnie jej prawą część, która stanowi jej wartość. stąd (0, s++)
jest równoważne z (s++)
.
0[s++]
jest równoważne (s++)[0]
i *(0 + s++)
lub *(s++ + 0)
które upraszczają jako *(s++)
. Przeniesienie wskaźnika i wyrażeń indeksowych w []
wyrażeniach nie jest zbyt powszechne ani szczególnie przydatne, ale jest zgodne ze standardem C.
, s++
i złe rzeczy się zdarzą:)
W tym przykładzie
s
wskazuje na'a'
in"a"
. Następnie jest zwiększany, ai
także zwiększany. Terazs
wskaż na terminator zerowy ii
jest1
. Tak więc w następnym przebiegu przez pętlę*(s++)
jest'\0'
(która jest0
), więc pętla kończy się i zwracana jest bieżąca wartośći
(to1
).Zasadniczo pętla jest uruchamiana raz dla każdego znaku w ciągu, a następnie zatrzymuje się na zakończeniu zerowym, więc w ten sposób liczy znaki.
źródło
s
utrzymywało przed inkrementacją. To, co opisujesz, to zachowanie++s
(które w rzeczywistości byłoby niedoszacowane o jeden i wywołanie UB, jeśli przejdzie pusty ciąg).Ma to sens:
Właśnie dlatego wskaźnik jest zwiększany, a nie znak, powiedzmy, że masz
(*s)++
, w tym przypadku znak będzie zwiększany, a nie wskaźnik. Dereferencje oznaczają, że pracujesz teraz z wartością wskazywaną przez wskaźnik, a nie sam wskaźnik.Ponieważ obaj operatorzy mają tę samą przewagę, ale skojarzenie od prawej do lewej, możesz nawet użyć po prostu
*s++
bez nawiasów, aby zwiększyć wskaźnik.źródło
Operator postkrementacji zwiększa wartość operandu o 1, ale wartość wyrażenia jest pierwotną wartością operandu przed operacją inkrementacji.
Załóżmy, że przekazany argument
str_len()
to"a"
. Wstr_len()
, wskaźniks
jest skierowany do pierwszego znaku łańcucha"a"
. Wwhile
pętli:chociaż wartość
s
będzie zwiększana, ale wartośćs
w wyrażeniu będzie wskaźnikiem do znaku, na który wskazuje przed przyrostem, czyli wskaźnika do pierwszego znaku'a'
. Pos
odsunięciu wskaźnika nada charakter'a'
. W następnej iteracjis
wskaźnik będzie wskazywał na następny znak, który jest znakiem pustym\0
. Gdys
zostanie odwołany, poda się,0
a pętla zostanie zakończona. Zauważ,s
że teraz będzie wskazywał jeden element poza pustym znakiem łańcucha"a"
.źródło