Bài sưu tầm từ WaltP
Lưu ý: vì sự khác biệt ngôn ngữ và cách hành văn nên mình sẽ không dịch bài này và để các bạn tự dịch để nắm nội dung sâu sắc và sát hơn với ý của tác giả
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!
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.
your buffer contains BufLength-1 characters
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.
your buffer contains BufLength-1
characters, including the '\n' at the end.
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.