【问题标题】:Why does this function return the correct length of a string? (Incrementing a char pointer)为什么此函数返回正确长度的字符串? (增加一个 char 指针)
【发布时间】:2020-05-01 05:53:59
【问题描述】:

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

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

为什么这会返回正确的长度?

假设我用一个简单的字符串"a" 调用这个函数。然后s在while循环中递增,因此si的值都是0。

【问题讨论】:

    标签: c while-loop strlen c89


    【解决方案1】:

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

    在该示例中,s 指向"a" 中的'a'。然后递增,i 也递增。现在s 指向空终止符,i1。所以在下一次循环中,*(s++)'\0'(即0),所以循环结束,返回i(即1)的当前值。

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

    【讨论】:

    • 因为s在方括号中,我认为它会先递增(所以现在它指向'/0')。因此,while 循环为 false,并且 i 永远不会递增。
    • @lor,记住后自增操作符是什么:它计算 sbefore 递增时所持有的任何值。您所描述的是++s 的行为(确实会少一分,如果传递一个空字符串则调用UB)。
    【解决方案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 循环。
    【解决方案3】:

    s++ 的值是s 的原始值,在递增之前,递增发生在下一个序列点之前的未指定时间。

    因此*s++*(s++) 是等价的:它们都取消引用s 的原始值。另一个等价的表达式是*(0, s++),不适合胆小的人,这就是:0[s++]

    但是请注意,您的函数应该使用类型 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++,坏事就会发生:)
    【解决方案4】:

    后自增运算符将操作数的值增加 1但表达式的值是自增操作之前操作数的原始值。

    假设传递给str_len() 的参数是"a"。在str_len() 中,指针s 指向字符串"a" 的第一个字符。在while 循环中:

    while(*(s++)) {
    .....
    .....
    

    虽然s 会递增,但表达式s 的值将是指向它在递增之前指向的字符的指针,即指向第一个字符'a' 的指针.当指针s 被取消引用时,它将给出字符'a'。在下一次迭代中,s 指针将指向下一个字符,即空字符\0。当s 被取消引用时,它将给出0 并且循环将退出。请注意,s 现在将指向字符串 "a" 的空字符之后的一个元素。

    【讨论】:

      猜你喜欢
      • 2016-05-12
      • 2015-01-02
      • 2021-10-15
      • 2021-12-20
      • 2013-08-03
      • 1970-01-01
      • 1970-01-01
      • 2017-02-19
      • 1970-01-01
      相关资源
      最近更新 更多