Reputation: 69
Why is that when I scan a string in the text file it always goes into an infinite loop?
while(val = fscanf(stdin,"%lf%c",d,c) != EOF)
{if(val==0){//error}
else if(c='\n'){//error print char}
else{//print double}
}
Text file:
4.5
r5
23
s
What I want is to print all of it but it always give me an infinite loop when I reach the string.
Upvotes: 1
Views: 1797
Reputation: 753515
The scanf()
family of functions are a torture test that should not be inflicted on novice programmers. They're incredibly difficult to use accurately.
Even ignoring the code layout (completely appalling — that's a professional assessment) and assuming you have variable declarations like this:
double value;
double *d = &value;
char newline;
char *c = &newline;
int val;
rather than the more plausible:
double d;
char c;
int val;
your fragment has an incredible number of problems crammed into a few lines.
while(val = fscanf(stdin,"%lf%c",d,c) != EOF)
{if(val==0){//error}
else if(c='\n'){//error print char}
else{//print double}
}
You have assigned the result of a comparison to val
, instead of assigning the return value of fscanf()
to val
and comparing that with EOF.
while ((val = fscanf(stdin, "%lf%c", d, c)) != EOF)
Now the code is merely wrong; fscanf()
could return EOF (usually, but not guaranteed to be, -1
), or 0
, or 1
or 2
, and of these, only 2
is the answer you're looking for. So, the loop condition should be:
while ((val = fscanf(stdin, "%lf%c", d, c)) == 2)
Or, if you've got the simpler definitions, then it should be:
while ((val = fscanf(stdin, "%lf%c", &d, &c)) == 2)
Now you know two values were read. The if (val == 0)
check inside the loop is now redundant; you only enter the loop body when val == 2
.
You can check whether the value in *c
is a newline doing a comparison instead of an assignment:
if (*c == '\n')
(or if (c == '\n')
; let's assume you have the simpler declarations and forgot the &
characters in the original code.) However, it's an error if c
is not a newline, so in fact it should be a !=
test.
while ((val = fscanf(stdin, "%lf%c", &d, &c)) == 2)
{
if (c != '\n')
...print error...
else
printf("Number = %g\n", d);
}
After the loop, you could test for val == EOF
vs val == 0
vs val == 1
. The first would mean you've reached EOF or an error occurred; the second would mean that the next character in the input is neither white space nor part of a valid number (a letter or a punctuation character other than .
, +
, -
, for example). The val == 1
case is esoteric; it would require that the end of the file occurs after a number that has no newline (or any other character) following it.
The most likely cause of your infinite loop, incidentally, is an invalid (non-numeric, non-white space) character in the input. And, on closer inspection, I see that there's an r
on the second line of input; that would trigger an infinite loop with your code. fscanf()
would always return 0, which is not EOF, so the loop continues. (It can't read the r
with the %c
because it has to read a number successfully first.)
The %lf
format will skip any leading white space, including newlines, so your code is attempting to ensure that there is one number per line with no trailing white space. You'd probably do better in this context to use fgets()
and strtod()
, though using strtod()
completely correctly is not completely trivial. The following code ignores the finer points of strtod()
.
char line[4096];
double d;
while (fgets(line, sizeof(line), stdin) != 0)
{
char *end;
d = strtod(line, &end);
if (end == line || *end != '\n')
...incorrect format...
else
printf("Number = %g\n", d);
}
The only reasons for fgets()
to return a null pointer is that you've reached EOF or an error occurred. You might want to set errno = 0;
before the call to strtod()
and examine its value afterwards to spot numbers out of range.
Upvotes: 4
Reputation: 153338
Code goes into an infinite loop because fscanf(stdin,"%lf%c",d,c)
attempt to read a number and finds a letter: the r
in r5
. Upon failing to scan anything, it returns a 0
. The 0 != EOF
is true and true is assigned to val
. And while (val)
repeats. The problem is that the r
is not consumed by anything, so the next `fscanf() repeatedly tries again with the same result.
Recommend
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
result = sscanf(buffer, "%lf %c", &d, &c);
if (result != 1) ; //handle error
}
Upvotes: 1
Reputation: 409146
One problem is that you shouldn't try to attempt to scan the newline. Another problem is that the not-equal operator !=
has higher precedence than the assignment, meaning val
is the result of the comparison. And a third error in that you don't provide a pointer to read the value into (leading to undefined behavior).
I suggest changing like this:
while (scanf("%lf", &d) == 1)
{
printf("You have read %f\n", d);
}
The above loop will loop as long as the input is a floating point.
Upvotes: 0