2010-08-02 28 views
14

我已阅读,使用strlen比这样那样的测试更加昂贵:在循环条件中使用strlen()比仅检查空字符慢吗?

我们有一个字符串长x 100个字符。

我认为

for (int i = 0; i < strlen(x); i++) 

比这个代码更昂贵:

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

是真的吗?也许第二个代码在某些情况下不起作用,那么使用第一个代码会更好吗?

下面会更好吗?

for (char *tempptr = x; *tempptr != '\0'; tempptr++) 
+3

第二个循环粗略地说明'strlen'在内部做什么;我仍然没有看到问题的要点 – 2010-08-02 13:14:23

+1

编写并测试它。指标是了解哪个更好的最好方法。 – 2010-08-02 13:27:35

+0

如果你不得不花费时间和精力去考虑这样的事情,你可以通过购买更快的电脑来节省资金。 – 2010-08-02 14:00:51

回答

26
for (int i=0;i<strlen(x);i++) 

此代码每次迭代调用strlen(x)。所以如果x的长度为100,则strlen(x)将被调用100次。这非常昂贵。此外,strlen(x)也是每次都以与for循环相同的方式遍历x。这使得O(n^2)复杂。

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

这段代码没有调用任何函数,所以会比前面的例子快得多。由于它只循环一次,这是O(n)的复杂性。

+0

虽然答案中没有任何不正确之处,但再次比较两个版本没有意义,因为它们不是同一算法的两个不同版本。他们只是两个示例代码做不同的事情 – 2010-08-02 13:31:55

+0

他们都为字符串中的每个字符加'1'。除此之外,有点难以分辨,因为循环内的代码没有提供。 – MatthewD 2010-08-02 13:38:57

+0

+ 1,用于指出每次执行FOR循环时都会调用strlen(),并且每次都返回相同的值。 – kiamlaluno 2010-08-02 13:41:52

11

在i每次迭代x的第一代码检查长度,它需要为O(n),以找到最后0,所以需要为O(n^2),第二壳体是O(n)

+0

所以人们很高兴投票,因为O (n^2)> O(n)? ;) – 2010-08-02 13:22:12

+0

@Gregory Pakosz请他们帮助我,因为我不太了解他们之间的差异,所以为什么这么生气?我很高兴,因为他们帮助我不是因为upvoting – 2010-08-02 13:25:35

+0

我不生气,我通过让你意识到帮助你你的问题不是一个真正的问题,因此这不是一个“真正的答案”,尽管@Artyom所说的没有任何错误 – 2010-08-02 13:29:18

2

我可以假设,在第一个变体中,你会发现strlen每次迭代,而在第二个变体中,你不会那样做。
试试这个检查:

int a = strlen(x); 
for (int i = 0; i < a; i++) {...} 
2

如果没有没有编译优化。是的,因为strlen每次都会迭代字符串的每个字节,而第二个实现只会执行一次。

2

我猜编译器可以优化(检查格雷戈里Pakosz评论)你的第一个for循环,这样你会是这样的:

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

仍然是O(n)

无论如何,我认为你的第二个for循环会更快。

+0

是,但是2 * O(n),而第二个是1 * O(n)。 – falstro 2010-08-02 13:13:53

+3

编译器不能将strlen()调用移出循环,除非它知道strlen()没有副作用,并且字符串的长度在循环内部不能更改。 – JeremyP 2010-08-02 13:17:40

+2

实际上GCC可以优化'strlen',因为它被识别为内置函数,请参阅http://ridiculousfish.com/blog/archives/2010/07/23/will-it-optimize/ – 2010-08-02 13:20:45

0

当然,第一个将花费比第二个更长的时间。他们实际上并没有做同样的事情 - 第一个是每次计算字符串的长度;第二个是(有效)只做一次。

第一个版本是相同的:“?是不是更有效的调用库函数strlen(),而不是实现自己的”

for (int i=0; x[i] != 0; i++) 
    for (int j=0; j<i; j++) 
    ; 

也许你的意思是说当然,答案就是“要看情况”。你的编译器可能有strlen()的内部版本,这些版本的优化超出了你对源代码的期望,你可能在一个功能调用昂贵(现在很少见)的平台上等。

唯一的答案是正确的是“配置文件并找出”。

4

是的,你的第二个可能无法工作的时间百分之百,但它会略微相当。这是因为使用strlen()时,您必须每次调用该方法。更好的方法是这样的

int strLength = strlen(x); 
for (int i = 0; i < strLength; i++) 

希望这会有所帮助。

+1

迷人。你有什么想法,其中第二个版本不起作用,但第一个版本是? (假设循环内容不包含'i'或字符串的进一步修改。) – 2010-08-02 13:27:36

+2

@john,如果循环的主体改变了字符串的长度......例如 – mb14 2010-08-02 13:31:02

+0

拿字符串 “世界最好”怎么样? – 2010-08-02 13:31:37

0

值得注意的是,如果您不针对包含字符串的缓冲区的大小测试索引,您可能会打开缓冲区溢出问题。根据你使用这段代码所做的事情,这可能是也可能不是一个实际问题,但它很少会受到额外检查的伤害,这是一个很好的习惯。

我建议: 为(I = 0;我< buf_size & & X [I] = '\ 0';我+ +!)

其中:

  • buf_size在预定缓冲区的大小。如果x是一个数组,这将是sizeof(x);如果x是一个指针,则应该有可用的缓冲区大小。
  • 我已经从循环中删除了i的声明,因为它只是有效的c99。如果你只在c99下编译,请随时重新编译。