在C中从字符串中删除子字符串

在C中从字符串中删除子字符串,c,string,loops,C,String,Loops,我已经有了在C中从字符串(单词)中删除子字符串的代码,但我不理解它。有人能给我解释一下吗?它不使用标准库中的函数。我试着自己分析,但某些部分我仍然不明白——我把它们放在了评论中。我只是想弄清楚这一切是怎么回事 谢谢 #include <stdio.h> #include <stdlib.h> void remove(char *s1, char *s2); int main() { char s1[101], s2[101]; printf("First w

我已经有了在C中从字符串(单词)中删除子字符串的代码,但我不理解它。有人能给我解释一下吗?它不使用标准库中的函数。我试着自己分析,但某些部分我仍然不明白——我把它们放在了评论中。我只是想弄清楚这一切是怎么回事

谢谢

#include <stdio.h>
#include <stdlib.h>
void remove(char *s1, char *s2);

int main()
{
   char s1[101], s2[101];
   printf("First word: ");
   scanf("%s", s1);
   printf("Second word: ");
   scanf("%s", s2);
   remove(s1, s2);
   printf("The first word after removing is '%s'.", s1);

   return 0;
}
void remove(char *s1, char *s2)
{
   int i = 0, j, k;
   while (s1[i])       // ITERATES THROUGH THE FIRST STRING s1?
   {
       for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // WHAT DOES THIS LINE DO?
          if (!s2[j])           // IF WE'RE AT THE END OF STRING s2? 
             {
                 for (k = i; s1[k + j]; k++)   //WHAT DOES THIS ENTIRE BLOCK DO?
                    s1[k] = s1[k + j];
                    s1[k] = 0;
              }
          else
              i++;    // ???
    }
}
#包括
#包括
无效删除(字符*s1,字符*s2);
int main()
{
字符s1[101],s2[101];
printf(“第一个单词:”);
scanf(“%s”,s1);
printf(“第二个词:”);
scanf(“%s”,s2);
移除(s1,s2);
printf(“删除后的第一个单词是“%s.”,s1);
返回0;
}
无效删除(字符*s1,字符*s2)
{
int i=0,j,k;
while(s1[i])//遍历第一个字符串s1?
{
for(j=0;s2[j]&&s2[j]==s1[i+j];j++);//这行是做什么的?
if(!s2[j])//如果我们在字符串s2的末尾?
{
for(k=i;s1[k+j];k++)//整个块做什么?
s1[k]=s1[k+j];
s1[k]=0;
}
其他的
i++;/???
}
}

这里的主要功能如下:

-跳过两个字符串之间的公共部分,并为第一个字符串指定新字符串

while (s1[i])       // Yes It ITERATES THROUGH THE FIRST STRING s1
       {
           for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // Here it skips the part which is 
//similar in both
由于此循环只是增加了公共部分的索引,因此将跳过s1中的数据存储

if (!s2[j])           // IF WE'RE AT THE END OF STRING s2
{
 for (k = i; s1[k + j]; k++)   //Here it is re assigning the non common part.
 s1[k] = s1[k + j];
 s1[k] = 0;
}
else
 i++;    // it is req. if both have more values.
}

在这里,函数的主要工作如下:

-跳过两个字符串之间的公共部分,并为第一个字符串指定新字符串

while (s1[i])       // Yes It ITERATES THROUGH THE FIRST STRING s1
       {
           for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // Here it skips the part which is 
//similar in both
由于此循环只是增加了公共部分的索引,因此将跳过s1中的数据存储

if (!s2[j])           // IF WE'RE AT THE END OF STRING s2
{
 for (k = i; s1[k + j]; k++)   //Here it is re assigning the non common part.
 s1[k] = s1[k + j];
 s1[k] = 0;
}
else
 i++;    // it is req. if both have more values.
}
第一个
while(s1[i])
遍历s1。是的,你说得对

for (j = 0; s2[j] && s2[j] == s1[i + j]; j++); 
上述for循环检查子串s2是否存在于从s1[i]开始的s1中。如果匹配,s2将完全迭代。如果不是,则在for循环的末尾,s2[j]将不是空字符。示例:如果s1=ITERATE,s2=RAT,则循环将仅在i=3时完全执行
所以
如果(!s2[j])
成立,则表示我们找到了一个子串,i是s1中子串的起点

         for (k = i; s1[k + j]; k++)   //WHAT DOES THIS ENTIRE BLOCK DO?
            s1[k] = s1[k + j];
            s1[k] = 0;
