GIDNetwork > Things to Avoid in C/C++ -- gets() , Part 1
Register
« Command Line Arguments, Part 3 Things to Avoid in C/C++ -- fflush(stdin), Part 2 »

Things to Avoid in C/C++ -- gets() , Part 1

by: WaltP - Sep 14, 2005

C/C++ programmers are allowed to do some things they shouldn't. We are given functions that are supposed to be useful but aren't because of hidden faults, or taught ways to do things that are bad, wrong, not necessary. These posts will discuss many of these as time goes on.

The code in this collection of electronic bits is specifically written in C. I'm using the free Borland 5.5 compiler for the code. For any code that is designed to show the errors, your results may be a little different. But rest assured, the problem exists in many if not all compilers. And if most compilers show these anomalies, wouldn't you rather not use the feature even if it works on your current compiler?

Most of these functions from C exist as methods in C++. Not being a guru in C++, if anyone would like to contact me with the C++ equivalent, I will add the information to these posts.

Enjoy, and clean up your code! :wink:

gets()

You should never use gets(). Never. Never. Never. I hope I am being clear. NEVER!!

gets() is a function that misbehaves badly. It has no internal checks which means it will read anything you give it. Define a 10 character buffer and gets() will happily accept the Declaration of Independance as its input.

Here's an example. Create and build this program:

C/CPP/C++ Code Example:

#include <stdio.h>

int main()
{
    char  b1[] = "ABCD";
    char  b2[] = "LMNO";
    char  b3[] = "ZYXW";
    
    puts(b1);
    puts(b2);
    puts(b3);
    putchar('\n');
    
    puts("Enter some characters:");
    gets(b2);

    putchar('\n');
    puts(b1);
    puts(b2);
    puts(b3);
    
    return(0);
}

You will notice there are 3 character arrays of 5 characters each (don't forget about the '\0' at the end of each).

Now run the program and enter "1234" when prompted. My output:

Generic Code Example:

D:\C\GIDForums>gets
ABCDE
LMNOP
ZYXWV

Enter some characters:
1234

ABCDE
1234
ZYXWV

D:\C\GIDForums>

So far so good. Now run it again and enter all the numbers:

Generic Code Example:

D:\wjp\C\GIDForums>gets
ABCDE
LMNOP
ZYXWV

Enter some characters:
1234567890

90
1234567890
ZYXWV

D:\wjp\C\GIDForums>

Whoa! What happened to b1?!? Well, gets() just happily accepted what you typed in and put it into memory starting at b2 and didn't give one hoot about anything but reading the characters. gets() overwrote memory it shouldn't have.

Keep in mind your results may be a little different, but the concept is the same. This function is dangerous!!!. Play around with this program. Some of you will find it crashes. Some will find it will accept a *lot* of characters. Who knows what it's doing with your memory, what it's writing over?

Avoid gets() like it's the bubonic plague with a rickets chaser.

fgets()

Instead, use fgets():

C/CPP/C++ Code Example:

fgets(buffer, BufLength, stdin);

So in our program, use:

C/CPP/C++ Code Example:

puts("Enter some characters:");
fgets(b2, 5, stdin);  // 5 is the size of buffer b2

Not much harder, but much safer. fgets() will read up to BufLength-1 characters and stop. It will also stop if it reads a new-line '\n' which it unfortunately will place in the buffer. So there are 2 possible outcomes using fgets():

Outcome #1
You've entered exactly or more characters than the buffer holds.

  1. your buffer contains BufLength-1 characters

  2. the input stream still contains the rest and will be read on the next fgets().

The characters in the input stream will have to be dealt with. See the fflush() discussion.

Outcome #2
You've entered fewer characters than the buffer holds.

  1. your buffer contains BufLength-1 characters, including the '\n' at the end.

  2. the input stream is empty.

The input stream is clean so you have no I/O problems. But that '\n' may have to be dealt with. To remove it, include string.h in your file and add a line:

C/CPP/C++ Code Example:

puts("Enter some characters:");
fgets(b2, 5, stdin);  // 5 is the size of buffer b2
if (b2[strlen(b2)-1] == '\n') b2[strlen(b2)-1] = '\0';

This if statement will test the last character (b2[strlen(b2)-1]) for the new-line and change it to a null.

To deal with both options at once to either remove the trailing '\n' or clear the buffer, whichever situation exists, define a dummy buffer of say 50 characters (you choose the size) and use this code:

C/CPP/C++ Code Example:

puts("Enter some characters:");
fgets(b2, 5, stdin);  // 5 is the size of buffer b2
if (b2[strlen(b2)-1] == '\n') 
{   // full input line read
    b2[strlen(b2)-1] = '\0';  // remove the new-line
}
else
{   // parial input line read
    b2[0] = 0;  // empty the b2 buffer
    do
    {   // loop until the new-line is read
        fgets(dummy, 50, stdin);
        strcat(b2, dummy);  // Save input but be sure
                            // sure to test your buffer size
    } while (dummy[strlen(dummy)-1] != '\n');
}

OK, so it's not that easy. But it's better than having a program that will explode, isn't it? Anyway, just copy the code above and you'll be fine.

Would you like to comment? This story has been viewed 161,061 times.
« Command Line Arguments, Part 3 Things to Avoid in C/C++ -- fflush(stdin), Part 2 »

__top__

Copyright © GIDNetwork™ 2001 - 2024

Another website by J de Silva

Page generated in : 0.00780 sec.