Hey, fgets() is one of the good guys
You usually see it being recommended as the function to use instead of bad-boy gets(). To quote the linux gets() man(ual) entry:
Never use gets(). Because it is impossible to tell without knowing the data in advance how many characters gets() will read, and because gets() will continue to store characters past the end of the buffer, it is extremely dangerous to use. It has been used to break computer security. Use fgets() instead.
fegts() takes an argument telling it how big the buffer is where it will store the input, and it won't attempt to store more than will fit in the buffer. gets() has no such argument - given a big enough input it will happily write all over your memory for you.
The ! thing is a separate issue - fgets() returns a pointer pointing to where the input has been stored (which as you say is where you told fgets() to put it), or NULL on error/end of input. It is just the fact that it is a pointer that allows it to be used with !, because NULL is 0, and 0 is false (obviously
Interesting (I use the word loosely) note, just in case you hadn''t heard it before - the fact that number 0 is the NULL pointer in a pointer context *doesn't* necessarily mean that your computer's internal representation of NULL is the number 0