|
||||
|
« 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():
The characters in the input stream will have to be dealt with. See the fflush() discussion.
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.
|
GIDNetwork Sites
Archives
Recent GIDBlog Posts
Recent GIDForums Posts
Contact Us
|
« Command Line Arguments, Part 3 | Things to Avoid in C/C++ -- fflush(stdin), Part 2 » |