473,397 Members | 2,056 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

Proper use of scanf


Hello,

I am aware that a lot of people are wary of using scanf,
because doing it improperly can be dangerous. I have
tried to find a good tutorial on all the ins and outs
of scanf() but been unsuccessful.

Is there a well-respected (by the c.l.c crowd) book
or tutorial that really covers scanf in detail?
Nov 14 '05 #1
17 3464
Lefty Bigfoot wrote:

Hello,

I am aware that a lot of people are wary of using scanf,
because doing it improperly can be dangerous. I have
tried to find a good tutorial on all the ins and outs
of scanf() but been unsuccessful.

Is there a well-respected (by the c.l.c crowd) book
or tutorial that really covers scanf in detail?


I don't know of one.
Here's two examples of one way to use scanf safely.
If you enter more than LENGTH characters,
the extra ones will be automatically discarded.
If you have questions, I can try to explain.
The whole topic of scanf is somewhat lengthy.

/* BEGIN anystring.c */

#include <stdio.h>

#define LENGTH 20
#define str(x) #x
#define xstr(x) str(x)

int main(void)
{
char string[LENGTH + 1];
int rc;

printf("Enter any string or enter an empty string to quit: ");
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", string);
if (!feof(stdin)) {
getchar();
}
while (rc == 1) {
printf("Your string was %s\n", string);
printf("scanf() returned %d\n", rc);
printf("Enter any string or enter an empty string to quit: ");
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", string);
if (!feof(stdin)) {
getchar();
}
}
printf("scanf() returned %d\n", rc);
return 0;
}

/* END anystring.c */
/* BEGIN grade.c */

#include <stdlib.h>
#include <stdio.h>

#define LENGTH 3
#define str(x) # x
#define xstr(x) str(x)

int main(void)
{
int rc;
char array[LENGTH + 1];
long number;
const char letter[4] = "DCBA";

fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getchar();
}
while (rc == 1) {
number = strtol(array, NULL, 10);
if (number > 60) {
if (number > 99) {
number = 99;
}
array[0] = letter[(number - 60) / 10];
switch (number % 10) {
case 0:
case 1:
array[1] = '-';
array[2] = '\0';
break;
case 8:
case 9:
array[1] = '+';
array[2] = '\0';
break;
default:
array[1] = '\0';
break;
}
} else {
array[0] = 'F';
array[1] = '\0';
}
printf("The Letter grade is: %s\n", array);
fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = scanf("%" xstr(LENGTH) "[^\n]%*[^\n]", array);
if (!feof(stdin)) {
getchar();
}
}
return 0;
}

/* END grade.c */
--
pete
Nov 14 '05 #2

Le 19/06/2005 00:54, dans no**************************@news.verizon.net,
«*Lefty Bigfoot*» <no****@awol.info> a écrit*:

Hello,

I am aware that a lot of people are wary of using scanf,
because doing it improperly can be dangerous. I have
tried to find a good tutorial on all the ins and outs
of scanf() but been unsuccessful.

Is there a well-respected (by the c.l.c crowd) book
or tutorial that really covers scanf in detail?


Yes, the ISO 9899-1999 Standard, section 7.19.6.4.
I can swear it's well respected here :-)

There is also the POSIX standard, at
http://www.opengroup.org/onlinepubs/000095399/
certainly well respected too.

If you want a tutorial, maybe the K&R C book will help you.

If you have UNIX or Linux, try "man scanf"

Nov 14 '05 #3
Lefty Bigfoot wrote:

I am aware that a lot of people are wary of using scanf,
because doing it improperly can be dangerous. I have
tried to find a good tutorial on all the ins and outs
of scanf() but been unsuccessful.

Is there a well-respected (by the c.l.c crowd) book
or tutorial that really covers scanf in detail?


Take a look at the links in my sig. Especially the one marked
C-library, and then the C99 one.

--
Some useful references about C:
<http://www.ungerhu.com/jxh/clc.welcome.txt>
<http://www.eskimo.com/~scs/C-faq/top.html>
<http://benpfaff.org/writings/clc/off-topic.html>
<http://anubis.dkuug.dk/jtc1/sc22/wg14/www/docs/n869/> (C99)
<http://www.dinkumware.com/refxc.html> (C-library}
<http://gcc.gnu.org/onlinedocs/> (GNU docs)

Nov 14 '05 #4
There seems to be some problem with the way I am using scanf() in my
code. Could please help me out?

/*Sample Program*/

#include<stdio.h>

int main()
{
double D;

scanf("%g", &D);
printf("%g", D);

return 0;
}

/*During Execution*/
1232 /*Input*/

5.68642e-315/*Output*/

/*End*/

If it helps, I am using the gcc compiler(ver 3.4.3) that I got with
DJGPP and I am using it on Win98.

Nov 14 '05 #5
Hello,

I just found a post from a person having the same problem. How cool is
that! The one mistake I found out is that '%g' in the scanf should be
'%lg'. Anyother nit picking will be welcomed.

Nov 14 '05 #6
Vivek wrote:
There seems to be some problem with the way I am using scanf() in my
code. Could please help me out?

/*Sample Program*/
#include<stdio.h>
int main()
{
double D;
scanf("%g", &D);
printf("%g", D);
return 0;
}

/*During Execution*/
1232 /*Input*/
5.68642e-315/*Output*/

#include<stdio.h>

int main(void)
{
double D;
char input[] = "1234";

printf("Using the OP's incorrect specifier for\n"
"reading the string \"%s\" as a double:", input);
sscanf(input, "%g", &D);
printf("%g\n", D);

printf("Using the correct specifier for\n"
"reading the string \"%s\" as a double:", input);
sscanf(input, "%lg", &D);
printf("%g\n", D);

return 0;
}

[output]
Using the OP's incorrect specifier for
reading the string "1234" as a double:2.88675e-13
Using the correct specifier for
reading the string "1234" as a double:1234
If it helps, I am using the gcc compiler(ver 3.4.3) that I got with
DJGPP and I am using it on Win98.


If you had turned on the warnings during compilation, gcc would have
told you the specifier was wrong. Not all compilers are so obliging.
Keep those warning levels up, and don't ignore the diagnostics.

Nov 14 '05 #7
Vivek wrote:
There seems to be some problem with the way I am using scanf() in my
code. Could please help me out?
[...]
double D;
scanf("%g", &D);
[...]

If it helps, I am using the gcc compiler(ver 3.4.3) that I got with
DJGPP and I am using it on Win98.


The compiler you're using happens to be able to
catch this error for you, if you ask it nicely. Use
the command-line flags "-Wall -W"; for code that's
intended to be portable use "-Wall -W -ansi -pedantic".
(There are alternatives to "-ansi"; see the info pages.)

--
Eric Sosman
es*****@acm-dot-org.invalid
Nov 14 '05 #8
Eric Sosman wrote:
Vivek wrote:
There seems to be some problem with the way I am using scanf()
in my code. Could please help me out?
[...]
double D;
scanf("%g", &D);
[...]

If it helps, I am using the gcc compiler(ver 3.4.3) that I got
with DJGPP and I am using it on Win98.


The compiler you're using happens to be able to
catch this error for you, if you ask it nicely. Use
the command-line flags "-Wall -W"; for code that's
intended to be portable use "-Wall -W -ansi -pedantic".
(There are alternatives to "-ansi"; see the info pages.)


This is one more of a long list of anomalies in scanf, and adds to
the list of reasons not to use it. Unfortunately the C library
lacks good routines to input from streams (rather than buffers). I
have written and published some suitable routines in the past.

To the OP - look up the modifier l (small ell) in the scanf
documentation. Read it with great care. Then don't use it, get
complete lines and work on those.

--
Some informative links:
news:news.announce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
Nov 14 '05 #9
On Sun, 19 Jun 2005 02:08:52 +0200, Jean-Claude Arbaut
<je****************@laposte.net> wrote in comp.lang.c:

Le 19/06/2005 00:54, dans no**************************@news.verizon.net,
«*Lefty Bigfoot*» <no****@awol.info> a écrit*:

Hello,

I am aware that a lot of people are wary of using scanf,
because doing it improperly can be dangerous. I have
tried to find a good tutorial on all the ins and outs
of scanf() but been unsuccessful.

Is there a well-respected (by the c.l.c crowd) book
or tutorial that really covers scanf in detail?
Yes, the ISO 9899-1999 Standard, section 7.19.6.4.
I can swear it's well respected here :-)


That's actually not a reference to how to use the function safely, nor
even a recommendation that it should be used.

See 7.19.7.7, which describes the gets() function, and includes not so
much as a hint of a warning about buffer overflows.
There is also the POSIX standard, at
http://www.opengroup.org/onlinepubs/000095399/
certainly well respected too.

If you want a tutorial, maybe the K&R C book will help you.

If you have UNIX or Linux, try "man scanf"


The general consensus here, which I agree with, is that the *scanf()
functions are best avoided by all except extreme experts on their use.
If non-experts avoid them, the will never become extreme experts,
making the point moot.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #10

On 20/06/2005 05:19, Jack Klein wrote:
On Sun, 19 Jun 2005 02:08:52 +0200, Jean-Claude Arbaut
<je****************@laposte.net> wrote in comp.lang.c:
That's actually not a reference to how to use the function safely, nor
even a recommendation that it should be used.

See 7.19.7.7, which describes the gets() function, and includes not so
much as a hint of a warning about buffer overflows.


Oopss :-)

