为什么此函数返回正确的字符串长度?(增加一个char指针)


12

这是一个计算字符串中字符数的函数:

int str_len(const char* s) {
    int i = 0;
    while(*(s++)) {
        i++;
    }
    return i;
}

为什么返回正确的长度?

假设我使用简单的String调用此函数"a"。然后s递增在while循环,因此值si均为0。

Answers:


10

的值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标准。


当然希望逗号运算符很清楚。带走了, s++坏的事情将会发生:)
戴维·C·兰金

6

假设我用一个简单的字符串“ a”来调用此函数。然后s在while循环中递增,因此s的值为0,i也为0。

在该示例中,s指向'a'in "a"。然后它递增,i也递增。现在s指向空终止符,并且i1。因此,在通过循环的下运行,*(s++)'\0'(这是0),所以循环结束,和当前值i(这是1)返回。

通常,循环对字符串中的每个字符运行一次,然后在空终止符处停止,因此这是对字符进行计数的方式。


因为s在方括号中,所以我认为它会先递增(所以现在它指向'/ 0')。因此,while循环为假,并且我永远不会递增。
lor

2
@lor,还记得那些后置运营商:它的计算结果无论s举行之前递增。您所描述的是其行为++s(实际上会低一,如果传递空字符串,则调用UB)。
Toby Speight

2

完全有道理:

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++使用不带括号的指针来增加指针。


但是s在方括号中。这就是为什么我认为它将首先增加的原因。(如果我们有一个像“ a”这样的简单字符串,现在将指向“ / 0”)。由于条件现在为while(0),因此永远不会进入while循环。
lor

2

后递增运算符将操作数的值增加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"

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.