Answers:
的值s++
是的原始值s
,在递增之前,递增发生在下一个序列点之前的未指定时间。
因此*s++
和*(s++)
是等效的:它们都取消引用的原始值s
。另一个等效的表达是*(0, s++)
,而不是因为胆小的人,这是这样的:0[s++]
但是请注意,您的函数应将type size_t
用于i
及其返回类型:
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标准。
假设我用一个简单的字符串“ a”来调用此函数。然后s在while循环中递增,因此s的值为0,i也为0。
在该示例中,s
指向'a'
in "a"
。然后它递增,i
也递增。现在s
指向空终止符,并且i
是1
。因此,在通过循环的下运行,*(s++)
是'\0'
(这是0
),所以循环结束,和当前值i
(这是1
)返回。
通常,循环对字符串中的每个字符运行一次,然后在空终止符处停止,因此这是对字符进行计数的方式。
s
举行之前递增。您所描述的是其行为++s
(实际上会低一,如果传递空字符串,则调用UB)。
完全有道理:
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;
}
“但是
s
放在方括号中。这就是为什么我认为它将首先增加的原因”
这就是为什么指针增加而不是字符(假设您有字符)的原因(*s)++
,在这种情况下,字符将增加而不是指针。解引用意味着您现在正在使用指针引用的值,而不是指针本身。
由于两个运算符具有相同的优先级,但从右到左的关联性,您甚至可以简单地*s++
使用不带括号的指针来增加指针。
后递增运算符将操作数的值增加1,但是表达式的值是该操作数在增量运算之前的原始值。
假设传递给的参数str_len()
是"a"
。在中str_len()
,指针s
指向字符串的第一个字符"a"
。在while
循环中:
while(*(s++)) {
.....
.....
虽然s
将被递增1,但值s
的表达式将是指向它的指针被递增之前指向字符,它是指向第一个字符'a'
。当指针s
被取消引用时,它将给出character 'a'
。在下一次迭代中,s
指针将指向下一个字符,即null字符\0
。当s
被取消引用时,它将给出0
并且循环将退出。注意,s
现在将指向string的空字符之后的一个元素"a"
。
, s++
坏的事情将会发生:)