为什么循环不重复?

时间:2020-04-22 06:48:26

标签: c

我的问题是:给定一个句子,如果该句子的开头是单词“ THE”,则仅删除该句子的最后一个“ WE”,否则删除所有“ THE

我的代码不会删除第一个THE之后的第二个THE。 怎么了?

int main(){

    char sent[100];
    int i;

    printf("Enter a sentence: ");
    gets(sent);

    if(sent[0] == 'w' && sent[1] == 'e'){
        for (i=2;i<strlen(sent);i++){
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
                while( i < strlen(sent)){
                sent[i] = sent[i+1];
                sent[i] = sent[i+2];
                sent[i] = sent[i+3];
                sent[i] = sent[i+4];
                i++;
            }
            printf("\n%s",sent);
            }

        }
    }
    else
        for (i=0;i<strlen(sent);i++){
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
                while( i < strlen(sent)){
                sent[i] = sent[i+1];
                sent[i] = sent[i+2];
                sent[i] = sent[i+3];
                sent[i] = sent[i+4];
                i++;
            }
            printf("\n%s",sent);
            }

        }

    return 0;
}

2 个答案:

答案 0 :(得分:0)

您的问题是复制剩余文本的内部循环:

   for (i=2;i<strlen(sent);i++){
        if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
            while( i < strlen(sent)){
            sent[i] = sent[i+1];
            sent[i] = sent[i+2];
            sent[i] = sent[i+3];
            sent[i] = sent[i+4];
            i++;
        }
        printf("\n%s",sent);
        }
    }

主要有2个问题:

  1. 如果删除单词,则必须继续在同一位置搜索。循环迭代完成后,将执行i++,前进到下一个位置。因此,如果您删除了i--;的出现,则需要通过添加the来抵消这种影响。

  2. 您的用于复制其余文本的内部循环会弄乱您用于外部循环的计数器。复制文本后,i指向终止循环的最后一个字符。您必须使用单独的计数器。

...以及其他一些问题:

  1. 次要问题: 您在复制循环中没有用的分配。如果您为sent[i]分配了一系列值,则只有最后一个值才会生效。

  2. 次要问题: 使用strlen作为循环条件会导致大量额外的运行时间。仅在必要时使用它。对于内部循环,只需检查一次长度并将其存储。

  3. gets是邪恶的。您应该改用fgets

更新后的版本可能如下所示:

       size_t len = strlen(sent);  // Calculate limit only once
       for (i=2; i < len; i++) {
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' ') {
                size_t j = i;
                while (j <= len-4) { // also copy the terminating 0 byte
                    sent[j] = sent[j+4];
                    j++;
                }
                printf("\n%s",sent);

                len -= 4;    // String was shortened
                i--;         // Check current position again.
            }
        }

注意: 您还应该考虑到最后一个词可能是the,而没有多余的空格...

您可能还会考虑使用标准的C库函数,例如strstr ...

答案 1 :(得分:0)

第一次出现单词the时终止循环的错误是内部while循环会修改外部i循环的循环变量for

        for (i=0;i<strlen(sent);i++){
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
                /* after this loop i points to the end of the string */
                while( i < strlen(sent)){
                    sent[i] = sent[i+1];
                    sent[i] = sent[i+2];
                    sent[i] = sent[i+3];
                    sent[i] = sent[i+4];
                    i++;
                }
                printf("\n%s",sent);
            }
        }

因此,当while循环将i移动到字符串的末尾时,外部for循环也将终止。

可以通过对内部循环使用单独的变量来解决此问题。 我还尝试修复越界访问并将strlen移出了循环。 (仍不完整,请参见下文)

        /* the length is constant except when we remove "the " */
        size_t len = strlen(sent);
        for (i=0; i < len; i++){
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
                /* use separate variable for inner loop */
                int j = i;
                /* limit len-3 tp prevent sent[j+4] from reading past the NUL ('\0') character */
                while( j < len-3){
                    /* useless assignments to the same array element removed */
                    sent[j] = sent[j+4];
                    j++;
                }
                len -= 4; /* we removed 4 characters */
                printf("\n%s",sent);
            }
        }

此代码仍然存在不能删除“ the”的问题,因为for循环在删除“ the”之后不会再次检查相同位置。

一种选择是在删除“ the”之后递减i。如果字符串以“ the”开头,则会将i暂时设置为-1for语句将再次增加它。

我更喜欢仅在找不到 的情况下才递增i。 这就是为什么将i++for语句移到循环主体中的原因。

        /* the length is constant except when we remove "the " */
        int len = strlen(sent);
        for (i=0; i < len; /* no i++ here */){
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
                /* use separate variable for inner loop */
                int j = i;
                /* limit len-3 tp prevent sent[j+4] from reading past the NUL ('\0') character */
                while( j < len-3){
                    /* useless assignments to the same array element removed */
                    sent[j] = sent[j+4];
                    j++;
                }
                len -= 4; /* we removed 4 characters */
                printf("\n%s",sent);
            } else {
                /* advance to the next character only if we didn't just remove "the " */
                i++;
            }
        }

while循环也可以写为for循环。

        /* the length is constant except when we remove "the " */
        int len = strlen(sent);
        for (i=0; i < len; /* no i++ here */){
            if(sent[i] == 't' && sent[i+1] == 'h' && sent[i+2] == 'e' && sent[i+3] == ' '){
                /* use separate variable for inner loop */
                /* limit len-3 tp prevent sent[j+4] from reading past the NUL ('\0') character */
                for(int j = i; j < len-3; j++){
                    /* useless assignments to the same array element removed */
                    sent[j] = sent[j+4];
                }
                len -= 4; /* we removed 4 characters */
                printf("\n%s",sent);
            } else {
                /* advance to the next character only if we didn't just remove "the " */
                i++;
            }
        }

注意:您可以用各种不同的方式编写循环,因此,从注释中可以看到其他有效的解决方案。