strcmp on a line read with fgets

2019-01-01 14:06发布

问题:

I\'m trying to compare two strings. One stored in a file, the other retrieved from the user (stdin).

Here is a sample program:

int main()
{
    char targetName[50];
    fgets(targetName,50,stdin);

    char aName[] = \"bob\";
    printf(\"%d\",strcmp(aName,targetName));

    return 0;
}

In this program, strcmp returns a value of -1 when the input is \"bob\". Why is this? I thought they should be equal. How can I get it so that they are?

回答1:

strcmp is one of the few functions that has the reverse results of true and false...if the strings are equal, the result is 0, not 1 as you would think....

if (strcmp(a, b)) {
    /* Do something here as the strings are not equal */
} else {
    /* Strings are equal */
}

Speaking of fgets, there is a likelihood that there is a newline attached to the end of the string...you need to get rid of it...

+-+-+-+--+--+
|b|o|b|\\n|\\0|
+-+-+-+--+--+

To get rid of the newline do this. CAVEATS: Do not use \"strlen(aName) - 1\", because a line returned by fgets may start with the NUL character - thus the index into the buffer becomes -1:

aName[strcspn(aName, \"\\n\")] = \'\\0\';

+-+-+-+--+
|b|o|b|\\0|
+-+-+-+--+

Now, strcmp should return 0...



回答2:

fgets reads until it sees a newline then returns, so when you type bob, in the console, targetName contains \"bob\\n\" which doesn\'t match \"bob\". From the fgets documenation: (bolding added)

Reads characters from stream and stores them as a C string into str until (num-1) characters have been read or either a newline or a the End-of-File is reached, whichever comes first. A newline character makes fgets stop reading, but it is considered a valid character and therefore it is included in the string copied to str. A null character is automatically appended in str after the characters read to signal the end of the C string.

You need to remove the newline from the end of targetName before you compare.

int cch = strlen(targetName);
if (cch > 1 && targetName[cch-1] == \'\\n\')
   targetName[cch-1] = \'\\0\';

or add the newline to your test string.

char targetName[50];
fgets(targetName,50,stdin);

char aName[] = \"bob\\n\";
printf(\"%d\",strcmp(aName,targetName));


回答3:

Because fgets is embededing the newline character into the variable targetName. This is throwing off the comparison.



回答4:

The fgets is appending a \\n to the string that you are pulling in from the user when they hit Enter. You can get around this by using strcspn or just adding \\n onto the end of your string you\'re trying to compare.

printf(\"Please enter put FILE_NAME (foo1, 2, or 3), ls, or exit: \\n\");
fgets(temp, 8, stdin);
temp[strcspn(temp, \"\\n\")] = \'\\0\';
if(strcmp(temp, \"ls\") == 0 || strcmp(temp, \"exit\") == 0)

This just replaces the \\n with a \\0, but if you want to be lazy you can just do this:

printf(\"Please enter put FILE_NAME (foo1, 2, or 3), ls, or exit: \\n\");
fgets(temp, 8, stdin);
if(strcmp(temp, \"ls\\n\") == 0 || strcmp(temp, \"exit\\n\") == 0)

But it\'s not as elegant.



回答5:

fgets appends the newline to the string, so you\'ll end up with bob\\n\\0 which isn\'t the same as bob\\0.



回答6:

Mostly because of the end of line char in the input \"\\n\" under unix like system.