The general consensus here, which I agree with, is that the *scanf()
functions are best avoided by all except extreme experts on their use.
If non-experts avoid them, the will never become extreme experts,
making the point moot.


Anyway it's certainly good practice not to use a function when one has
doubts on its use. Concerning scanf, it's rarely useful, because of its
strange behaviour, at least on some implementations (if I remember well, you
may enter an infinite loop if you enter wrong data when an integer is
expected, not merely because of scanf, because of the program that uses it).
I mainly use it in toy programs.

Nov 14 '05 #11
Jack Klein wrote:
[...]
The general consensus here, which I agree with, is that the *scanf()
functions are best avoided by all except extreme experts on their use.
If non-experts avoid them, the will never become extreme experts,
making the point moot.


I'd agree that scanf() and fscanf() are best avoided,
but sscanf() is both usable and useful. fgets()/sscanf()
make a good combination.

--
Eric Sosman
es*****@acm-dot-org.invalid
Nov 14 '05 #12
Lefty Bigfoot wrote:
Hello,

I am aware that a lot of people are wary of using scanf,
because doing it improperly can be dangerous. I have
tried to find a good tutorial on all the ins and outs
of scanf() but been unsuccessful.

Is there a well-respected (by the c.l.c crowd) book
or tutorial that really covers scanf in detail?


There is also a useful reference in the documentation of the GNU
standard C library

http://www.gnu.org/software/libc/man...ut%20Functions

This also mentions many GNU extensions though.

Nov 14 '05 #13
Eric Sosman <es*****@acm-dot-org.invalid> writes:
I'd agree that scanf() and fscanf() are best avoided,
but sscanf() is both usable and useful.


Only if one doesn't mind the nasal demons that are emitted when a
conversion's value cannot be represented in the object it is
stored into, e.g. when an out-of-range number is read.
--
"The expression isn't unclear *at all* and only an expert could actually
have doubts about it"
--Dan Pop
Nov 14 '05 #14


Ben Pfaff wrote:
Eric Sosman <es*****@acm-dot-org.invalid> writes:

I'd agree that scanf() and fscanf() are best avoided,
but sscanf() is both usable and useful.

Only if one doesn't mind the nasal demons that are emitted when a
conversion's value cannot be represented in the object it is
stored into, e.g. when an out-of-range number is read.


Hmmm ... I'd always assumed that'd be a "matching
failure," but no: trying to derive an eight-bit `char'
value from "666" is, indeed, U.B. You learn something
new every day.

--
Er*********@sun.com

Nov 14 '05 #15
On Mon, 20 Jun 2005 07:39:46 -0400, Eric Sosman
<es*****@acm-dot-org.invalid> wrote in comp.lang.c:
Jack Klein wrote:
[...]
The general consensus here, which I agree with, is that the *scanf()
functions are best avoided by all except extreme experts on their use.
If non-experts avoid them, the will never become extreme experts,
making the point moot.


I'd agree that scanf() and fscanf() are best avoided,
but sscanf() is both usable and useful. fgets()/sscanf()
make a good combination.


As Ben already pointed out, all the members of *scanf() produce
undefined behavior if the result of a numeric conversion is out of
range for the destination type.

Which means to use them safely, you need to pre-check the numeric
digits before converting. If you are going to check them by hand, you
might as well do the conversion yourself, it takes little additional
effort.

Now fgets() and { strol(), strtod(), strtoul(), strtoll(), stroull() }
make a robust combination.

--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
comp.lang.c++ http://www.parashift.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html
Nov 14 '05 #16
Jack Klein wrote:
On Mon, 20 Jun 2005 07:39:46 -0400, Eric Sosman
Jack Klein wrote:

[...]
The general consensus here, which I agree with, is that the
*scanf() functions are best avoided by all except extreme
experts on their use. If non-experts avoid them, the will
never become extreme experts, making the point moot.


I'd agree that scanf() and fscanf() are best avoided,
but sscanf() is both usable and useful. fgets()/sscanf()
make a good combination.


As Ben already pointed out, all the members of *scanf() produce
undefined behavior if the result of a numeric conversion is out
of range for the destination type.

Which means to use them safely, you need to pre-check the numeric
digits before converting. If you are going to check them by hand,
you might as well do the conversion yourself, it takes little
additional effort.

Now fgets() and { strol(), strtod(), strtoul(), strtoll(),
stroull() } make a robust combination.


The only problem with that is that you have to assign a buffer. I
have published some routines which operate directly on the input
stream, and need no buffers (as does scanf). However my routines
are not variadic, and do not involve loading a large interpreter
system. They also have comprehensive error reporting, and do such
things as absorbing a complete numeric field even when the value
overflows. These are worthwhile considerations, especially in a
resource starved embedded system.

The following is a sample of the routines:

