为什么这个函数 return 是字符串的正确长度? (增加一个字符指针)
Why does this function return the correct length of a string? (Incrementing a char pointer)
这是一个计算字符串中字符数的函数:
int str_len(const char* s) {
int i = 0;
while(*(s++)) {
i++;
}
return i;
}
为什么这个 return 长度正确?
假设我用一个简单的字符串 "a"
调用这个函数。然后s
在while循环中递增,所以s
和i
的值都是0。
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.
在那个例子中,s
指向 "a"
中的 'a'
。然后递增,i
也递增。现在 s
指向空终止符,而 i
是 1
。所以在接下来的运行循环中,*(s++)
是'[=18=]'
(也就是0
),所以循环结束,i
的当前值(返回 1
)。
通常,循环 运行 对字符串中的每个字符执行一次,然后在空终止符处停止,这就是它计算字符的方式。
很有道理:
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 '[=10=]', that is, if s = "a" then s is 'a'
// followed by '[=10=]' 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"
这正是指针而不是字符递增的原因,假设您有 (*s)++
,在这种情况下,字符将递增而不是指针。取消引用意味着您现在正在使用指针引用的值,而不是指针本身。
由于两个运算符具有相同的优先级但从右到左的关联性,您甚至可以使用不带括号的简单 *s++
来递增指针。
s++
的值为s
的原始值,在递增之前,递增发生在下一个序列点之前的未指定时间。
因此 *s++
和 *(s++)
是等价的:它们都取消引用 s
的原始值。另一个等价的表达式是 *(0, s++)
并且,胆小者不宜,例如:0[s++]
但是请注意,您的函数应该使用类型 size_t
作为 i
及其 return 类型:
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
这是一个可能更高效的版本,每个循环只有一个增量:
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
对于那些对第二段中奇怪的表达感到疑惑的人:
0, s++
是逗号运算符 ,
的一个实例,它计算它的左边部分,然后是构成它的值的右边部分。因此 (0, s++)
等同于 (s++)
.
0[s++]
等价于(s++)[0]
和*(0 + s++)
或*(s++ + 0)
,简化为*(s++)
。在 []
表达式中转置指针和索引表达式不是很常见也不是特别有用,但符合 C 标准。
post 递增运算符将操作数的值增加 1 但表达式的值是递增操作之前操作数的原始值。
假设传递给 str_len()
的参数是 "a"
。在 str_len()
中,指针 s
指向字符串 "a"
的第一个字符。在 while
循环中:
while(*(s++)) {
.....
.....
虽然 s
会递增,但是 表达式 中 s
的值将指向它在递增之前指向的字符,这是指向第一个字符 'a'
的指针。当指针 s
被取消引用时,它将给出字符 'a'
。在下一次迭代中,s
指针将指向下一个字符,即空字符 [=23=]
。当 s
被取消引用时,它将给出 0
并且循环将退出。请注意,s
现在将指向字符串 "a"
.
空字符后的一个元素
这是一个计算字符串中字符数的函数:
int str_len(const char* s) {
int i = 0;
while(*(s++)) {
i++;
}
return i;
}
为什么这个 return 长度正确?
假设我用一个简单的字符串 "a"
调用这个函数。然后s
在while循环中递增,所以s
和i
的值都是0。
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.
在那个例子中,s
指向 "a"
中的 'a'
。然后递增,i
也递增。现在 s
指向空终止符,而 i
是 1
。所以在接下来的运行循环中,*(s++)
是'[=18=]'
(也就是0
),所以循环结束,i
的当前值(返回 1
)。
通常,循环 运行 对字符串中的每个字符执行一次,然后在空终止符处停止,这就是它计算字符的方式。
很有道理:
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 '[=10=]', that is, if s = "a" then s is 'a'
// followed by '[=10=]' 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"
这正是指针而不是字符递增的原因,假设您有 (*s)++
,在这种情况下,字符将递增而不是指针。取消引用意味着您现在正在使用指针引用的值,而不是指针本身。
由于两个运算符具有相同的优先级但从右到左的关联性,您甚至可以使用不带括号的简单 *s++
来递增指针。
s++
的值为s
的原始值,在递增之前,递增发生在下一个序列点之前的未指定时间。
因此 *s++
和 *(s++)
是等价的:它们都取消引用 s
的原始值。另一个等价的表达式是 *(0, s++)
并且,胆小者不宜,例如:0[s++]
但是请注意,您的函数应该使用类型 size_t
作为 i
及其 return 类型:
size_t str_len(const char *s) {
size_t i = 0;
while (*s++) {
i++;
}
/* s points after the null terminator */
return i;
}
这是一个可能更高效的版本,每个循环只有一个增量:
size_t str_len(const char *s) {
const char *s0 = s;
while (*s++) {
/* nothing */
}
return s - 1 - s0;
}
对于那些对第二段中奇怪的表达感到疑惑的人:
0, s++
是逗号运算符,
的一个实例,它计算它的左边部分,然后是构成它的值的右边部分。因此(0, s++)
等同于(s++)
.0[s++]
等价于(s++)[0]
和*(0 + s++)
或*(s++ + 0)
,简化为*(s++)
。在[]
表达式中转置指针和索引表达式不是很常见也不是特别有用,但符合 C 标准。
post 递增运算符将操作数的值增加 1 但表达式的值是递增操作之前操作数的原始值。
假设传递给 str_len()
的参数是 "a"
。在 str_len()
中,指针 s
指向字符串 "a"
的第一个字符。在 while
循环中:
while(*(s++)) {
.....
.....
虽然 s
会递增,但是 表达式 中 s
的值将指向它在递增之前指向的字符,这是指向第一个字符 'a'
的指针。当指针 s
被取消引用时,它将给出字符 'a'
。在下一次迭代中,s
指针将指向下一个字符,即空字符 [=23=]
。当 s
被取消引用时,它将给出 0
并且循环将退出。请注意,s
现在将指向字符串 "a"
.