2010-08-02 17 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下編譯,請隨時重新編譯。