在C中的for循环条件中调用strlen()的最佳替代方法是什么?
我已经读过在我的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)如果字符串长度在循环中被修改,只要长度不是<i,它应该仍然到达终点。
但是,我不确定。 其中哪一个是C程序员的标准做法?
第二个通常是首选。
另一种流行的forms是
for (char* p = something; *p; p++) { // ... work with *p }
还有一个是
char* p = something; char c; while ((c = *p++)) { // ... do something with c }
(需要额外的()
分配,以使一些可疑的编译器不发出警告,说明我可能意味着while
条件内while
比较)
确实, strlen
非常慢,因为它必须通过整个字符串寻找尾随0.因此, strlen
基本上实现为
int s = 0; while (*p++) s++; return s;
(实际上,使用稍微更优化的汇编程序版本)。
所以你应该尽可能避免使用strlen
。
这些是首选:
for (int i = 0; str[i]; ++i) for (char* p = str; *p; ++p)
如果循环的某些部分可以覆盖字符串末尾的NUL字符,那么调用strlen的版本仍然会在缓冲区结束之前完成。 第二个版本可以超出缓冲区并聚集在别人的记忆中。 strlen版本一目了然也更容易理解。
通常是第二个。 如果没有别的,第一个必须遍历字符串两次:一次查找长度,再次操作每个元素。 另一方面,如果您已经编写了代码strlen,则可能更容易将strlen调用提升出循环并仍然获得大部分好处。
第一种方法对我来说是这样的:
while(..) { Test end of string } /* strlen */ while(..) { Your Code } /* processing */
而第二种方法看起来像:
while(..) { Your Code + Test end of string } /* both */
恕我直言,这两种方法计算的操作数量大致相同,我认为它们是等价的。 另外,如前所述,strlen已经过优化 ,并经过了充分测试。 此外,第二种方法看起来像是过早优化:)如果需要,你最好测试/分析你的代码,然后优化(毕竟,它只是一个线性算法)。
然而,如果处理可能在字符串结束之前很久就停止(例如,找到单词的第一次出现),则可以考虑第二种方法。
正如其他答案所述,虽然两种选择都适用,但第二种选择更常见。 但是反对’\ 0’的比较字符不是我推荐的。 ‘\ 0’的类型是int,而不是char。 也就是说,它具有与0相同的类型。但是,写”0’比仅仅0更容易出错,因为偶然的退格可以将其转换为’0’,这根本不相同。 偶然读取代码的人可能不会轻易发现此错误。