Usage of fgets function in C

2019-01-26 15:35发布

问题:

One of my assignments in to write my own UNIX Shell. To receive input from the user, I am using fgets to capture the input as a string but I'm not really sure how it works. When I run:

char command[50];
fgets(command, sizeof(command), stdin);

printf("Your Command: %s", &command);
int length = strlen(command);
printf("Length of String: %d\n", length);

Lets say my the input was "exit". strlen says that the string is 5 characters long, instead of four. I want to do this:

if( (strcmp(command, "exit")) == 0 ){
    doSomething();
}

but command is never equaling the string that I want it to; its like it has an unknown character that Im not sure of. Is it the null character at the end? How do I change the if statement to check that the user input caught with fgets equals "exit"? Thanks!

回答1:

fgets considers the line terminator as a valid character. That's the extra character you are receiving.

Just do something like command[strlen(command) - 1] = '\0'; to remove the line terminator. Then you are free to do all your strcmp's.



回答2:

From the fgets manual page:

fgets() reads in at most one less than size characters from stream and stores them into the buffer pointed to by s. Reading stops after an EOF or a newline. If a newline is read, it is stored into the buffer. A '\0' is stored after the last character in the buffer.

Bottom-line: you have an extra newline at the end of your string when comparing.



回答3:

fgets will always include the line termination character in the input string. You can remove any space, including the newline characters, from the end of your "command" by doing:

char command[50];
fgets(command, sizeof(command), stdin);

size_t length = strlen(command);
// Trim off trailing "spaces" including newline characters
while ((length > 0) && isspace(command[length-1]))
      command[--length] = '\0';

printf("Your Command: %s\n", &command); // Include newline now...
// This is computed above...
// int length = strlen(command);

// Continue as before


回答4:

fgets is capturing the line break, too.

Note that you can overcome this in a few ways, one might be using strncmp:

if((strncmp(command, "exit", 4)) == 0)

which checks if only the first 4 characters of command match (though this might not be the right option for you here).

Another tactic is to check with the line break in place:

if((strcmp(command, "exit\n")) == 0)


回答5:

Probably the easiest way to handle this is to switch to using scanf to read the input:

char command[51];

scanf("%50[^\n]", command);

if (0 == strcmp(command, "exit"))
    do_something();


回答6:

Your string still has the newline at the end. You could compare with "exit\n" or use something like strncmp(command, "exit", 4). Note that that would accept anything that started with "exit" and ignore the rest.



回答7:

As noted, fgets(3) gives you the trailing '\n'. If you use gets(3), you don't gets the trailing newline. Nothing like consistency, sez I.

Perl has a hand chomp() function that trims the trailing newline if its present — you could do worse than to roll your own:

#define NUL ((char)0)
void chomp( char *s )
{
  if ( s != null )
  {
    int len = strlen(s) ;
    if ( len >= 1 && s[len-1] == "\n" )
    {
      s[len-1] = NUL ;
    }
  }
  return ;
}