简体   繁体   中英

infinite loop fscanf string textfile c programming

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.

The scanf() family of functions are a torture test that should not be inflicted on novice programmers. They're incredibly difficult to use accurately.

Analysis

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.

Infinite loop

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.)

Synthesis

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.

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
}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM