get_double input function (getchar+scanf)

  • Thread starter =?ISO-8859-1?Q?Martin_J=F8rgensen?=
  • Start date
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Hi,

Since I'm a newbie I have some small but quick (probably) stupid
questions also :)

This is my "get_double" function which takes a default argument also of
type double. The function returns a value of type double so I can write
something like value = getdouble(0.5); in my program.

--------------

double get_double(double default)
{
double input;
char ch;

while (scanf("%lf", &input) != 1) /* if valid input was not entered */
{
while ((ch = getchar()) != '\n')
putchar(ch); /* dispose bad input */
printf(" is not valid input. Assuming default value: %lf\n", default);
input = default;
}
return input;
}

--------------

The compiler says:

syntax error : missing ')' before 'default'
syntax error : missing '{' before 'default'
syntax error : 'default'
syntax error : ')'

It probably thinks I'm trying to cast some value to type double I
guess....? What is it complaining about?

It is declared in the beginning as:

double get_double(double); /* get input of type double */


Med venlig hilsen / Best regards
Martin Jørgensen
 
B

Broeisi

Hello,

default is a keyword in C.
It's used in the switch statement..

Try changing that as that;s the only thing I see that can be a problem
in the code you posted..

Broeisi
 
E

Eric Sosman

Martin Jørgensen wrote On 02/16/06 13:45,:
[...]

double get_double(double default)
[...]
The compiler says:

syntax error : missing ')' before 'default'

`default' is a keyword; you cannot use it as an
identifier. What you've written is very much like

double get_double(double return)
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Eric Sosman wrote:
-snip-
`default' is a keyword; you cannot use it as an
identifier. What you've written is very much like

double get_double(double return)

Ok, thanks Eric.

Next (small) problem:

double get_double(double defaultvalue)
{
double input;

if (scanf("%lf", &input) != 1 || input == '\n' || input < 0 || input >1
) /* if valid input was not entered */
{
printf("That is not valid input (0 <= theta <= 1). Assuming default
value: %lf\n", defaultvalue);
input = defaultvalue;
}
return input;
}

If I hit "enter" it doesn't immediately assign defaultvalue to input,
but keeps waiting for something. I want: If the user hits enter, input =
defaultvalue; I thought the "\n" did the job, but it doesn't...


Med venlig hilsen / Best regards
Martin Jørgensen
 
F

Fred Kleinschmidt

Martin Jørgensen said:
Hi,

Since I'm a newbie I have some small but quick (probably) stupid questions
also :)

This is my "get_double" function which takes a default argument also of
type double. The function returns a value of type double so I can write
something like value = getdouble(0.5); in my program.

--------------

double get_double(double default)
{
double input;
char ch;

while (scanf("%lf", &input) != 1) /* if valid input was not entered */
{
while ((ch = getchar()) != '\n')
putchar(ch); /* dispose bad input */
printf(" is not valid input. Assuming default value: %lf\n", default);
input = default;
}
return input;
}

1) Don't use 'default' as the name of a variable; it is a reserved word.
2) Don't use scanf, getchar, and putchar.
Instead, use fgets to read the user's input, then use strtod to convert it
to a double. You can check strtod's returned pointer to see if there is a
format error in the user's input.
 
E

Eric Sosman

Martin Jørgensen wrote On 02/16/06 15:11,:
Eric Sosman wrote:
-snip-




Ok, thanks Eric.

Next (small) problem:

