Why scanf accepts chars for “%f” format specifier?
up vote
1
down vote
favorite
I'm preparing a simple program for my classes and found that scanf
is not as strict as I expected:
int main()
{
// Define variables
float alpha;
float b;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
scanf("%f %f", &alpha, &b);
printf("%f %fn", alpha, b);
return 0;
}
Returns:
Type alpha and b. Space separated float numbers only.
a 0
-29768832.000000 0.000000
Where I can read about its behavior?
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
P. S. I'm using gcc v5 in Ubuntu.
c stdio
|
show 1 more comment
up vote
1
down vote
favorite
I'm preparing a simple program for my classes and found that scanf
is not as strict as I expected:
int main()
{
// Define variables
float alpha;
float b;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
scanf("%f %f", &alpha, &b);
printf("%f %fn", alpha, b);
return 0;
}
Returns:
Type alpha and b. Space separated float numbers only.
a 0
-29768832.000000 0.000000
Where I can read about its behavior?
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
P. S. I'm using gcc v5 in Ubuntu.
c stdio
3
How can I .. throw an exception - There are no exceptions in C.
– kfx
Nov 11 at 18:18
9
You could start by checking the return value fromscanf
to see if it read anything at all or not.
– Retired Ninja
Nov 11 at 18:18
4
"Where I can read about its behavior?" -- the best place is the Standard
– David Bowling
Nov 11 at 18:18
3
... or the documentation for your C library. On a Unix-flavored system, you can find that in its manual page (man scanf
). For the Microsoft C library, look at the online docs. Etc.
– John Bollinger
Nov 11 at 18:31
1
Better to post your own answer below as an answer rather than in your question. See Can I answer my own question?. Recommend to roll-back your edit.
– chux
Nov 11 at 20:19
|
show 1 more comment
up vote
1
down vote
favorite
up vote
1
down vote
favorite
I'm preparing a simple program for my classes and found that scanf
is not as strict as I expected:
int main()
{
// Define variables
float alpha;
float b;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
scanf("%f %f", &alpha, &b);
printf("%f %fn", alpha, b);
return 0;
}
Returns:
Type alpha and b. Space separated float numbers only.
a 0
-29768832.000000 0.000000
Where I can read about its behavior?
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
P. S. I'm using gcc v5 in Ubuntu.
c stdio
I'm preparing a simple program for my classes and found that scanf
is not as strict as I expected:
int main()
{
// Define variables
float alpha;
float b;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
scanf("%f %f", &alpha, &b);
printf("%f %fn", alpha, b);
return 0;
}
Returns:
Type alpha and b. Space separated float numbers only.
a 0
-29768832.000000 0.000000
Where I can read about its behavior?
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
P. S. I'm using gcc v5 in Ubuntu.
c stdio
c stdio
edited Nov 11 at 20:25
asked Nov 11 at 18:15
terales
1,6641525
1,6641525
3
How can I .. throw an exception - There are no exceptions in C.
– kfx
Nov 11 at 18:18
9
You could start by checking the return value fromscanf
to see if it read anything at all or not.
– Retired Ninja
Nov 11 at 18:18
4
"Where I can read about its behavior?" -- the best place is the Standard
– David Bowling
Nov 11 at 18:18
3
... or the documentation for your C library. On a Unix-flavored system, you can find that in its manual page (man scanf
). For the Microsoft C library, look at the online docs. Etc.
– John Bollinger
Nov 11 at 18:31
1
Better to post your own answer below as an answer rather than in your question. See Can I answer my own question?. Recommend to roll-back your edit.
– chux
Nov 11 at 20:19
|
show 1 more comment
3
How can I .. throw an exception - There are no exceptions in C.
– kfx
Nov 11 at 18:18
9
You could start by checking the return value fromscanf
to see if it read anything at all or not.
– Retired Ninja
Nov 11 at 18:18
4
"Where I can read about its behavior?" -- the best place is the Standard
– David Bowling
Nov 11 at 18:18
3
... or the documentation for your C library. On a Unix-flavored system, you can find that in its manual page (man scanf
). For the Microsoft C library, look at the online docs. Etc.
– John Bollinger
Nov 11 at 18:31
1
Better to post your own answer below as an answer rather than in your question. See Can I answer my own question?. Recommend to roll-back your edit.
– chux
Nov 11 at 20:19
3
3
How can I .. throw an exception - There are no exceptions in C.
– kfx
Nov 11 at 18:18
How can I .. throw an exception - There are no exceptions in C.
– kfx
Nov 11 at 18:18
9
9
You could start by checking the return value from
scanf
to see if it read anything at all or not.– Retired Ninja
Nov 11 at 18:18
You could start by checking the return value from
scanf
to see if it read anything at all or not.– Retired Ninja
Nov 11 at 18:18
4
4
"Where I can read about its behavior?" -- the best place is the Standard
– David Bowling
Nov 11 at 18:18
"Where I can read about its behavior?" -- the best place is the Standard
– David Bowling
Nov 11 at 18:18
3
3
... or the documentation for your C library. On a Unix-flavored system, you can find that in its manual page (
man scanf
). For the Microsoft C library, look at the online docs. Etc.– John Bollinger
Nov 11 at 18:31
... or the documentation for your C library. On a Unix-flavored system, you can find that in its manual page (
man scanf
). For the Microsoft C library, look at the online docs. Etc.– John Bollinger
Nov 11 at 18:31
1
1
Better to post your own answer below as an answer rather than in your question. See Can I answer my own question?. Recommend to roll-back your edit.
– chux
Nov 11 at 20:19
Better to post your own answer below as an answer rather than in your question. See Can I answer my own question?. Recommend to roll-back your edit.
– chux
Nov 11 at 20:19
|
show 1 more comment
4 Answers
4
active
oldest
votes
up vote
3
down vote
I'm preparing a simple program for my classes and found that scanf is
not as strict as I expected
No, you didn't.
Given this scanf
call:
float alpha;
float b;
scanf("%f %f", &alpha, &b);
... and this input:
a 0
... scanf
has a matching failure when it encounters the 'a' while trying to scan a floating-point value and not having yet scanned any decimal digits. It stops at that point (and leaves the 'a' in the stream for a subsequent read), and, as always, it returns the number of input fields successfully scanned (0).
Where I can read about its behavior?
You could try running the command man scanf
at the command line (Linux, OSX, ...), or entering the same as a Google search. Or google "scanf docs" or "scanf manual" or similar. Or look up the official manual for your particular C library. For standard library functions, the standard is an excellent reference, but your particular implementation may have extensions not documented there, or occasionally may even differ from the standard in minor ways.
How can I make input strict with standard functions and throw an
exception if there was neither ints nor floats?
C does not have exceptions. It tells you about errors via function return values, for the most part, though some third-party libraries may do it slightly differently. But you have to do your part, by checking the return values and responding appropriately. In this particular case, you must avoid reading the values of alpha
and b
. Because those variables were not initialized and did not subsequently have any values assigned to them, reading their values produces undefined behavior.
1
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions seterrno
under some circumstances.
– David Bowling
Nov 11 at 19:04
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
1
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that whenscanf
reports fewer than 2 matches (it will not report more).
– John Bollinger
Nov 12 at 11:53
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
add a comment |
up vote
3
down vote
Others answers, especially @John Bollinger well explain why code fails to meet the goal.
Note input may converter to a int
, float
, neither, or both.
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
The best is to use other tools like fgets()
to read a line of input and form a string for later testing.
To test strictly for is a bit hard. *scanf("%d",...)
has undefined behavior on overflow. *scanf("%f",...)
has similar UB, especially when float
does not support infinity/not-a-number.
To test if a string convert to a valid int
bool my_isint(const char *s) {
// Add to dis-allow leading white-space
if (isspace((unsigned char) *s)) return false;
char *endptr;
base = 0; // use base = 0 to only allow base 10 input
errno = 0;
long val = strtol(s, &endptr, base);
if (s == endptr) return false; // no conversion
if (errno == ERANGE) return false; // too big for long
if (val > INT_MAX || val < INT_MIN) return false; // too big for int
// Add to allow trailing white-space
while (isspace((unsigned char) *endptr)) endptr++;
// Add to dis-allow trailing junk
while (*endptr) return false; // trailing junk
return true;
}
To test if a string converts to a valid float
is like testing for double
when float
supports infinity/non-a-number. More later- GTG.
1
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
2
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it justif (sscanf(buf, "%d",...) == 1)
andif (sscanf(buf, "%f",...) == 1)
.
– chux
Nov 11 at 20:15
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
add a comment |
up vote
1
down vote
fgets
can be used to read a line. Parse the line with sscanf
. sscanf
will return the number of items successfully scanned. This also captures the character following the second float. If it is not a newline, the loop continues until two floats followed by a newline are scanned.
#include <stdio.h>
#include <stdlib.h>
int main( void) {
char input[200] = "";
char nl = 0;
int items = 3;
float alpha;
float b;
float result;
do {
printf("Type alpha and b. Space separated float numbers only.n");
if ( fgets ( input, sizeof input, stdin)) {
// Get user input
items = sscanf ( input, "%f %f%c", &alpha, &b, &nl);
}
else {
fprintf ( stderr, "fgets EOFn");
return 0;
}
} while ( 3 != items || 'n' != nl);
printf("%f %fn", alpha, b);
return 0;
}
Why not simply usescanf
?
– kfx
Nov 11 at 18:45
@kfx ifscanf
gets bad input such asabc
for a float, it leaves the bad input in the input stream. So you must clean the input stream.fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.
– user3121023
Nov 11 at 18:48
1
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
@M.M yes. could use"%f %f %c"
and just test thatitems
is 2. then any trailing whitespace is ok.
– user3121023
Nov 11 at 20:00
@user3121023 --"%f %f %c"
would match the newline before%c
is encountered, leavingnl
unassigned anditems
with a value of 2.
– David Bowling
Nov 11 at 20:04
|
show 3 more comments
up vote
0
down vote
accepted
As @John Bollinger (answer) and @chux (answer) kindly explained the question is wrong by itself, actually scanf
doesn't accept chars instead of floats but omitting it. To catch this behavior I've modified the code in the following way:
+ #include <errno.h> // Error codes constants
int main()
{
// Define variables
float alpha;
float b;
+ int matches;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
± matches = scanf("%f %f", &alpha, &b);
+ if (matches != 2) {
+ printf("ERROR: Space separated float numbers only expected.n");
+ return EINVAL;
+ }
printf("%f %fn", alpha, b);
return 0;
}
Appropriate only for simple learning programs you're writing during your CS degree!
Otherwise, check @chux's answer for a more production-like solution.
1
Minor: why hard code 22 and not usereturn EINVAL;
?
– chux
Nov 11 at 20:33
1
Detail:"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.
– chux
Nov 11 at 20:35
1
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
add a comment |
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
3
down vote
I'm preparing a simple program for my classes and found that scanf is
not as strict as I expected
No, you didn't.
Given this scanf
call:
float alpha;
float b;
scanf("%f %f", &alpha, &b);
... and this input:
a 0
... scanf
has a matching failure when it encounters the 'a' while trying to scan a floating-point value and not having yet scanned any decimal digits. It stops at that point (and leaves the 'a' in the stream for a subsequent read), and, as always, it returns the number of input fields successfully scanned (0).
Where I can read about its behavior?
You could try running the command man scanf
at the command line (Linux, OSX, ...), or entering the same as a Google search. Or google "scanf docs" or "scanf manual" or similar. Or look up the official manual for your particular C library. For standard library functions, the standard is an excellent reference, but your particular implementation may have extensions not documented there, or occasionally may even differ from the standard in minor ways.
How can I make input strict with standard functions and throw an
exception if there was neither ints nor floats?
C does not have exceptions. It tells you about errors via function return values, for the most part, though some third-party libraries may do it slightly differently. But you have to do your part, by checking the return values and responding appropriately. In this particular case, you must avoid reading the values of alpha
and b
. Because those variables were not initialized and did not subsequently have any values assigned to them, reading their values produces undefined behavior.
1
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions seterrno
under some circumstances.
– David Bowling
Nov 11 at 19:04
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
1
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that whenscanf
reports fewer than 2 matches (it will not report more).
– John Bollinger
Nov 12 at 11:53
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
add a comment |
up vote
3
down vote
I'm preparing a simple program for my classes and found that scanf is
not as strict as I expected
No, you didn't.
Given this scanf
call:
float alpha;
float b;
scanf("%f %f", &alpha, &b);
... and this input:
a 0
... scanf
has a matching failure when it encounters the 'a' while trying to scan a floating-point value and not having yet scanned any decimal digits. It stops at that point (and leaves the 'a' in the stream for a subsequent read), and, as always, it returns the number of input fields successfully scanned (0).
Where I can read about its behavior?
You could try running the command man scanf
at the command line (Linux, OSX, ...), or entering the same as a Google search. Or google "scanf docs" or "scanf manual" or similar. Or look up the official manual for your particular C library. For standard library functions, the standard is an excellent reference, but your particular implementation may have extensions not documented there, or occasionally may even differ from the standard in minor ways.
How can I make input strict with standard functions and throw an
exception if there was neither ints nor floats?
C does not have exceptions. It tells you about errors via function return values, for the most part, though some third-party libraries may do it slightly differently. But you have to do your part, by checking the return values and responding appropriately. In this particular case, you must avoid reading the values of alpha
and b
. Because those variables were not initialized and did not subsequently have any values assigned to them, reading their values produces undefined behavior.
1
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions seterrno
under some circumstances.
– David Bowling
Nov 11 at 19:04
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
1
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that whenscanf
reports fewer than 2 matches (it will not report more).
– John Bollinger
Nov 12 at 11:53
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
add a comment |
up vote
3
down vote
up vote
3
down vote
I'm preparing a simple program for my classes and found that scanf is
not as strict as I expected
No, you didn't.
Given this scanf
call:
float alpha;
float b;
scanf("%f %f", &alpha, &b);
... and this input:
a 0
... scanf
has a matching failure when it encounters the 'a' while trying to scan a floating-point value and not having yet scanned any decimal digits. It stops at that point (and leaves the 'a' in the stream for a subsequent read), and, as always, it returns the number of input fields successfully scanned (0).
Where I can read about its behavior?
You could try running the command man scanf
at the command line (Linux, OSX, ...), or entering the same as a Google search. Or google "scanf docs" or "scanf manual" or similar. Or look up the official manual for your particular C library. For standard library functions, the standard is an excellent reference, but your particular implementation may have extensions not documented there, or occasionally may even differ from the standard in minor ways.
How can I make input strict with standard functions and throw an
exception if there was neither ints nor floats?
C does not have exceptions. It tells you about errors via function return values, for the most part, though some third-party libraries may do it slightly differently. But you have to do your part, by checking the return values and responding appropriately. In this particular case, you must avoid reading the values of alpha
and b
. Because those variables were not initialized and did not subsequently have any values assigned to them, reading their values produces undefined behavior.
I'm preparing a simple program for my classes and found that scanf is
not as strict as I expected
No, you didn't.
Given this scanf
call:
float alpha;
float b;
scanf("%f %f", &alpha, &b);
... and this input:
a 0
... scanf
has a matching failure when it encounters the 'a' while trying to scan a floating-point value and not having yet scanned any decimal digits. It stops at that point (and leaves the 'a' in the stream for a subsequent read), and, as always, it returns the number of input fields successfully scanned (0).
Where I can read about its behavior?
You could try running the command man scanf
at the command line (Linux, OSX, ...), or entering the same as a Google search. Or google "scanf docs" or "scanf manual" or similar. Or look up the official manual for your particular C library. For standard library functions, the standard is an excellent reference, but your particular implementation may have extensions not documented there, or occasionally may even differ from the standard in minor ways.
How can I make input strict with standard functions and throw an
exception if there was neither ints nor floats?
C does not have exceptions. It tells you about errors via function return values, for the most part, though some third-party libraries may do it slightly differently. But you have to do your part, by checking the return values and responding appropriately. In this particular case, you must avoid reading the values of alpha
and b
. Because those variables were not initialized and did not subsequently have any values assigned to them, reading their values produces undefined behavior.
answered Nov 11 at 18:55
John Bollinger
77.2k63872
77.2k63872
1
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions seterrno
under some circumstances.
– David Bowling
Nov 11 at 19:04
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
1
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that whenscanf
reports fewer than 2 matches (it will not report more).
– John Bollinger
Nov 12 at 11:53
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
add a comment |
1
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions seterrno
under some circumstances.
– David Bowling
Nov 11 at 19:04
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
1
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that whenscanf
reports fewer than 2 matches (it will not report more).
– John Bollinger
Nov 12 at 11:53
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
1
1
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions set
errno
under some circumstances.– David Bowling
Nov 11 at 19:04
C does not have exceptions in the sense that OP is thinking of, but C does have a concept of exceptional conditions, e.g. floating point exceptions and integer overflow. Also, some functions set
errno
under some circumstances.– David Bowling
Nov 11 at 19:04
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
Thanks a lot for your explanation! So, if I get it right, I can just check is I have exactly two matches and return 22 otherwise.
– terales
Nov 11 at 20:08
1
1
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that when
scanf
reports fewer than 2 matches (it will not report more).– John Bollinger
Nov 12 at 11:53
@terales, yes, you check whether you have exactly two matches. Any different result tells you not only that some fields were not parsed, but which ones. You may safely use the ones that were parsed. I'm not sure were returning 22 comes from, but if that's what you're supposed to do in the event of incorrect input, then yes, do that when
scanf
reports fewer than 2 matches (it will not report more).– John Bollinger
Nov 12 at 11:53
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
@JohnBollinger thanks a lot! 22 is code of EINVAL, sorry for not being clear there.
– terales
Nov 12 at 16:18
add a comment |
up vote
3
down vote
Others answers, especially @John Bollinger well explain why code fails to meet the goal.
Note input may converter to a int
, float
, neither, or both.
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
The best is to use other tools like fgets()
to read a line of input and form a string for later testing.
To test strictly for is a bit hard. *scanf("%d",...)
has undefined behavior on overflow. *scanf("%f",...)
has similar UB, especially when float
does not support infinity/not-a-number.
To test if a string convert to a valid int
bool my_isint(const char *s) {
// Add to dis-allow leading white-space
if (isspace((unsigned char) *s)) return false;
char *endptr;
base = 0; // use base = 0 to only allow base 10 input
errno = 0;
long val = strtol(s, &endptr, base);
if (s == endptr) return false; // no conversion
if (errno == ERANGE) return false; // too big for long
if (val > INT_MAX || val < INT_MIN) return false; // too big for int
// Add to allow trailing white-space
while (isspace((unsigned char) *endptr)) endptr++;
// Add to dis-allow trailing junk
while (*endptr) return false; // trailing junk
return true;
}
To test if a string converts to a valid float
is like testing for double
when float
supports infinity/non-a-number. More later- GTG.
1
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
2
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it justif (sscanf(buf, "%d",...) == 1)
andif (sscanf(buf, "%f",...) == 1)
.
– chux
Nov 11 at 20:15
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
add a comment |
up vote
3
down vote
Others answers, especially @John Bollinger well explain why code fails to meet the goal.
Note input may converter to a int
, float
, neither, or both.
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
The best is to use other tools like fgets()
to read a line of input and form a string for later testing.
To test strictly for is a bit hard. *scanf("%d",...)
has undefined behavior on overflow. *scanf("%f",...)
has similar UB, especially when float
does not support infinity/not-a-number.
To test if a string convert to a valid int
bool my_isint(const char *s) {
// Add to dis-allow leading white-space
if (isspace((unsigned char) *s)) return false;
char *endptr;
base = 0; // use base = 0 to only allow base 10 input
errno = 0;
long val = strtol(s, &endptr, base);
if (s == endptr) return false; // no conversion
if (errno == ERANGE) return false; // too big for long
if (val > INT_MAX || val < INT_MIN) return false; // too big for int
// Add to allow trailing white-space
while (isspace((unsigned char) *endptr)) endptr++;
// Add to dis-allow trailing junk
while (*endptr) return false; // trailing junk
return true;
}
To test if a string converts to a valid float
is like testing for double
when float
supports infinity/non-a-number. More later- GTG.
1
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
2
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it justif (sscanf(buf, "%d",...) == 1)
andif (sscanf(buf, "%f",...) == 1)
.
– chux
Nov 11 at 20:15
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
add a comment |
up vote
3
down vote
up vote
3
down vote
Others answers, especially @John Bollinger well explain why code fails to meet the goal.
Note input may converter to a int
, float
, neither, or both.
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
The best is to use other tools like fgets()
to read a line of input and form a string for later testing.
To test strictly for is a bit hard. *scanf("%d",...)
has undefined behavior on overflow. *scanf("%f",...)
has similar UB, especially when float
does not support infinity/not-a-number.
To test if a string convert to a valid int
bool my_isint(const char *s) {
// Add to dis-allow leading white-space
if (isspace((unsigned char) *s)) return false;
char *endptr;
base = 0; // use base = 0 to only allow base 10 input
errno = 0;
long val = strtol(s, &endptr, base);
if (s == endptr) return false; // no conversion
if (errno == ERANGE) return false; // too big for long
if (val > INT_MAX || val < INT_MIN) return false; // too big for int
// Add to allow trailing white-space
while (isspace((unsigned char) *endptr)) endptr++;
// Add to dis-allow trailing junk
while (*endptr) return false; // trailing junk
return true;
}
To test if a string converts to a valid float
is like testing for double
when float
supports infinity/non-a-number. More later- GTG.
Others answers, especially @John Bollinger well explain why code fails to meet the goal.
Note input may converter to a int
, float
, neither, or both.
How can I make input strict with standard functions and throw an exception if there was neither ints nor floats?
The best is to use other tools like fgets()
to read a line of input and form a string for later testing.
To test strictly for is a bit hard. *scanf("%d",...)
has undefined behavior on overflow. *scanf("%f",...)
has similar UB, especially when float
does not support infinity/not-a-number.
To test if a string convert to a valid int
bool my_isint(const char *s) {
// Add to dis-allow leading white-space
if (isspace((unsigned char) *s)) return false;
char *endptr;
base = 0; // use base = 0 to only allow base 10 input
errno = 0;
long val = strtol(s, &endptr, base);
if (s == endptr) return false; // no conversion
if (errno == ERANGE) return false; // too big for long
if (val > INT_MAX || val < INT_MIN) return false; // too big for int
// Add to allow trailing white-space
while (isspace((unsigned char) *endptr)) endptr++;
// Add to dis-allow trailing junk
while (*endptr) return false; // trailing junk
return true;
}
To test if a string converts to a valid float
is like testing for double
when float
supports infinity/non-a-number. More later- GTG.
answered Nov 11 at 19:36
chux
79.5k869146
79.5k869146
1
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
2
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it justif (sscanf(buf, "%d",...) == 1)
andif (sscanf(buf, "%f",...) == 1)
.
– chux
Nov 11 at 20:15
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
add a comment |
1
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
2
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it justif (sscanf(buf, "%d",...) == 1)
andif (sscanf(buf, "%f",...) == 1)
.
– chux
Nov 11 at 20:15
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
1
1
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
Oh my goodness! Thanks a lot, this gives me an idea about the underneath complexity. This is a totally manual approach which I feel is more supposed to be used in production rather in learning apps for sake of algorithms exploration.
– terales
Nov 11 at 19:52
2
2
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it just
if (sscanf(buf, "%d",...) == 1)
and if (sscanf(buf, "%f",...) == 1)
.– chux
Nov 11 at 20:15
@terales Post did ask for "make input strict with standard functions". I saw that as seeking a robust solution beyond a learner's debut. Else is it just
if (sscanf(buf, "%d",...) == 1)
and if (sscanf(buf, "%f",...) == 1)
.– chux
Nov 11 at 20:15
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
Thanks, @chux, I would try to be more clear the next time. I've added your and John's info in the final answer.
– terales
Nov 11 at 20:19
add a comment |
up vote
1
down vote
fgets
can be used to read a line. Parse the line with sscanf
. sscanf
will return the number of items successfully scanned. This also captures the character following the second float. If it is not a newline, the loop continues until two floats followed by a newline are scanned.
#include <stdio.h>
#include <stdlib.h>
int main( void) {
char input[200] = "";
char nl = 0;
int items = 3;
float alpha;
float b;
float result;
do {
printf("Type alpha and b. Space separated float numbers only.n");
if ( fgets ( input, sizeof input, stdin)) {
// Get user input
items = sscanf ( input, "%f %f%c", &alpha, &b, &nl);
}
else {
fprintf ( stderr, "fgets EOFn");
return 0;
}
} while ( 3 != items || 'n' != nl);
printf("%f %fn", alpha, b);
return 0;
}
Why not simply usescanf
?
– kfx
Nov 11 at 18:45
@kfx ifscanf
gets bad input such asabc
for a float, it leaves the bad input in the input stream. So you must clean the input stream.fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.
– user3121023
Nov 11 at 18:48
1
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
@M.M yes. could use"%f %f %c"
and just test thatitems
is 2. then any trailing whitespace is ok.
– user3121023
Nov 11 at 20:00
@user3121023 --"%f %f %c"
would match the newline before%c
is encountered, leavingnl
unassigned anditems
with a value of 2.
– David Bowling
Nov 11 at 20:04
|
show 3 more comments
up vote
1
down vote
fgets
can be used to read a line. Parse the line with sscanf
. sscanf
will return the number of items successfully scanned. This also captures the character following the second float. If it is not a newline, the loop continues until two floats followed by a newline are scanned.
#include <stdio.h>
#include <stdlib.h>
int main( void) {
char input[200] = "";
char nl = 0;
int items = 3;
float alpha;
float b;
float result;
do {
printf("Type alpha and b. Space separated float numbers only.n");
if ( fgets ( input, sizeof input, stdin)) {
// Get user input
items = sscanf ( input, "%f %f%c", &alpha, &b, &nl);
}
else {
fprintf ( stderr, "fgets EOFn");
return 0;
}
} while ( 3 != items || 'n' != nl);
printf("%f %fn", alpha, b);
return 0;
}
Why not simply usescanf
?
– kfx
Nov 11 at 18:45
@kfx ifscanf
gets bad input such asabc
for a float, it leaves the bad input in the input stream. So you must clean the input stream.fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.
– user3121023
Nov 11 at 18:48
1
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
@M.M yes. could use"%f %f %c"
and just test thatitems
is 2. then any trailing whitespace is ok.
– user3121023
Nov 11 at 20:00
@user3121023 --"%f %f %c"
would match the newline before%c
is encountered, leavingnl
unassigned anditems
with a value of 2.
– David Bowling
Nov 11 at 20:04
|
show 3 more comments
up vote
1
down vote
up vote
1
down vote
fgets
can be used to read a line. Parse the line with sscanf
. sscanf
will return the number of items successfully scanned. This also captures the character following the second float. If it is not a newline, the loop continues until two floats followed by a newline are scanned.
#include <stdio.h>
#include <stdlib.h>
int main( void) {
char input[200] = "";
char nl = 0;
int items = 3;
float alpha;
float b;
float result;
do {
printf("Type alpha and b. Space separated float numbers only.n");
if ( fgets ( input, sizeof input, stdin)) {
// Get user input
items = sscanf ( input, "%f %f%c", &alpha, &b, &nl);
}
else {
fprintf ( stderr, "fgets EOFn");
return 0;
}
} while ( 3 != items || 'n' != nl);
printf("%f %fn", alpha, b);
return 0;
}
fgets
can be used to read a line. Parse the line with sscanf
. sscanf
will return the number of items successfully scanned. This also captures the character following the second float. If it is not a newline, the loop continues until two floats followed by a newline are scanned.
#include <stdio.h>
#include <stdlib.h>
int main( void) {
char input[200] = "";
char nl = 0;
int items = 3;
float alpha;
float b;
float result;
do {
printf("Type alpha and b. Space separated float numbers only.n");
if ( fgets ( input, sizeof input, stdin)) {
// Get user input
items = sscanf ( input, "%f %f%c", &alpha, &b, &nl);
}
else {
fprintf ( stderr, "fgets EOFn");
return 0;
}
} while ( 3 != items || 'n' != nl);
printf("%f %fn", alpha, b);
return 0;
}
answered Nov 11 at 18:35
user3121023
5,41741113
5,41741113
Why not simply usescanf
?
– kfx
Nov 11 at 18:45
@kfx ifscanf
gets bad input such asabc
for a float, it leaves the bad input in the input stream. So you must clean the input stream.fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.
– user3121023
Nov 11 at 18:48
1
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
@M.M yes. could use"%f %f %c"
and just test thatitems
is 2. then any trailing whitespace is ok.
– user3121023
Nov 11 at 20:00
@user3121023 --"%f %f %c"
would match the newline before%c
is encountered, leavingnl
unassigned anditems
with a value of 2.
– David Bowling
Nov 11 at 20:04
|
show 3 more comments
Why not simply usescanf
?
– kfx
Nov 11 at 18:45
@kfx ifscanf
gets bad input such asabc
for a float, it leaves the bad input in the input stream. So you must clean the input stream.fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.
– user3121023
Nov 11 at 18:48
1
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
@M.M yes. could use"%f %f %c"
and just test thatitems
is 2. then any trailing whitespace is ok.
– user3121023
Nov 11 at 20:00
@user3121023 --"%f %f %c"
would match the newline before%c
is encountered, leavingnl
unassigned anditems
with a value of 2.
– David Bowling
Nov 11 at 20:04
Why not simply use
scanf
?– kfx
Nov 11 at 18:45
Why not simply use
scanf
?– kfx
Nov 11 at 18:45
@kfx if
scanf
gets bad input such as abc
for a float, it leaves the bad input in the input stream. So you must clean the input stream. fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.– user3121023
Nov 11 at 18:48
@kfx if
scanf
gets bad input such as abc
for a float, it leaves the bad input in the input stream. So you must clean the input stream. fgets
will read everything from the input stream up to the size of the input array or a newline. So on bad input, the input stream has already been cleaned.– user3121023
Nov 11 at 18:48
1
1
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
This newline scan fails if they enter other whitespace before the newline
– M.M
Nov 11 at 19:49
@M.M yes. could use
"%f %f %c"
and just test that items
is 2. then any trailing whitespace is ok.– user3121023
Nov 11 at 20:00
@M.M yes. could use
"%f %f %c"
and just test that items
is 2. then any trailing whitespace is ok.– user3121023
Nov 11 at 20:00
@user3121023 --
"%f %f %c"
would match the newline before %c
is encountered, leaving nl
unassigned and items
with a value of 2.– David Bowling
Nov 11 at 20:04
@user3121023 --
"%f %f %c"
would match the newline before %c
is encountered, leaving nl
unassigned and items
with a value of 2.– David Bowling
Nov 11 at 20:04
|
show 3 more comments
up vote
0
down vote
accepted
As @John Bollinger (answer) and @chux (answer) kindly explained the question is wrong by itself, actually scanf
doesn't accept chars instead of floats but omitting it. To catch this behavior I've modified the code in the following way:
+ #include <errno.h> // Error codes constants
int main()
{
// Define variables
float alpha;
float b;
+ int matches;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
± matches = scanf("%f %f", &alpha, &b);
+ if (matches != 2) {
+ printf("ERROR: Space separated float numbers only expected.n");
+ return EINVAL;
+ }
printf("%f %fn", alpha, b);
return 0;
}
Appropriate only for simple learning programs you're writing during your CS degree!
Otherwise, check @chux's answer for a more production-like solution.
1
Minor: why hard code 22 and not usereturn EINVAL;
?
– chux
Nov 11 at 20:33
1
Detail:"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.
– chux
Nov 11 at 20:35
1
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
add a comment |
up vote
0
down vote
accepted
As @John Bollinger (answer) and @chux (answer) kindly explained the question is wrong by itself, actually scanf
doesn't accept chars instead of floats but omitting it. To catch this behavior I've modified the code in the following way:
+ #include <errno.h> // Error codes constants
int main()
{
// Define variables
float alpha;
float b;
+ int matches;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
± matches = scanf("%f %f", &alpha, &b);
+ if (matches != 2) {
+ printf("ERROR: Space separated float numbers only expected.n");
+ return EINVAL;
+ }
printf("%f %fn", alpha, b);
return 0;
}
Appropriate only for simple learning programs you're writing during your CS degree!
Otherwise, check @chux's answer for a more production-like solution.
1
Minor: why hard code 22 and not usereturn EINVAL;
?
– chux
Nov 11 at 20:33
1
Detail:"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.
– chux
Nov 11 at 20:35
1
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
add a comment |
up vote
0
down vote
accepted
up vote
0
down vote
accepted
As @John Bollinger (answer) and @chux (answer) kindly explained the question is wrong by itself, actually scanf
doesn't accept chars instead of floats but omitting it. To catch this behavior I've modified the code in the following way:
+ #include <errno.h> // Error codes constants
int main()
{
// Define variables
float alpha;
float b;
+ int matches;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
± matches = scanf("%f %f", &alpha, &b);
+ if (matches != 2) {
+ printf("ERROR: Space separated float numbers only expected.n");
+ return EINVAL;
+ }
printf("%f %fn", alpha, b);
return 0;
}
Appropriate only for simple learning programs you're writing during your CS degree!
Otherwise, check @chux's answer for a more production-like solution.
As @John Bollinger (answer) and @chux (answer) kindly explained the question is wrong by itself, actually scanf
doesn't accept chars instead of floats but omitting it. To catch this behavior I've modified the code in the following way:
+ #include <errno.h> // Error codes constants
int main()
{
// Define variables
float alpha;
float b;
+ int matches;
float result;
// Get user input
printf("Type alpha and b. Space separated float numbers only.n");
± matches = scanf("%f %f", &alpha, &b);
+ if (matches != 2) {
+ printf("ERROR: Space separated float numbers only expected.n");
+ return EINVAL;
+ }
printf("%f %fn", alpha, b);
return 0;
}
Appropriate only for simple learning programs you're writing during your CS degree!
Otherwise, check @chux's answer for a more production-like solution.
edited Nov 11 at 21:57
answered Nov 11 at 20:24
terales
1,6641525
1,6641525
1
Minor: why hard code 22 and not usereturn EINVAL;
?
– chux
Nov 11 at 20:33
1
Detail:"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.
– chux
Nov 11 at 20:35
1
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
add a comment |
1
Minor: why hard code 22 and not usereturn EINVAL;
?
– chux
Nov 11 at 20:33
1
Detail:"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.
– chux
Nov 11 at 20:35
1
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
1
1
Minor: why hard code 22 and not use
return EINVAL;
?– chux
Nov 11 at 20:33
Minor: why hard code 22 and not use
return EINVAL;
?– chux
Nov 11 at 20:33
1
1
Detail:
"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.– chux
Nov 11 at 20:35
Detail:
"%f %f"
will not insure "Space separated float numbers". Try "123.4-567.8". If space separation is required, additional code needed.– chux
Nov 11 at 20:35
1
1
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
— "Minor: why hard code 22 and not use return EINVAL;?" — Thanks! I just didn't know it's possible. Space separation is optional there, the main point is to prevent wrong calculations. Thanks a lot @chux!
– terales
Nov 11 at 20:43
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53251744%2fwhy-scanf-accepts-chars-for-f-format-specifier%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
3
How can I .. throw an exception - There are no exceptions in C.
– kfx
Nov 11 at 18:18
9
You could start by checking the return value from
scanf
to see if it read anything at all or not.– Retired Ninja
Nov 11 at 18:18
4
"Where I can read about its behavior?" -- the best place is the Standard
– David Bowling
Nov 11 at 18:18
3
... or the documentation for your C library. On a Unix-flavored system, you can find that in its manual page (
man scanf
). For the Microsoft C library, look at the online docs. Etc.– John Bollinger
Nov 11 at 18:31
1
Better to post your own answer below as an answer rather than in your question. See Can I answer my own question?. Recommend to roll-back your edit.
– chux
Nov 11 at 20:19