问题描述
我正在阅读The C Programming Language这本书,但我无法弄清楚我在这个练习中的代码有什么问题。
该练习要求您实现一个版本的 squeeze()
函数,该函数删除 s1 中与字符串 s2 中任何字符匹配的每个字符。
这是我的代码:
#include <stdio.h>
#include <stdlib.h>
int main ()
{
char s1[100];
char s2[100];
int c;
int i;
int j;
int flag=0;
char s3[100];
printf("TYPE THE FirsT STRING\n");
for(i=0;s1[i-1]!='\n';i++)
{
scanf("%c",&s1[i]);
}
printf("\n\nTYPE THE SECOND STRING\n");
for(i=0;s2[i-1]!='\n';i++)
{
scanf("%c",&s2[i]);
}
for(i=0;s1[i]!='\n';i++)/*sets the "i" character of s1 to be compared*/
{
for(j=0;s2[j]!='\n';j++)/*compares the "i" character in s1 with
{ every character on s2*/
if(s1[i]==s2[j])
{
flag=1;/*sets the flag variable to one if it finds 2 equal
break; characters and stops the looP*/
}
}
if(flag!=1)/*if it have not found a matching pair of chacters,{ this part copies the s1 char to s3*/
s3[i]=s1[i];
}
flag=0;
printf("\n");
}
printf("\n\n%s",s3);
return 0;
}
问题是,如果我在 s1 中输入“test”,在 s2 中输入“second”,它只会打印“t”。一旦找到匹配的对,它就会停止。 flag
工作不正常?我在这个练习中超过 2 小时,无法解决。
解决方法
for (i = 0; s1[i-1] != '\n'; i++)
此循环第一次迭代的谓词将访问超出边界的s1[-1]
,并依次调用undefined behavior。涉及 s2
的循环也有同样的问题。
此外,您的字符串永远不会以 NUL 结尾,并且它们的缓冲区很容易通过 scanf
溢出。
您有多个跨多行的 /* */
注释实例,它们注释掉了您的代码部分:两个开头的 {
和 break
。
即使解决了评论的问题
if (flag != 1) {
s3[i] = s1[i];
}
会在你的最后一根弦上留下洞。您需要一个单独的 s3
索引计数器,它只会随着字符串长度的增加而增加。
一个简单的例子,我们初始化我们的缓冲区(特别是这个 NUL 终止 s3
),并使用 fgets
来限制我们的输入。
#include <stdio.h>
#include <stdlib.h>
int main(void) {
char s1[100] = { 0 },s2[100] = { 0 },s3[100] = { 0 };
int flag = 0;
size_t k = 0;
if (
!fgets(s1,sizeof s1,stdin) ||
!fgets(s2,sizeof s2,stdin)
) {
fprintf(stderr,"Could not read input.\n");
return EXIT_FAILURE;
}
for (size_t i = 0; s1[i] && s1[i] != '\n'; i++) {
for (size_t j = 0; s2[j] && s2[j] != '\n'; j++) {
if (s1[i] == s2[j]) {
flag = 1;
break;
}
}
if (flag == 0)
s3[k++] = s1[i];
flag = 0;
}
printf("%s\n",s3);
}
或者,使用strchr
,我们可以组成一个整洁的函数:
#include <string.h>
void squeeze(char *dest,const char *source,const char *filter) {
for (; *source; source++)
if (!strchr(filter,*source))
*dest++ = *source;
*dest = '\0';
}