abov块删除子字符串。因此,对于ITERATE和RAT示例,这是通过在存在R和A的位置复制E和null字符来完成的。for循环实现了这一点。如果for循环后s2[j]不为null,则i将递增,以检查是否从s1的下一个位置进行了替换。

第一个
,而(s1[i])
将迭代s1。是的,你说得对

for (j = 0; s2[j] && s2[j] == s1[i + j]; j++); 
上述for循环检查子串s2是否存在于从s1[i]开始的s1中。如果匹配,s2将完全迭代。如果不是,则在for循环的末尾,s2[j]将不是空字符。示例:如果s1=ITERATE,s2=RAT,则循环将仅在i=3时完全执行
所以
如果(!s2[j])
成立,则表示我们找到了一个子串,i是s1中子串的起点

         for (k = i; s1[k + j]; k++)   //WHAT DOES THIS ENTIRE BLOCK DO?
            s1[k] = s1[k + j];
            s1[k] = 0;

abov块删除子字符串。因此,对于ITERATE和RAT示例,这是通过在存在R和A的位置复制E和null字符来完成的。for循环实现了这一点。如果for循环后s2[j]不为null,则i将递增,以检查是否从s1的下一个位置进行了替换。

以下是注释中浓缩的功能方法

void remove(char *s1, char *s2)
{
   int i = 0, j, k;
   while (s1[i])       // Iterates through s1 (until it finds a zero)
   {
       for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // Iterates through s2 while both it is NOT the end of the string s2 and each character of s2 coincides with s1 (if s2 == s1, j points to the end of s2 => zero)
          if (!s2[j])           // If j point to the end of s2 => We've found the coincidence
             {
                 for (k = i; s1[k + j]; k++)   //Remove the coincident substring
                    s1[k] = s1[k + j];
                    s1[k] = 0;
              }
          else
              i++;    // There is no coincidence so we continue to the next character of s1
    }
}

注意:我还注意到,这可能很容易爆发,因为它在s1范围之外迭代。

这里是一种在注释中浓缩的功能方法

void remove(char *s1, char *s2)
{
   int i = 0, j, k;
   while (s1[i])       // Iterates through s1 (until it finds a zero)
   {
       for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);   // Iterates through s2 while both it is NOT the end of the string s2 and each character of s2 coincides with s1 (if s2 == s1, j points to the end of s2 => zero)
          if (!s2[j])           // If j point to the end of s2 => We've found the coincidence
             {
                 for (k = i; s1[k + j]; k++)   //Remove the coincident substring
                    s1[k] = s1[k + j];
                    s1[k] = 0;
              }
          else
              i++;    // There is no coincidence so we continue to the next character of s1
    }
}

注意:我还注意到,这可能很容易爆发,因为它在s1范围之外迭代。

让我们将其分解。你有

while (s1[i])
{
    // Code
}
这将迭代通过
s1
。一旦到达字符串的末尾,就有了
\0
,它是空终止符。在条件下进行计算时,它将计算为
0
。在这里使用
可能更好

那么你有

for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);
这只会增加
j
。应该注意的是,这个表达式没有大括号,并且以分号结尾,因此后面的代码不应该在循环体中执行。如果括号正确,它将在以下
If/else
上循环,而
s2
不为空且
s2[j]==s1[i+j]
。除了
s2
中的字符被
s1
中的金额
I
抵消之外,我对第二部分没有任何解释。这一部分可能会得到改进,以消除不必要的迭代

然后是

if (!s2[j])
{
}
else
{
}
这将检查以确保
s2
中的位置有效,如果有效,则执行字符串删除,否则将增加
i
。当
s2
不再适合
s1
的其余部分时,可以通过返回
else
来改进

for (k = i; s1[k + j]; k++)
    s1[k] = s1[k + j];
    s1[k] = 0;
这是另一个有点奇怪的循环,因为由于没有大括号,
s1[k]=0将被设置在循环之外。这里发生的是,通过删除
s2
并将
k+j
处的字符下移到
k
来压缩字符串。在循环的末尾,
s1[k]=0
在空终止符中结束要正确结束的字符串


如果您想要更深入的理解,那么尝试编写自己的代码来做同样的事情,然后进行比较可能是值得的。我发现这通常比阅读一系列测试更有帮助。

让我们把它分解一下。你有

while (s1[i])
{
    // Code
}
这将迭代通过
s1
。一旦到达字符串的末尾,就有了
\0
,它是空终止符。在条件下进行计算时,它将计算为
0
。在这里使用
可能更好

那么你有

for (j = 0; s2[j] && s2[j] == s1[i + j]; j++);
这只会增加
j
。应该注意的是,这个表达式没有大括号,并且以一个分号结尾