2013-08-21 239 views
0

我用下面從刪除空格我的變量刪除白色空間

 for (i=0, ptr=lpsz;ptr[i];ptr++) 
     { 
      if (*ptr == ' ') 
       i++; 

      *ptr = ptr[i]; 
     } 
     *ptr=0; 

這似乎是有問題的時候有但是不止一個空間,我不知道我做錯了。任何人都可以幫助我嗎?

+1

它用字符串中的下一個字符替換一個空格,然後在替換之後移動到字符*上。替換字符從不檢查。 –

+0

@ xen-0謝謝。我的字符串就像今天的「你好世界」。並且在它讀到'helloworldoday'後缺少第三個單詞的第一個字母。作爲一個新手我很困惑..大聲笑 –

+0

錯誤的問題;現在就制定答案。 –

回答

2

這應該工作。考慮穿過字符串的兩個指針比一個指針加上一個偏移量要容易得多。

auto sptr = lpsz; 
auto dptr = lpsz; 
while (*dptr = *sptr) { // copy up to and including terminating NUL 
    if (*dptr != ' ') dptr++; // but spaces take no slots in the destination 
    sptr++; 
} 

甚至

auto sptr = lpsz; 
auto dptr = lpsz; 
while (auto c = *dptr = *sptr) { 
    dptr += (c != ' '); 
    sptr++; 
} 

這和原來的代碼之間的本質區別是,當我們看到其他的東西比一個空間,無論是我的,原本將讀寫位置向前移動一個。但是當我們看到一個空間時,我將讀取位置向前移動1,並且不移動寫入位置,而原稿將讀取位置向前移動2,寫入位置向前移動1,從而跳過字符。另外,原件正在寫入位置測試一個空間,而不是在讀取位置(我的測試寫入位置,但是從讀取位置複製字符後結果爲,所以結果是正確的)。

6

我建議你使用std::isspace而不是做你的指針魔術。

如果結合使用std::stringstd::isspace你可以做這樣的事情:

std::string str = "Hello World Today"; 

str.erase(remove_if(str.begin(), str.end(), isspace), str.end()); 

source

的字符串真的只是個字符的容器,因此您可以將擦除/去掉它的成語。

+0

這是如何工作,而不是指針魔術? – 0x499602D2

+0

@ 0x499602D2:真的,它是'remove_if',它取代了指針魔術。 –

+5

請注意,此代碼是**不是**安全的,並可能導致未定義的行爲,例如,與我的名字一起使用時!問題是'std :: isspace()'和family只接受正面的參數,但'char'可能被簽名。你需要使用類似於'[](unsigned char c){return std :: isspace(c); }'。當然,要替換原來的代碼,'std :: remove(str.begin(),str.end(),'')'會起作用。 –

0

仔細地通過你的循環。

i在循環開始時設置爲0。 對於遇到的第一個空間,i增加(因此i==1)。 ptr中的字符被下一個字符prt+i中的字符替換。此作品是第一次,因爲i是1

但對於第二空間,i設置爲2(因爲它增加),所以空間由字符在ptr+2

更換這將是多少容易做到這一點,作爲字符串複製的一部分,而不是就地更改。 dest是我們更改副本的目標緩衝區。

for(ptr = lpsz; *ptr; ptr++){ 
    if(' ' == *ptr) {continue;} 
    *dest = *ptr; 
    dest++; 
} 
*dest = 0; 
+0

它會。這很有趣,因爲我也是在原始代碼中挑選的。編輯的代碼。 –

+0

@DavidRodríguez-dribeas:我寧願說它不會對空格做任何特殊的事情,但它會對零做任何事情;)(當你寫下你的評論,我最初寫了這個評論) –

1

你應該使用這個算法,因爲它們經過了很好的測試。但是如果你想分析你的代碼並理解失敗,請考慮對你的代碼運行的高級描述(參見Tony的答案)。

您在緩衝區中維護兩個索引,一個用於讀取,另一個用於寫入。每當讀數頭檢測到一個空間時,您將其移動,但跳過寫入。如果字符不是空格,則使用讀取頭獲取值並通過寫入頭寫入。

在您的實現中,讀取頭是ptr+i,這與寫入頭的偏移有點奇怪(如ptr[i])。寫頭是ptr*ptr =)。但是你在循環中的測試是使用寫入頭替代讀取頭:if (*ptr==' ')

即使你解決了這個問題,實現還有其他問題,比如說如果有兩個連續的空格,因爲你在循環中做了單個測試。你的算法的改寫可能是:

char* remove_spaces(char* buffer) { 
    char *read = buffer; 
    for (char *read = buffer; (*read), ++read) { 
     if (*read != ' ') {  // copy element 
     *buffer = *read; 
     ++buffer;    // and increment write head 
     } 
    } 
    *buffer = 0;    // ensure null termination 
    return read; 
} 

現在,該算法可以進一步提高(性能)通過移除寫入需要記憶的號碼,如果你做的第一空間中的初始搜索,並使用它作爲起點點上面的循環。這將減少標記爲髒的操作數量和緩存行數量。