Reading a number from stdin

P

pandit

AIM: To read a number from standard input

WHAT I DID: I use getchar() to read a single digit. Can use strtol() for numbers more than one digit long.

PROBLEM: isn't there a better way ?

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


int main(void)
{
int i = 0;

i = getchar();
if((EOF == i) && (ferror(stdin)))
{
printf("ERROR reading input @LINE = %d\n", __LINE__);
}
else
{
i = i - '0';
}

return 0;
}


-- output here --
../a.out
1

output
1
 
I

Ike Naar

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

int main(void)
{
int i = 0;

i = getchar();
if((EOF == i) && (ferror(stdin)))
{
printf("ERROR reading input @LINE = %d\n", __LINE__);
}
else
{
i = i - '0';
}

return 0;
}


-- output here --
./a.out
1

output
1

The program that you have shown does not produce any output.
 
M

Malcolm McLean

AIM: To read a number from standard input

WHAT I DID: I use getchar() to read a single digit. Can use strtol() for numbers more than
one digit long.

PROBLEM: isn't there a better way ?
Yes and no.
For most purposes, grabbing a line from stdin then parsing it with sscanf() is fine.
But there are issues like what to do with an integer which is too big for machine precision,
which mean that a nice fully general solution is hard, and C doesn't provide one,
though you can build something on top of strtol().
 
B

Ben Bacarisse

pandit said:
AIM: To read a number from standard input

For simple programs, use scanf. When you need to control the layout
that you accept, or when you must correctly handle boundary cases like
digit strings that do not correspond to valid numbers, you need to read
the data into a buffer and process it with functions like strtol().
WHAT I DID: I use getchar() to read a single digit. Can use strtol()
for numbers more than one digit long.

PROBLEM: isn't there a better way ?

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


int main(void)
{
int i = 0;

i = getchar();
if((EOF == i) && (ferror(stdin)))

This includes a redundant test and is, almost certainly, not what you
intended to write. When there has been an error reading a character
(i.e. when ferror(stdin) is non-zero), i is guaranteed to be EOF.
Testing both is pointless. You may have intended to test for either
EOF or and error:

if (i == EOF || ferror(stdin)) ...
{
printf("ERROR reading input @LINE = %d\n", __LINE__);

It's a good idea to get into the habit if writing error messages to
stderr.
}
else
{
i = i - '0';
}

return 0;
}


-- output here --
./a.out
1

output
1

Your program can't produce this output. Always cut-and-pasts (or
similar) when posting programs. That avoids people commenting on code
that is not the code you are actually running!
 
B

Bill Cunningham

pandit said:
AIM: To read a number from standard input

I ususally use fgets directed to stdin. That way there's a buffer and
you don't have to worry about buffer overflow like can happen with scanf.

Bill
 
K

Keith Thompson

What you have written, reads a single digit.

To read a whole numeral, one can use »scanf«.

scanf("%d", &i) has undefined behavior if the input matches the
syntax of an optionally signed integer constant but has a value
outside the range INT_MIN..INT_MAX.

