【问题标题】:What is the best alternative to calling strlen() in my for loop condition in C?在 C 中的 for 循环条件中调用 strlen() 的最佳替代方法是什么?
【发布时间】:2010-03-03 17:36:32
【问题描述】:

我了解到在我的 for 循环条件中调用 strlen() 是一种不好的做法,因为这是一个 O(N) 操作。

但是,在寻找替代方案时,我看到了两种可能的解决方案:

int len = strlen(somestring);  
for(int i = 0; i < len; i++)  
{

}

或者...

for(int i = 0; somestring[i] != '\0'; i++)  
{

}

现在,第二个选项似乎具有以下优点:1)不声明不必要的变量,以及 2)如果在循环中修改字符串长度,只要长度不是,它仍然应该到达末尾

但是,我不确定。以下哪一项是 C 程序员的标准做法?

【问题讨论】:

    标签: c string for-loop


    【解决方案1】:

    通常首选第二个。

    另一种流行的形式是

    for (char* p = something; *p; p++)
    {
       // ... work with *p
    }
    

    还有一个是

    char* p = something;
    char c;
    while ((c = *p++))
    {
        // ... do something with c
    }
    

    (需要额外的 () 赋值以使一些可疑的编译器不会发出警告,说明我可能意味着在 while 条件内进行比较)

    确实,strlen 很慢,因为它必须遍历整个字符串来寻找尾随的 0。所以,strlen 本质上是这样实现的

    int s = 0;
    while (*p++) s++;
    return s;
    

    (嗯,实际上使用了稍微优化的汇编器版本)。

    所以你应该尽可能避免使用strlen

    【讨论】:

    • 你需要 *p 作为条件,而不是 p;
    • 确实如此。刚刚添加了一个版本。
    • 那么,null char 被解释为 false 呢? null 是否也不会被解释为假(即,将条件保留为指针 p,而不是 *p)?
    • 在 C 中,没有真/假,根本没有 bool 类型。 int 0 表示 false,ints != 0 表示 true。
    • @Vlad: 指向最后一个字符的指针总是不是标准 C 中的空指针。6.3.2.3/3 说,“...空指针,是保证比较不等于指向任何对象或函数的指针。”当地址 0 是空指针时,允许您映射地址 0 的奇怪内核模式是非标准的。
    【解决方案2】:

    这些是首选:

    for (int i = 0; str[i]; ++i)
    for (char* p = str; *p; ++p)
    

    【讨论】:

      【解决方案3】:

      如果循环的某些部分可以覆盖字符串末尾的 NUL 字符,则调用 strlen 的版本仍将在缓冲区结束之前完成。第二个版本可能会超出缓冲区并在其他人的内存中聚会。 strlen 版本也更容易一目了然。

      【讨论】:

      • 不知道的,NULL是空指针,而NUL是'\0'代表的ASCII字符。
      【解决方案4】:

      通常是第二个。如果不出意外,第一个必须遍历字符串两次:一次是为了找到长度,另一次是对每个元素进行操作。另一方面,如果您已经编写了 strlen 代码,那么将 strlen 调用提升到循环之外并仍然获得大部分的好处可能会更容易。

      【讨论】:

        【解决方案5】:

        第一种方法对我来说是这样的:

        while(..) { Test end of string }  /* strlen */
        while(..) { Your Code }           /* processing */
        

        虽然第二种方法看起来像:

        while(..) { Your Code + Test end of string } /* both */
        

        恕我直言,这两种方法计算的操作数量大致相同,并且 我认为它们是等价的。另外,如前所述,strlen 是quite optimized, 并经过良好测试。 此外,第二种方法看起来像过早的优化:) 你最好 如有必要,测试/分析您的代码,然后进行优化(毕竟,它只是一种线性算法)。

        但是,如果处理 可能会在字符串结束之前很久就停止(例如,找到一个单词的第一次出现)。

        【讨论】:

        • 其实第一个是O(2n),第二个是O(n)。它们只有在无关紧要时才大致等价
        • 考虑到大 O 表示法,它们都是 O(n)。我的观点是,如果你展开循环,你有 (nx) + (ny) == n * (x+y) 操作,这就是为什么我不认为第二种方法是速度是第一个的两倍。通常,我们希望优化并进行一次复杂的处理,而不是多次简单的迭代;根据实际问题,它可能是高度合理的,也可能不是;我也认为优化这样的线性算法并不能有效地利用可用的编码时间。
        【解决方案6】:

        正如其他答案所述,虽然这两个选项都有效,但第二个更常见。但是我不建议将字符与 '\0' 进行比较。 '\0' 的类型是 int,而不是 char。也就是说,它与 0 具有相同的类型。但是,写 '\0' 比只写 0 更容易出错,因为意外的退格可以将其转换为 '0',这根本不一样。随便阅读代码的人可能不容易发现此错误。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-08-05
          • 2019-09-06
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多