Why does this function return the correct length of a string? (Incrementing a char pointer)
The value of s++
is the original value of s
, before increment, the increment occurs at an unspecified time before the next sequence point.
Hence *s++
and *(s++)
are equivalent: they both dereference the original value of s
. Another equivalent expression is *(0, s++)
and, not for the faint of heart, such is this one: 0[s++]
Note however that your function should use type size_t
for i
and its return type:
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
Here is a potentially more efficient version with a single increment per loop:
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
For those who wonder about the weird expressions in the second paragraph:
0, s++
is an instance of the comma operator,
that evaluates its left part, then its right part which constitutes its value. hence(0, s++)
is equivalent to(s++)
.0[s++]
is equivalent to(s++)[0]
and*(0 + s++)
or*(s++ + 0)
which simplify as*(s++)
. Transposing the pointer and the index expressions in[]
expressions is not very common nor particularly useful but conforms to the C standard.
Let's say I call this function with a simple String "a". Then s is incremented in the while loop therefore the value of s is 0 an i is also 0.
In that example, s
points to the 'a'
in "a"
. Then it is incremented and i
is also incremented. Now s
point to the null terminator, and i
is 1
. So in the next run through the loop, *(s++)
is '\0'
(which is 0
), so the loop ends, and the current value of i
(that's 1
) is returned.
Generally, the loop runs once for each character in the string, and then stops at the null terminator, so that's how it counts the characters.
It makes perfect sense:
int str_len(const char* s) {
int i = 0;
while(*(s++)) { //<-- increments the pointer to char till the end of the string
//till it finds '\0', that is, if s = "a" then s is 'a'
// followed by '\0' so it increments one time
i++; //counts the number of times the pointer moves forward
}
return i;
}
"But
s
is in brackets. That's why I thought it would be incremented first"
That is exactly why the pointer is incremented and not the character, let's say you have (*s)++
, in this case the character will be incremented and not the pointer. The dereferencing means that you are now working with the value refered by the pointer, not the pointer itself.
Since both operators have the same precendence but right-to-left associativity you can even use simply *s++
with no brackets to increment the pointer.