(I personally consider this to be a flaw in the language definition.
The standard explicitly states that it's UB, so it's not
inconsistent, but it's bad design.)

You can avoid that by restricting the number of digits, but then
you can't read certain large values.

If you want robust behavior, use fgets() (plus whatever you
need to do to allow for very long lines) followed by one of the
strto*() functions. (I might write a wrapper around strtol()
that more cleanly differentiates between the value read and an
error indication.)
 
K

Keith Thompson

pandit said:
AIM: To read a number from standard input

WHAT I DID: I use getchar() to read a single digit. Can use strtol()
for numbers more than one digit long.

PROBLEM: isn't there a better way ?

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


int main(void)
{
int i = 0;

i = getchar();
if((EOF == i) && (ferror(stdin)))
{
printf("ERROR reading input @LINE = %d\n", __LINE__);
}
else
{
i = i - '0';

Subtracting '0' from i makes no sense unless you already know i is a
digit (i.e., a value in the range '0' .. '9'). You have no handling for
invalid input. What happens if the first input character is 'z', for
example?
 
J

jay

Ben Bacarisse wrote:

For simple programs, use scanf.


Why this advice ? I think C-FAQs tell about enough of the issues related with scanf.

http://c-faq.com/stdio/scanfprobs.html

footnotes explanation by "your truly" give much better case against scanf.

strtol() is what I always use myself.


This includes a redundant test and is, almost certainly, not what you
intended to write. When there has been an error reading a character
(i.e. when ferror(stdin) is non-zero), i is guaranteed to be EOF.
Testing both is pointless. You may have intended to test for either
EOF or and error:


I think OP used it in correct way:

Section 15.6, H&s5, (regarding getchar())

"If an error occurs or if the stream is at end of file, then fgetc returns EOF. The feof and/or ferror facilities should be used in this case to determine whether end of file has really been reached."

Section 15.1, H&S5 (regarding EOF):

"Because EOF is sometimes used to signal other problems, it is best to use feof() facility to determine whether end of file has indeed been encountered when EOF is returned."


-- Arnuld
 
J

James Kuyper

I think OP used it in correct way:

Section 15.6, H&s5, (regarding getchar())

"If an error occurs or if the stream is at end of file, then fgetc returns EOF. The feof and/or ferror facilities should be used in this case to determine whether end of file has really been reached."

Section 15.1, H&S5 (regarding EOF):

"Because EOF is sometimes used to signal other problems, it is best to use feof() facility to determine whether end of file has indeed been encountered when EOF is returned."

There's nothing incorrect about the if() condition, it's simply mildly
wasteful: it is inherently equivalent to if(ferror(stdin)). The only
point in including the EOF==i part is to minimize the overhead
associated with calling ferror(). On systems where ferror(stdin) is
actually a macro that expands to something like stdin->_eof, that
overhead can be quite trivial.
 
B

Ben Bacarisse

jay said:
Why this advice ? I think C-FAQs tell about enough of the issues
related with scanf.

It's good to know the issues, but if the advice it simply not to use
scanf, ever, then I disagree. If you are using C for some simple
numerical task, I think scanf is fine. You'll see I went on the explain
the main reasons to avoid it -- when you worry about overflow and where
line endings are significant.
http://c-faq.com/stdio/scanfprobs.html

footnotes explanation by "your truly" give much better case against
scanf.

No, it explains the problems that you might encounter mixing scanf and
gets (yes, gets!). It is not about using scanf on its own. In
particular, the summery says:

"The 'better way', as indicated in the FAQ list, is either to abandon
scanf entirely, or to use it exclusively."

Not much of a case against scanf. [By the way, it describes using gets
with a dummy buffer to read an discard up to the end of a line as "ugly,
unclean" and "unsatisfying". It omits to say "horribly unsafe". The
page dates, I think, from a more innocent era.]
strtol() is what I always use myself.

You are careful about input. That's good. If, on day one of Numerical
Analysis 101, you were asked to write something like this:

int main(void)
{
int n = 0;
double sum = 0, sum_sq = 0, x;
while (scanf("%lf", &x) == 1) {
n += 1;
sum += x;
sum_sq += x*x;
}
if (n)
printf("N=%d, mean=%g, var=%g\n",
n, sum/n, (n*sum_sq - sum*sum)/(n*n));
}

How would you do it, and would it be worth the effort?
I think OP used it in correct way:

Note that I did not say it was incorrect, but presumably you are saying
that I was wrong to say that it includes a redundant test.
Section 15.6, H&s5, (regarding getchar())

"If an error occurs or if the stream is at end of file, then fgetc
returns EOF. The feof and/or ferror facilities should be used in this
case to determine whether end of file has really been reached."

Section 15.1, H&S5 (regarding EOF):

"Because EOF is sometimes used to signal other problems, it is best to
use feof() facility to determine whether end of file has indeed been
encountered when EOF is returned."

I don't see anything there that contradicts what I said. Why do you
think it does?
 
J

jay

No, it explains the problems that you might encounter mixing scanf and
gets (yes, gets!). It is not about using scanf on its own.

I see your reasoning but still I have two mental-blocks in recommending scanf():

1) scanf() means scan formatted and interactive-terminal is the least formatted thing you can ever across.

2) What about Chris Torek's footnote. It simply says, there is a right answer to read user input you should either use fegts() with strtol() or fgets() with sscanf().


My bigger problem is looking at programmers in Indian companies actually. Their ways of working frustrates me sometimes. Every programmer I have met in industry here uses scanf() 100% of the time and that too without knowing about it how it works. We ran into some problems because someone in team used scanf() and all hell broke loose because he did not know scanf() leaves the input on stream, it is exactly like the input "three" in Chris Torek's footnote. Now when I try to explain how scanf() works and what caused the issue, then no one even believes me. Even if I point them to CLC or n1570.pdf , it does not matter, no one listens and 100% of the people have hated me for telling them about scanf() works. Of all the people I have met in last 7 years, not one has ever read the standard and they detest it.

So, I have developed hatred for scanf() family. That is my mental block. But I want to learn C better and better everyday and become expert like Keith Thompson and that is the reason I always keep on coming back to CLC andthat is why I posted my mental block because I think it may prevent me from becoming better with C


You are careful about input. That's good. If, on day one of Numerical
Analysis 101, you were asked to write something like this:

int main(void)
{
int n = 0;
double sum = 0, sum_sq = 0, x;
while (scanf("%lf", &x) == 1) {
n += 1;
sum += x;
sum_sq += x*x;
}
if (n)
printf("N=%d, mean=%g, var=%g\n",
n, sum/n, (n*sum_sq - sum*sum)/(n*n));
}

How would you do it, and would it be worth the effort?

Literally no idea what meaningful work this program does

Note that I did not say it was incorrect, but presumably you are saying
that I was wrong to say that it includes a redundant test.

yes, that is what I am saying. See down below.



I don't see anything there that contradicts what I said. Why do you
think it does?


Read this:

"Because EOF is sometimes used to signal other problems, it is best to
use feof() facility to determine whether end of file has indeed been
encountered when EOF is returned."


It say, when EOF is returned then you shoudl use feof() facility to check for errors. It does *not* say that you should use either EOF or feof(). It says when EOF is returned then use feof().

Same thing I am doing, I am checking that EOF is returned and only then (&&) I am checking ferror() (because I don't know the difference between usingfeof() and ferror())
 
K

Keith Thompson

jay said:
I see your reasoning but still I have two mental-blocks in
recommending scanf():

1) scanf() means scan formatted and interactive-terminal is the least
formatted thing you can ever across.

2) What about Chris Torek's footnote. It simply says, there is a right
answer to read user input you should either use fegts() with strtol()
or fgets() with sscanf().