/*--------------------------------------------------------------
* Read an unsigned value. Signal error for overflow or no
* valid number found. Returns true for error, false for noerror
*
* Skip all leading whitespace on f. At completion getc(f) will
* return the character terminating the number, which may be \n
* or EOF among others. Barring EOF it will NOT be a digit. The
* combination of error, zero, and the following getc returning
* \n indicates that no numerical value was found on the line.
*
* If the user wants to skip all leading white space including
* \n, \f, \v, \r, he should first call "skipwhite(f);"
*
* Peculiarity: This specifically forbids a leading '+' or '-'.
* Peculiarity: This forbids overflow, unlike C unsigned usage.
* on overflow, UINT_MAX is returned.
*/
int readxwd(unsigned int *wd, FILE *f)
{
unsigned int value, digit;
int status;
int ch;

#define UWARNLVL (UINT_MAX / 10U)
#define UWARNDIG (UINT_MAX - UWARNLVL * 10U)

value = 0; /* default */
status = 1; /* default error */

do {
ch = getc(f);
} while ((' ' == ch) || ('\t' == ch)); /* skipblanks */
/* while (isblank((UCHAR)ch)); */ /* for C99 */

if (!(EOF == ch)) {
if (isdigit((UCHAR)ch)) /* digit, no error */
status = 0;
while (isdigit((UCHAR)ch)) {
digit = (unsigned) (ch - '0');
if ((value < UWARNLVL) ||
((UWARNLVL == value) && (UWARNDIG >= digit)))
value = 10 * value + digit;
else { /* overflow */
status = 1;
value = UINT_MAX;
}
ch = getc(f);
} /* while (ch is a digit) */
}
*wd = value;
ungetc(ch, f);
return status;
} /* readxwd */

--
Some informative links:
news:news.announce.newusers
http://www.geocities.com/nnqweb/
http://www.catb.org/~esr/faqs/smart-questions.html
http://www.caliburn.nl/topposting.html
http://www.netmeister.org/news/learn2quote.html
Nov 14 '05 #17
CBFalconer wrote:
...
int ch;
ch = getc(f);
...
if (!(EOF == ch)) {
if (isdigit((UCHAR)ch)) /* digit, no error */
Since getc already returns a value in the range of unsigned
char, there's nothing to gain by adding the UCHAR (presumably
unsigned char) cast.

If you're worried that UCHAR_MAX > INT_MAX, then you should
be performing a specific feof check.
status = 0;
while (isdigit((UCHAR)ch)) {
digit = (unsigned) (ch - '0');
if ((value < UWARNLVL) ||
((UWARNLVL == value) && (UWARNDIG >= digit)))
value = 10 * value + digit;
else { /* overflow */
status = 1;
value = UINT_MAX;
}
ch = getc(f);
} /* while (ch is a digit) */


For unsigned int, you can simplify the overflow check to...

while (isdigit(ch))
{
new_value = 10 * value + ch - '0';
if (new_value < value) { status = 1; new_value = -1; }
value = new_value;
ch = getc(f);
}

--
Peter

Nov 14 '05 #18

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: B Thomas | last post by:
Hi, I was reading O'Reilly's "Practical C programming" book and it warns against the use of scanf, suggesting to avoid using it completely . Instead it recomends to use using fgets and sscanf....
14
by: Peter Mount | last post by:
Hello I'm having trouble with " scanf("%c", &answer);" on line 20 below. When I run the program in cygwin on Windows 98SE it skips that line completely and ends the program. Does scanf have...
7
by: hugo27 | last post by:
obrhy8 June 18, 2004 Most compilers define EOF as -1. I'm just putting my toes in the water with a student's model named Miracle C. The ..h documentation of this compiler does state that when...
4
by: sushant | last post by:
hi why do we use '&' operator in scanf like scanf("%d", &x); but why not in printf() like printf("%d" , x); thnx in advance sushant
33
by: Lalatendu Das | last post by:
Dear friends, I am getting a problem in the code while interacting with a nested Do-while loop It is skipping a scanf () function which it should not. I have written the whole code below. Please...
14
by: main() | last post by:
I know this is the problem that most newbies get into. #include<stdio.h> int main(void) { char a; scanf("%c",&a); /*1st scanf */ printf("%c\n",a); scanf("%c",&a); /*2nd scanf*/...
8
by: Neil | last post by:
Hello Just to let you know this not homework, I'm learning the language of C on my own time.. I recently tried to create a escape for user saying printf ("Do you want to continue? (y or n)");...
3
by: Tinku | last post by:
#include<stdio.h> main() { char line; scanf("%", line); printf("%s", line); } it will read and print the line but what is "%" in general we gives %s, %c .
2
by: subramanian100in | last post by:
Consider the following program named as x.c #include <stdlib.h> #include <stdio.h> int main(void) { unsigned int u; char str;
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.