1. Summary
  2. Files
  3. Support
  4. Report Spam
  5. Create account
  6. Log in

Gets

From cpwiki

Jump to: navigation, search

What is gets()?

#include <stdio.h>
char *gets(char *s);

The gets function reads characters from the input stream pointed to by stdin, into the array pointed to by s, until end-of-file is encountered or a new-line character is read. Any new-line character is discarded, and a null character is written immediately after the last character read into the array.

The gets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned. (C Standard (ISO/IEC 9899:1999), Section 7.19.7.7)

What is wrong with gets()?

gets() has no way of determining how large the array pointed to by s is. As such, if the size of the user input is larger than the array, there will be a buffer overrun as gets() writes past the end of the array.

The reason why gets() cannot determine the size of the array is that when an array is passed to a function, it decays to a pointer. With only a pointer, one cannot tell how large the original array was. For example, sizeof(s) would return the size of the pointer, not the array pointed to by s. Therefore, gets() has to assume that the array is infinitely large, but no array is infinitely large. Consequently, no matter how large is the buffer (i.e., the array pointed to by s), there is the potential for a buffer overrun.

(Some people point out that certain terminals only let you type a certain number of characters -- 512, say, or 256. But the program might be run with different terminals, and besides, the user can always redirect a file as input to the program, and that file could contain lines of any size.)

A buffer overrun can be quite serious. It involves data being written beyond the end of an array, overwriting whatever data happened to be residing in that particular point in memory. This can be virtually anything, from other variables in the program to the program's code to vital data for the operating system.

Most modern operating systems will prevent buffer overruns from getting too far out of control, but any buffer overrun can still represent a security risk in the code. Buffer overruns should be avoided at all costs.

For more information, see buffer overruns.

What alternatives are there to gets()?

The most commonly suggested alternative to gets() is fgets().

#include <stdio.h>
char *fgets(char * restrict s, int n, FILE * restrict stream);

The fgets function reads at most one less than the number of characters specified by n from the stream pointed to by stream into the array pointed to by s. No additional characters are read after a new-line character (which is retained) or after end-of-file. A null character is written immediately after the last character read into the array.

The fgets function returns s if successful. If end-of-file is encountered and no characters have been read into the array, the contents of the array remain unchanged and a null pointer is returned. If a read error occurs during the operation, the array contents are indeterminate and a null pointer is returned. (C Standard (ISO/IEC 9899:1999), Section 7.19.7.2)

The only caveat with fgets() is that it does not remove the (possible) newline from the end of the buffer like gets() does. This is easily remedied, however, in several different ways. As an example:

#include <stdio.h>  /* for fgets() */
#include <string.h>  /* for strchr() */

char buffer[256], *p;
fgets(buffer, sizeof buffer, stdin);

/* strip the newline, if any, from buffer */
p = strchr(buffer, '\n');
if(p) *p = '\0';

That last strchr() method is but one of dozens for removing the newline. Here are some others.

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

At any rate, one can use something like this to replace gets().

#include <string.h>

char * safegets(char * buffer, size_t count)
{
    char * result = buffer;
    char * tail;
    if(buffer == NULL || count <= 0) 
        result = NULL;
    else if(count == 1)
        *result = '\0';
    else if(fgets(buffer, count, stdin) != NULL) {
        if( (tail = strchr(buffer, '\n')) != NULL)
            *tail = '\0';
    }
    return result;
}

Note the return value of fgets() is checked. If fgets() returns NULL, it failed to read any input from stdin. This usually only happens if the user types End-Of-File, CTRL-Z on DOS and CTRL-D on UNIX, or the input was a file and the end of that file has been reached. Usually this can be ignored, but this function returns NULL if fgets() failed, just in case the caller wants to check it.

As a side note, size_t is the proper type for the lengths of strings.

Use fgets(), not gets().

Personal tools