我的问题是:给定一个句子,如果该句子的开头是单词“ 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;
}
答案 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个问题:
如果删除单词,则必须继续在同一位置搜索。循环迭代完成后,将执行i++
,前进到下一个位置。因此,如果您删除了i--;
的出现,则需要通过添加the
来抵消这种影响。
您的用于复制其余文本的内部循环会弄乱您用于外部循环的计数器。复制文本后,i
指向终止循环的最后一个字符。您必须使用单独的计数器。
...以及其他一些问题:
次要问题:
您在复制循环中没有用的分配。如果您为sent[i]
分配了一系列值,则只有最后一个值才会生效。
次要问题:
使用strlen
作为循环条件会导致大量额外的运行时间。仅在必要时使用它。对于内部循环,只需检查一次长度并将其存储。
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
暂时设置为-1
。 for
语句将再次增加它。
我更喜欢仅在找不到 的情况下才递增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++;
}
}
注意:您可以用各种不同的方式编写循环,因此,从注释中可以看到其他有效的解决方案。