2017-06-21 54 views
1

我寫了下面的代碼,目的是在字符串上使用指針算術來查找和替換目標子字符串。很明顯,這不是優雅的,但不幸的是它也是不正確的 - 它給字符串添加了無關的字符。查找和替換子字符串(C語言)

#include <stdio.h> 
#include <string.h> 

int main() { 
    char string[] = "The quick brown fox jumped over the lazy dog."; 
    char target[] = "brown" 
    char replacement[] = "ochre"; 
    char segment[80+1]; 
    char pre_segment[80+1]; 
    char post_segment[80+1]; 
    int S = strlen(string), T = strlen(target); 
    for (int i = 0; i < S; i++) { 
     strncpy(segment, string + i, T); 
     if (strcmp(segment, target) == 0) { 
     >>> strncpy(pre_segment, string, i); <<< 
      strncpy(post_segment, string + i + T, 
       S - (i + T)); 
      strcat(pre_segment, replacement); 
      strcat(pre_segment, post_segment); 
      printf("%s\n", pre_segment); 
     } 
    } 
    return 0; 
} 

線條爲標誌像>>>這< < <後,多餘的字符已經預先考慮到更換前更換與pre_segment串聯。

有人可以給我一些關於如何調試的建議嗎? (對於更好的解決方案的建議也是受歡迎的,但請儘量明確說明。另外,我不應該爲此使用動態內存分配。)

+0

「如何調試這個」?用同樣的方法可以調試大多數程序。使用調試器來執行代碼並檢查狀態。 – kaylum

+0

@kaylum我可以告訴你哪裏出錯了,我希望有更多的知識能夠幫助我理解*爲什麼*。 – Chris

+1

那你爲什麼不告訴我們哪裏出了問題?這將是有用的信息 - 所以我們不必自己調試,也可以證明你已經完成了。你明確地問「如何調試這個」。 – kaylum

回答

5

請勿使用strncpy。它幾乎肯定不會做你認爲它做的事。特別是,它並不能保證NUL終止,同時愚弄人們認爲它確實如此。如果您想要精確複製n個字符,請使用memcpy(dest, src, n);,然後明確NUL終止於dest[n] = '\0';。缺少NUL終止可能會導致您的問題。 (請在您的調試器中檢查!)

但是,根本不需要執行strncpy。使用strncmpmemcmp。 (如果知道字符串中至少有strlen(target)個字節,則僅使用memcmp。)如果strlen(target)字節在string的某個點開始匹配target,那麼您已找到匹配項。

更好的辦法是使用strstr來查找下一次出現的字符串。

+0

非常感謝。嘗試後我會馬上回來! – Chris

+0

您的建議正好適合我,所以如果您不介意,我可以問一些跟進問題嗎? (1)你怎麼知道這是錯誤的,(2)你如何在調試器中識別這個確切的問題? (即它看起來像什麼?) – Chris

+1

@chris:「添加無關字符」通常意味着沒有終止的字符串,並且濫用'strncpy'通常會導致未終結的字符串。所以我開始以經驗爲基礎的偏見。您將通過查看strlen發出意外值(或段錯誤)或打印無關字符,或通過查找NUL終止符而未找到它來在調試器中看到它。 'strncpy'被設計用於打包的固定長度數據庫字段,但是已經有一個神話,它比strcpy更安全。所以它總是值得一看。 – rici

0

我不能同意@rici,它表示不應該使用函數strncpy。任何功能都可能被錯誤地使用。而strncpy也不例外。你應該記住,函數不需要複製一個字符串。所以你有自己明確地追加一個零字符到複製的字符序列。

你忘了這麼做。

雖然你的實現過於複雜和混亂,但無論如何它應該仔細寫。

這是您程序的更新版本。注意這些語句

segment[T] = '\0'; 
pre_segment[i] = '\0'; 
post_segment[S - (i + T)] = '\0'; 

或者如果你喜歡TP使用指針,那麼你可以寫

*(segment + T) = '\0'; 
*(pre_segment + I) = '\0'; 
*(post_segment + S - (i + T)) = '\0'; 

給你。

#include <stdio.h> 
#include <string.h> 

int main(void) 
{ 
    char string[] = "The quick brown fox jumped over the lazy dog."; 
    char target[] = "brown"; 
    char replacement[] = "ochre"; 
    char segment[80+1]; 
    char pre_segment[80+1]; 
    char post_segment[80+1]; 

    size_t S = strlen(string), T = strlen(target); 

    for (size_t i = 0; i < S; i++) 
    { 
     strncpy(segment, string + i, T); 
     segment[T] = '\0'; 

     if (strcmp(segment, target) == 0) 
     { 
      strncpy(pre_segment, string, i); 
      pre_segment[i] = '\0'; 

      strncpy(post_segment, string + i + T, S - (i + T)); 
      post_segment[S - (i + T)] = '\0'; 

      strcat(pre_segment, replacement); 
      strcat(pre_segment, post_segment); 
      printf("%s\n", pre_segment); 
     } 
    } 

    return 0; 
} 

程序輸出是

The quick ochre fox jumped over the lazy dog. 
+3

我沒有閱讀@rici的意見,表示不應該使用'strncpy()';它經常被濫用。爲了「安全」的利益,有些人希望將任何'strcpy()'的實例轉換爲'strncpy()',這種情況往往是正確的選擇。 –

+0

我,呃,增加了你的聲望(這個網站不喜歡這樣的評論)。我很感謝你在複製後拼出空字符的重要性。 – Chris

1

你應該總是在你的代碼分割成更小的部分(功能),我們可以找出在更換子的過程中的兩個關鍵步驟,找到子然後更換它。 這是一個解決方案我建議你,它已經三年了,因爲我寫的代碼,我的最後一個C線,所以這是不完美的,但它的工作:

#include <stdio.h> 
#include <string.h> 


int find_occurence(char* original, char *target){ 
    size_t counter = 0; 
    char *index = original; 
    do{ 
    while(target[counter] == index[counter]) 
     counter++; 
    if (counter >= strlen(target)) 
     return (int)(index-original); 
    else 
     counter = 0; 
    } 
    while(*(index++)); 
    return -1; 
} 

void replace(char *original, char *target, char *replacement,char *destination){ 
    int index = find_occurence(original, target); 
    if (index == -1) 
    { 
    strncpy (destination, original, strlen(original)+1); 
    return; 
    } 

    char *last_part; 

    //Copy the string before target 
    strncpy (destination, original, index); 

    //Copy the replacement 
    strncpy (&destination[index], replacement, strlen(replacement)); 

    //Extract the part after the target 
    last_part = &original[index+strlen(target)]; 

    //Copy the part after the target plus the \0 character 
    strncpy (&destination[index+strlen(replacement)],last_part,strlen(last_part)+1); 
} 


int main() { 
    char *original = "I want to replace literally this by that"; 
    char *target = "this"; 
    char *replacement = "that"; 
    char destination[100]; 

    replace(original,target,replacement, destination); 

    printf("%s\n",destination); 


} 
+0

這可能就像我剛纔提到的那樣,沒有完美的地方,讀者應該建立它,但是,我會審查和更新它,謝謝你的重要注意事項 – SEDaradji

+0

我修正了上面的代碼,我相信它是可以接受的解決方案目前狀態 – SEDaradji

+0

感謝您的支持,它已經超過三年了,因爲我停止在c編碼,這應該做 – SEDaradji