Fgets

From aldeid
Jump to navigation Jump to search

Syntax

char * fgets ( char * str, int num, FILE * stream );

Description

Get string from stream

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 the end-of-file is reached, whichever happens first.

A newline character makes fgets stop reading, but it is considered a valid character by the function and included in the string copied to str.

A terminating null character is automatically appended after the characters copied to str.

Notice that fgets is quite different from gets: not only fgets accepts a stream argument, but also allows to specify the maximum size of str and includes in the string any ending newline character.

Parameters

str
Pointer to an array of chars where the string read is copied.
num
Maximum number of characters to be copied into str (including the terminating null-character).
stream
Pointer to a FILE object that identifies an input stream.
stdin can be used as argument to read from the standard input.

Return Value

On success, the function returns str.

If the end-of-file is encountered while attempting to read a character, the eof indicator is set (feof). If this happens before any characters could be read, the pointer returned is a null pointer (and the contents of str remain unchanged).

If a read error occurs, the error indicator (ferror) is set and a null pointer is also returned (but the contents pointed by str may have changed).

Examples

Max length reached before end of line

Source Run
#include <stdio.h>

int main(int argc, char *argv[])
{

  FILE *pFile = NULL;
  pFile = fopen("pets", "r");
  char str[20] = "";

  if (pFile==NULL) perror("Error opening file\n");
  else {
    fgets(str, 16, pFile);
    printf("%s\n", str);
    fclose(pFile);
  }

  return 0;
}
$ cat pets
You have 3 pets and prefer cats.
$ ./code
You have 3 pets

End of line reached before max length

Source Run
#include <stdio.h>
#define MAX_LEN 1000

int main(int argc, char *argv[])
{

  FILE *pFile = NULL;
  pFile = fopen("multiline", "r");
  char str[MAX_LEN] = "";

  if (pFile==NULL) perror("Error opening file\n");
  else {
    while (fgets(str, MAX_LEN, pFile)) {
      printf("%s", str);
    }
    fclose(pFile);
  }

  return 0;
}
$ cat multiline
This is line 1. Four remaining lines.
This is line 2. Three remaining lines.
This is line 3. Two remaining lines.
This is line 4. One remaining line.
This is line 5. No remaining line.
$ ./code
This is line 1. Four remaining lines.
This is line 2. Three remaining lines.
This is line 3. Two remaining lines.
This is line 4. One remaining line.
This is line 5. No remaining line.

stdin

Let's consider the following code:

#include <stdio.h>

int main(int argc, char *argv[])
{
  char firstname[10] = "";
  char lastname[10] = "";

  printf("First name? ");
  fgets(firstname, 10, stdin);
  printf("Last name? ");
  fgets(lastname, 10, stdin);

  printf("Hello %s %s", firstname, lastname);
 
  return 0;
}

When run, the program is asking for both the first name and last name. However, when concatenated, we notice a carriage return between the first name and the last name:

$ ./code 
First name? Alice 
Last name? Shaw
Hello Alice
 Shaw

The reason is that the ENTER key has been saved in the buffer when the first name has been provided. A solution is to purge the buffer as follows:

#include <stdio.h>
#include <string.h>

void purgeBuffer();
int getString(char *str, int len);

int main(int argc, char *argv[])
{
  char firstname[10] = "";
  char lastname[10] = "";

  printf("First name? ");
  getString(firstname, 10);
  printf("Last name? ");
  getString(lastname, 10);

  printf("Hello %s %s\n", firstname, lastname);
 
  return 0;
}

void purgeBuffer()
{
  int c = 0;
  while(c!='\n' && c!=EOF)
    c = getchar();
}

int getString(char *str, int len)
{
  char *enter = NULL;
  if (fgets(str, len, stdin)!=NULL) {
    enter = strchr(str, '\n');
    if (enter!=NULL) *enter = '\0';
    else purgeBuffer();
    return 0;
  } else {
    purgeBuffer();
    return 1;
  }
}

Now, it looks better:

$ ./code 
First name? Alice
Last name? Shaw
Hello Alice Shaw