double get_double(double defaultvalue)
{
double input;

if (scanf("%lf", &input) != 1 || input == '\n' || input < 0 || input >1
) /* if valid input was not entered */
{
printf("That is not valid input (0 <= theta <= 1). Assuming default
value: %lf\n", defaultvalue);
input = defaultvalue;
}
return input;
}

If I hit "enter" it doesn't immediately assign defaultvalue to input,
but keeps waiting for something. I want: If the user hits enter, input =
defaultvalue; I thought the "\n" did the job, but it doesn't...

The only way input == '\n' can be true is if the
user entered the number that happens to be equal to the
numeric code for the newline character -- 10, on many
systems. In particular, scanf() does not store '\n' (or
anything else) in the variable when presented with an
empty line.

What does it do instead? It keeps on looking for
something to convert. The "%lf" specifier (like most)
reads and ignores leading white space until it finds
something else, and '\n' is white space. You can hit
ENTER all day long, and scanf() will keep on eating those
newline characters. It won't return to your code until
something else is entered.

scanf() is not a good tool for what you're trying to
do -- you want to consider the user's input line by line,
but scanf() is not very sensitive to line boundaries. An
easy alternative is to read a line with fgets() (*not*
with gets!()!), and then use sscanf() to extract data
from the buffered line.
 
M

Mark McIntyre

if (scanf("%lf", &input) != 1 || input == '\n' || input < 0 || input >1
If I hit "enter" it doesn't immediately assign defaultvalue to input,
but keeps waiting for something.

The fix for this is NOT to use scanf. This is only one of the problems
with the function.
I want: If the user hits enter, input =
defaultvalue; I thought the "\n" did the job, but it doesn't...

\n doesn't match %lf, so scanf ignores it. Use fgets and sscanf.
Mark McIntyre
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Eric Sosman wrote:
-snip-
scanf() is not a good tool for what you're trying to
do -- you want to consider the user's input line by line,
but scanf() is not very sensitive to line boundaries. An
easy alternative is to read a line with fgets() (*not*
with gets!()!), and then use sscanf() to extract data
from the buffered line.

Thanks a lot. Good explanation. I'll dig into that gets()+sscanf() stuff.


Med venlig hilsen / Best regards
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Mark said:
The fix for this is NOT to use scanf. This is only one of the problems
with the function.

What other problems are there?


Med venlig hilsen / Best regards
Martin Jørgensen
 
M

Michael Mair

Martin said:
What other problems are there?

scanf() does not tell you what kind of errors you have
at conversion, whether it left anything in the input line
etc.
Your function only has stdout to tell the user that something
went wrong.

Consider the following:

,----
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "ggets/ggets.h"

int get_double (double *retval, double *range)
{
double input;
char *buf = NULL, *ctrl;
int failure = ggets(&buf);

if (failure != 0) {
/* You could do further error analysis via failure */
failure = failure<0 ? failure : 1;
}
else {
input = strtod(buf, &ctrl);

if (ERANGE == errno) {
/* fputs("number out of range\n", stderr); */
failure = 2;
}
else if (ctrl == buf) {
/* fputs("not valid numeric input\n", stderr); */
failure = 3;
}
#ifdef KNOW_IT_ALL
else if (*ctrl != '\0') {
/* fputs("some characters have been discarded\n", stderr); */
failure = 4;
}
#endif
else {
if (range != NULL
&& (range[0] > input || range[1] < input))
{
/* fprintf(stderr, "%g not in range [%g, %g]\n",
input, range[0], range[1]);
*/
failure = 5;
}
else
*retval = input;
}
}

free(buf);
return failure;
}

int main (void)
{
double value = 42.0;
double range[] = {0.0, 1.0};
int retval;

do {
printf("> "); (void)fflush(stdout);
retval = get_double(&value, range);
printf("(%d) ", retval);
if (0 == retval)
printf("%g", value);
putchar('\n');
} while (value != 0.0);

return 0;
}

`----

The only unsafe part is that value could be used
uninitialised if a non-zero return value of get_double
is ignored.
ggets is the one "Available at
<http://cbfalconer.home.att.net/download/ggets.zip>"
as Chuck Falconer puts it.


Cheers
Michael
 
M

Mark McIntyre

Eric Sosman wrote:
-snip-


Thanks a lot. Good explanation. I'll dig into that gets()+sscanf() stuff.

NO - not gets(), you want fgets().
NEVER EVER use gets().
Mark McIntyre
 
M

Martin Ambuhl

Martin said:
Eric Sosman wrote:
-snip-



Thanks a lot. Good explanation. I'll dig into that gets()+sscanf() stuff.

Please don't. Read what Eric wrote ("*not* with gets").
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Mark McIntyre wrote:
-snip-
NO - not gets(), you want fgets().
NEVER EVER use gets().

Ok, got it. Thanks for the corrections too :)


Med venlig hilsen / Best regards
Martin Jørgensen
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael Mair wrote:
-snip <code>-

Nice. Thanks for that. A bit more complicated than I thought was
necessary, but okay - I have something to study now.
The only unsafe part is that value could be used
uninitialised if a non-zero return value of get_double
is ignored.
ggets is the one "Available at
<http://cbfalconer.home.att.net/download/ggets.zip>"
as Chuck Falconer puts it.

I just downloaded it and will test it tomorrow...


Med venlig hilsen / Best regards
Martin Jørgensen
 
M

Michael Mair

Martin said:
Michael Mair wrote:
-snip <code>-

Nice. Thanks for that. A bit more complicated than I thought was
necessary, but okay - I have something to study now.

That was the point -- you always can deliberately skimp on
the error checking and handling but you should know what
can go wrong beforehand.
Moreover, only if your interface layer and I/O functions
are bulletproof then you need not worry about unintended
input upsetting your program -- also the need for certain
kinds of consistency checks may vanish in places where
they cost performance.


Cheers
Michael
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael Mair wrote:
-snip-
That was the point -- you always can deliberately skimp on
the error checking and handling but you should know what
can go wrong beforehand.
Moreover, only if your interface layer and I/O functions
are bulletproof then you need not worry about unintended
input upsetting your program -- also the need for certain
kinds of consistency checks may vanish in places where
they cost performance.

Yeah, I liked your example code. I also wondered why sometimes if I
wanted the user to input something and if the user entered a letter such
as 'd', then the output went completely crazy. Unfortunately, I can't
remember if I used getchar() og scanf() or which program code I used but
I tried this thing at least twice and it is still a problem I'll have to
figure out of how to solve.


Med venlig hilsen / Best regards
Martin Jørgensen
 

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,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top