2017-06-21 30 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