strcmp function not working properly

2019-07-05 05:07发布

问题:

I have a delete function on array of structures books. I'm passing it an array of records, author of book and name of book and size of the list.

Now here given that list[0].author and list[5].author and author all are equal to "Dan Brown" (same string)

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
}    

Why is it happening? What's wrong here?

回答1:

From the documentation of fgets:

Reading stops when a newline character is found, at end-of-file or error. The newline, if any, is retained.

This means that fgets will not remove the final '\n' from the end of the read string. Thus, your strings are:

  1. "Dan Brown"
  2. "Dan Brown"
  3. "Dan Brown\n"

They're not equal.

This is a very common issue when using fgets. That's why I usually prefer scanf, like this:

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

Otherwise, you can use fgets with something like this:

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';
}

Even though it's easier, I don't like this second method, because strlen scans the string another time to determine its length. In most cases, this is not a performance issue, I avoid it because I have my own mental issues.



回答2:

You should verify your inputs. Sometimes by more than one method is necessary. Here, I am using strlen(), and strstr(), because if the length is ==, and a substring exists, then the strings ARE equal. So, try something like this to verify the input strings are what you thing they are before making a conclusion:

Note: the enum is of course not necessary, but included here to add clarity to example of output.

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);              

}    


回答3:

check second strings by printing character by character.

Especially author string.

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()