fgets() with sscanf() is still perilous for numeric input. All the
*scanf() functions (scanf, fscanf, sscanf) have undefined behavior when
scanning numeric input if the input is syntactically correct but outside
the range of the target type. (You can use, for example, "%5d" to limit
the number of digits, but then there will be valid numbers you can't
read.)

At least with sscanf() you can in principle avoid feeding it a string
with an overflowing number -- but if you can determine that, then you've
probably already determined the value anyway.
Literally no idea what meaningful work this program does

It reads a sequence of floating-point numbers from standard input,
keeping track of who many numbers have been read, the sum of the
numbers, and the sum of the squares of the numbers. It then computes
and prints the mean and variance.

[...]
Read this:

"Because EOF is sometimes used to signal other problems, it is best to
use feof() facility to determine whether end of file has indeed been
encountered when EOF is returned."


It say, when EOF is returned then you shoudl use feof() facility to
check for errors. It does *not* say that you should use either EOF or
feof(). It says when EOF is returned then use feof().
Right.

Same thing I am doing, I am checking that EOF is returned and only
then (&&) I am checking ferror() (because I don't know the difference
between using feof() and ferror())

Not quite. The point is that this:

i = getchar();
if((EOF == i) && (ferror(stdin)))

is logically equivalent to this:

i = getchar();
if (ferror(stdin))

After getchar() returns EOF exactly one of feof() and ferror() will be
true.

