strcmp函数不能正常工作

3
我有一个针对结构体数组books的删除功能。我传入了记录数组、书籍作者、书籍名称以及列表大小。在这里,给定list[0].author、list[5].author和author都等于"Dan Brown"(同一个字符串)。
void delete(struct books *list,char author[],char name[],int n)
{
    int i,a;
    a=strcmp(list[0].author,list[5].author);
    printf("%d\n",a);              // prints 0
    a=strcmp(list[0].author,author);
    printf("%d\n",a);              // prints other than 0
}    

为什么会发生这种情况?这里出了什么问题?

5
确定一些字符串末尾没有'\n'吗? - Giulio Franco
1
要么使用调试器,要么将所有三个字符串都使用 printf 输出,printf("%s|%s|%s|\n", list[0].author, list[5].author, author); 应该输出 Dan Brown|Dan Brown|Dan Brown| - Giulio Franco
@GiulioFranco,它没有打印出Dan Brown|Dan Brown|Dan Brown|,而是在3行中打印出了Dan Brown。我认为fgets()在末尾留下了一个杂项\n - user2675010
1
@xmpirate 使用 strlen 检查每个字符串的长度。 - digital_revenant
1
@AlterMann - 不是 strstr()。我建议使用两种方法来验证每个字符串的输入(即 strlen()strstr()),这是解决 OP 遇到问题的一种方式。实际上,在处理字符串时,假设通常是危险的,双重检查总是一个好主意。 - ryyker
显示剩余6条评论
3个回答

2
fgets文档中可以看到:
当发现换行符、文件末尾或错误时,读取将停止。如果有换行符,则保留该字符。 这意味着fgets不会从读取的字符串末尾删除最后一个'\n'。 因此,您的字符串如下所示:
1. "Dan Brown" 2. "Dan Brown" 3. "Dan Brown\n"
它们不相等
在使用fgets时,这是一个非常常见的问题。这就是为什么我通常更喜欢使用scanf的原因,如下所示:
char buffer[BUF_LEN];
char format[16];
int scanf_result;

sprintf(format, "%%%u[^\n]", BUF_LEN);
//....
do
{
  //TODO: Ask for input
  scanf_result = scanf(format, buffer);
  switch (scanf_result)
  {
    case -1: //TODO: Print error message and exit
    case 0: //TODO: Print error mesage and break
  }
  //Discard remainings of buffered input line
  while (getchar() != '\n') {;}
} while (1); //Ugly, but plain

否则,你可以使用以下代码之类的 fgets
int buf_len;

//TODO: Ask for input
while (fgets(buffer, BUF_LEN, stdin) == NULL)
{
  //TODO: Check and handle error
}
buf_len = strlen(buffer);
//Remove trailing '\n', if present
if (buffer[buf_len - 1] == '\n')
{
  buffer[--buf_len] = '\0';
}

虽然第二种方法更简单,但我不喜欢它,因为strlen会再次扫描字符串以确定其长度。在大多数情况下,这不是性能问题,但我避免使用它是因为我有自己的思维问题。


1
将字符串末尾的字符设为空字符。 - digital_revenant
1
@Giulio Franco:+1,根据你提到的文档,换行符(如果有的话)会保留。不检查一下buffer[--buf_len] = '\0';这个是否真的是\n,难道不危险吗?我的意思是,它可能不是换行符。我总是检查它 - The Mask
strlen() 可能返回零:if (buffer[buf_len - 1] == '\n') -->> if (buff_len && buffer[buf_len - 1] == '\n') 较不重要的是:buff_len 应该是 size_t 类型,而不是 int。 - wildplasser
@wildplasser strlen 不会返回零,因为我知道缓冲区足够大,可以容纳一个字符和尾随的'\0',而且fgets会获取一行。所以,如果fgets成功,那么缓冲区至少包含"\n",因此buf_len至少为1。至于size_t,当我面对这些问题时,我几乎只了解intchar。我试图保持简单,因为用4条指令读取一行可能会造成创伤。 - Giulio Franco
@GiulioFranco:尝试读取一个包含NUL字符的二进制文件(测试时可以使用/dev/zero)。fgets将在第一个NUL字节处停止,如果该字节恰好是行首,则strlen()将报告零长度。此处缓冲区大小无关紧要。顺便问一下,while (fgets(buffer, BUF_LEN, stdin) == NULL)应该做什么,等待EOF消失吗? - wildplasser
显示剩余4条评论

1

您应该验证您的输入。有时需要使用多种方法。在这里,我使用了 strlen()strstr(),因为如果长度 ==,并且存在一个子字符串,则字符串 相等。因此,在得出结论之前,请尝试像这样验证输入字符串是否是您想要的:

注意:当然不需要枚举,但在此处包含以清晰地说明输出示例。

enum    {
    SAME,     //0
    NOT_SAME  //1
}

void delete(struct books *list,char author[],char name[],int n)
{
    int i,a, len1, len2;
    A = NOT_SAME;
    len1 = strlen(list[0].author);
    len2 = (list[5].author);
    if(strstr(list[0].author,list[5].author) && (len1==len2)) a = SAME;
    printf("%d\n",a);              


    a = NOT_SAME;
    len1 = strlen(list[0].author);
    len2 = (author);
    if(strstr(list[0].author,author) && (len1==len2)) a = SAME;
    printf("%d\n",a);              

}    

0

通过逐个打印字符来检查第二个字符串。

特别是author字符串。

for(i=0; i < strlen(list[0].author);i++)
{
   if(list[0].author[i]!=author[i])
   {
     printf("this is position is not matching\n",i+1);
     //try to print characters and also print ascii characters.
     break; 
   }

}
//or simply try to use strncpy() 

1
他想知道为什么 strcmp(list[0].author, author); 没有输出 0 - digital_revenant
1
@Kunal 这里给出的模糊答案是它们不相等,否则该代码将产生一个结果为0。 - user539810

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接