C - scanf() vs gets() vs fgets()?

Yes, you want to avoid gets . Fgets will always read the new-line if the buffer was big enough to hold it (which lets you know when the buffer was too small and there's more of the line waiting to be read). If you want something like fgets that won't read the new-line (losing that indication of a too-small buffer) you can use fscanf with a scan-set conversion like: "%N^\n" where the 'N' is replaced by the buffer size - 1.

Up vote 1 down vote favorite 2 share g+ share fb share tw.

So I've been doing a fairly easy program of converting a string of Characters (assuming numbers are entered) to an Integer. After I was done, I noticed some very peculiar "bugs" that I can't answer. Mostly because of my limited knowledge on how these 3 functions in Thread title works (I did read a lot of literature though).

So without writing too much text, here's the code of the program: #include #define MAX 100 int CharToInt(const char *); int main() { char strMAX; printf(" Enter some numbers (no spaces): "); gets(str); // fgets(str, sizeof(str), stdin); // scanf("%s", str); printf(" Entered number is: %d\n", CharToInt(str)); return 0; } int CharToInt(const char *s) { int i, result, temp; result = 0; I = 0; while(*(s+i)! = '\0') { temp = *(s+i) & 15; result = (temp + result) * 10; i++; } return result / 10; } So here's the problem I've been having. First, when using gets() function, the program works perfectly.

Second, when using fgets(), the result is slightly wrong because apparently fgets() function reads New Line (ASCII value 10) character last which screws up a result. Third, when using scanf() function, the result is completely wrong because first character apparently has a -52 ASCII value. For this, I have no explanation.

Now I know that gets() is discouraged to use, so I would like to know if I can use fgets() here so it doesn't read (or ignores) New Line character. Also, what's the deal with scanf() function in this program? Thank you.

C link|improve this question asked Jul 21 '10 at 17:54Marko112.

You may wan to replace your CharToInt() function with a call to atoi() (they do the same thing). Also, the char datatype is implicitly signed, which may explain the "-52 ASCII value" you were seeing. Cplusplus.com/reference/clibrary/cstdlib/atoi – sigint Jul 21 '10 at 18:07 Yes, I could use atoi(), but the very point of this program was to use Bitwise Operators.

Also, thank you very much for reminding me about signed value of char. Using unsigned char solved the problem, even though I'm still unsure how and why. – Marko Jul 21 '10 at 18:18 @sigint: In C, char can be signed char or unsigned char at the discretion of the compiler.

– ninjalj Jul 21 '10 at 18:26 I figured you probably had to write-your-own. As for why unsigned char(s) are solving your problem; A normal (signed) char has a value range of –128 to 127, whereas an unsigned char has a range of 0 to 255. The bit-twiddling was probably doing weird things with the negative values.

– sigint Jul 21 '10 at 18:28 By the way, *(s+i) is usually written in C as si (it has exactly the same semantics). – caf Jul 21 '107 at 0:12.

Yes, you want to avoid gets. Fgets will always read the new-line if the buffer was big enough to hold it (which lets you know when the buffer was too small and there's more of the line waiting to be read). If you want something like fgets that won't read the new-line (losing that indication of a too-small buffer) you can use fscanf with a scan-set conversion like: "%N^\n", where the 'N' is replaced by the buffer size - 1.

One easy (if strange) way to remove the trailing new-line from a buffer after reading with fgets is: strtok(buffer, "\n"); This isn't how strtok is intended to be used, but I've used it this way more often than in the intended fashion (which I generally avoid).

You're correct that you should never use gets. If you want to use fgets, you can simply overwrite the newline. Char *result = fgets(str, sizeof(str), stdin); if(result!

= NULL) { strstrlen(str) - 1 = '\0'; } else { // handle error } This does assume there are no embedded NULs. Another option is POSIX getline: char *line = NULL; size_t len = 0; ssize_t count = getline(&line, &len, stdin); if(count >= 1) { linecount - 1 = '\0'; } else { // Handle error } The advantage to getline is it does allocation and reallocation for you, it handles embedded NUL, and it returns the count so you don't have to waste time with strlen. Note that you can't use an array with getline.

The pointer must be NUL or free-able. I'm not sure what issue you're having with scanf.

Never use gets(), it can lead to unprdictable overflows. If your string array is of size 1000 and I enter 1001 characters, I can buffer overflow your program.

Thank you all for your answers. They were very much helpful. But I'd also like to know why scanf() doesn't work in this program?

Thank you. – Marko Jul 21 '10 at 18:13.

Never use gets. It offers no protections against a buffer overflow vulnerability (that is, you cannot tell it how big the buffer you pass to it is, so it cannot prevent a user from entering a line larger than the buffer and clobbering memory). Avoid using scanf.

If not used carefully, it can have the same buffer overflow problems as gets. Even ignoring that, it has other problems that make it hard to use correctly. Generally you should use fgets instead, although it's sometimes inconvenient (you have to strip the newline, you must determine a buffer size ahead of time, and then you must figure out what to do with lines that are too long–do you keep the part you read and discard the excess, discard the whole thing, dynamically grow the buffer and try again, etc.).

There are some non-standard functions available that do this dynamic allocation for you (e.g. Getline on Linux, Chuck Falconer's public domain ggets function). Note that ggets has gets-like semantics in that it strips a trailing newline for you.

As I said in my answer, getline is now standard. – Matthew Flaschen Jul 21 '10 at 19:04 @Matthew Flaschen: Which standard? When I say "non-standard", I mean "non-standard C", not non-POSIX.

– jamesdlin Jul 21 '10 at 19:14.

Try using fgets() with this modified version of your CharToInt(): int CharToInt(const char *s) { int i, result, temp; result = 0; I = 0; while(*(s+i)! = '\0') { if (isdigit(*(s+i))) { temp = *(s+i) & 15; result = (temp + result) * 10; } i++; } return result / 10; } It essentially validates the input digits and ignores anything else. This is very crude so modify it and salt to taste.

To clean things up, consider replacing strchr() with isdigit(). Even better, replace the entire CharToInt() function with a call to atoi(). Cplusplus.com/reference/clibrary/cctype/isdigit cplusplus.com/reference/clibrary/cstdlib... – sigint Jul 21 '10 at 18:14 isdigit() is a great suggestion... done.

– Amardeep Jul 21 '10 at 18:21.

I cant really gove you an answer,but what I can give you is a way to a solution, that is you have to find the anglde that you relate to or peaks your interest. A good paper is one that people get drawn into because it reaches them ln some way.As for me WW11 to me, I think of the holocaust and the effect it had on the survivors, their families and those who stood by and did nothing until it was too late.

Related Questions