If you just want to read as many characters as you can, you don't need
to call ferror() or feof() at all; you can just keep reading until
getchar() returns EOF. If you want to distinguish between an
end-of-file condition and an error condition, you can do something like
this:

int c;
while ((c = getchar()) != EOF) {
/* do something with c, which is a character read from stdin */
}
/* Now we've run out of input -- but why? */
if (ferror(stdin)) {
printf("Error reading from stdin\n"):
}
else {
printf("No error, just ran out of input\n");
}

If you don't know the difference between feof() and ferror(), I suggest
you find out.
 
M

Malcolm McLean

fgets() with sscanf() is still perilous for numeric input. All the
*scanf() functions (scanf, fscanf, sscanf) have undefined behavior when
scanning numeric input if the input is syntactically correct but outside
the range of the target type. (You can use, for example, "%5d" to limit
the number of digits, but then there will be valid numbers you can't
read.)
Normally the valid numbers for the application are much lower than INT_MAX,
so the %5d method works for most situations.
I checked my version of sscanf, and it sets the target to 0xFFFFFFFFF (all bits set)
and returns 1 on begin fed a massive integer. That's undesirable, because it
should be returning 0 and setting the stream to the start position. Sometimes
you just want to skip a number and parse the following text, in which case
my compiler's behaviour is best, but if the value is used, the program will get
into an odd state, even if checks are made.
 
J

jay

Keith Thompson wrote:
fgets() with sscanf() is still perilous for numeric input. All the
*scanf() functions (scanf, fscanf, sscanf) have undefined behavior when
scanning numeric input if the input is syntactically correct but outside
the range of the target type.

Because of this reason I always check strtol() for errors. IIRC, you posted about the errors scenarios few years back as a reply to one of my posts.



It reads a sequence of floating-point numbers from standard input,
keeping track of who many numbers have been read, the sum of the
numbers, and the sum of the squares of the numbers. It then computes
and prints the mean and variance.

My math is a bit weak, don't know the difference between "mean", "variance", "average" and "median". I will work on it.


while ((c = getchar()) != EOF) {
/* do something with c, which is a character read from stdin */
}
/* Now we've run out of input -- but why? */
if (ferror(stdin)) {
printf("Error reading from stdin\n"):
}

What if I am reading input only once and there is an error in reading it ? Can't I use ferror() in this case ?



If you don't know the difference between feof() and ferror(), I suggest
you find out.


ok, I get it.

-- feof() : checks if end of file has been detected while reading from the input stream. It signals end of file when an attempt is made to read *past* the last character. If it was really an end of file then it returns non-zero value else zero.

-- ferror() : returns error status of stream. if an error has occurred while reading from or writing to the stream, then it returns non-zero value else zero.

stream -- any of 4: pointer to a file/stdin/stdout/stderr.
 
M

Malcolm McLean

My math is a bit weak, don't know the difference between "mean", "variance", "average"
and "median". I will work on it.
"mean" is the total divided by the number. It's also what we commonly mean by the "average",
though that's a loose term which doesn't necessarily have a mathematical meaning. (An average
sort of football player).
median is the point at which half the population is above and half below the value. Median
is often more useful than mean for describing things like salaries, where the mean can be
skewed by a few people on extremely high salaries, giving a flattering impression of the
typical salary.

Variance is a measure of spread. Most adult men are between 6 foot two and five foot tall,
with only a few outside these limits. When you include women and children, you get a
huge range, with fairly large numbers of people under three foot tall (little children).
So variance amongst adult males is quite low, amongst humans in general, pretty high.
 
J

James Kuyper

My math is a bit weak, don't know the difference between "mean", "variance", "average" and "median". I will work on it.

Well, the key point of the question was not the math (and all of the
relevant formulas were already present in the code). The key point was,
if you're not going to use scanf(), what alternative would you use.
fgets()/strtol() is a good answer to that question - but that approach
is significantly more complicated than using scanf().
What if I am reading input only once and there is an error in reading it ? Can't I use ferror() in this case ?

You can always use ferror(stream) to determine whether or not there has
been an I/O error on that stream. It doesn't matter how many times
you've read input from that stream. It even works if you've never done
so. The key issue is that it's generally not useful to continue reading
from a given stream after having had an I/O error, and it's not
necessary to check for either feof() or ferror() until after getchar()
has returned EOF. It's perfectly safe, just not useful.
 
B

Ben Bacarisse

Keith has provided all the technical answers already, but since there is
some opinion here, I'll do some duplication and answer myself...
I see your reasoning but still I have two mental-blocks in
recommending scanf():

1) scanf() means scan formatted and interactive-terminal is the least
formatted thing you can ever across.

That's an argument from a name. The formatted refers to the format
string, not to the structure of the input. In fact, the main problem
with scanf for interactive input is that scanf can't impose a format on
the input, at least not in the sense that other languages like Fortran
can; %d, %f and so on denote what other languages would call
"free-form" input.
2) What about Chris Torek's footnote. It simply says, there is a right
answer to read user input you should either use fegts() with strtol()
or fgets() with sscanf().

He is welcome to his opinion. I disagree. Reading lines if very often
the right thing to do, but blanket rules are not a good idea in
programming. In fact, while you are learning programming your should
try to think of an exception to every rule you hear. You may not find
one, but the trying is worth it.
My bigger problem is looking at programmers in Indian companies
actually. Their ways of working frustrates me sometimes. Every
programmer I have met in industry here uses scanf() 100% of the time
and that too without knowing about it how it works. We ran into some
problems because someone in team used scanf() and all hell broke loose
because he did not know scanf() leaves the input on stream,

All input operations 9except for the last one) leave input on the
stream. Whatever the problem was, it was not that!
it is
exactly like the input "three" in Chris Torek's footnote. Now when I
try to explain how scanf() works and what caused the issue, then no
one even believes me.

OK, but with that level of denial, are you sure that using fgets +
sscanf (both of which are tricky to use correctly) would help?
Even if I point them to CLC or n1570.pdf , it
does not matter, no one listens and 100% of the people have hated me
for telling them about scanf() works. Of all the people I have met in
last 7 years, not one has ever read the standard and they detest it.

So, I have developed hatred for scanf() family. That is my mental
block. But I want to learn C better and better everyday and become
expert like Keith Thompson and that is the reason I always keep on
coming back to CLC and that is why I posted my mental block because I
think it may prevent me from becoming better with C

Well, try the exercise I suggested then:
Literally no idea what meaningful work this program does

Do you work programming in C?
yes, that is what I am saying. See down below.

Well, I stick to what I said. Keith, who you quite correctly regard as
an expert, has explained some more about this.
Read this:

"Because EOF is sometimes used to signal other problems, it is best to
use feof() facility to determine whether end of file has indeed been
encountered when EOF is returned."


It say, when EOF is returned then you shoudl use feof() facility to
check for errors. It does *not* say that you should use either EOF or
feof(). It says when EOF is returned then use feof().

Same thing I am doing, I am checking that EOF is returned and only
then (&&) I am checking ferror() (because I don't know the difference
between using feof() and ferror())

You've not really understood what the passage you quote is saying but
I'll leave this for now since it's been addressed and I see further
posts in the thread. If you remain unconvinced, feel free to ask again
later.
 
B

Ben Bacarisse

Malcolm McLean said:
Normally the valid numbers for the application are much lower than INT_MAX,
so the %5d method works for most situations.

That's very risky advice. Try scanf("%d %d", &i, &j) and feed it
-10001. How surprised will the use be?

Also, %5d is not small enough to be safe with 16-bit ints. These may be
rare, but you never know when they will make a come-back.

<snip>
 
B

Ben Bacarisse

(something has gone wrong with the quoting level, but the names are right)
My math is a bit weak, don't know the difference between "mean",
"variance", "average" and "median". I will work on it.

The maths does not matter. Chuck out everything but finding the sum
(you know that much maths, I'm sure). The point of the exercise was to
see how you write the input using your better safe methods; and,
ultimately, to see if it worth it in this case.

<snip>
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top