简体   繁体   中英

C - fscanf raises EOF before end-of-file

I am writing a C code to read floating point numbers from a text file. The text file looks like this:

202.75 47.22 141.20
202.75 47.22 -303.96
202.75 47.22 -301.67
202.75 47.22 482.42
...

There are 19973 lines in this file and the C code snippet that reads the text file is

nLinesToRead = 19973;
x  = (float *)calloc(nLinesToRead, sizeof(float));
y = (float *)calloc(nLinesToRead, sizeof(float));
z  = (float *)calloc(nLinesToRead, sizeof(float));
ptr = fopen(fileName, "r");
for(i=0; i<nLinesToRead; i++)   {
    status = fscanf(ptr, "%f%f%f", &x[i], &y[i], &z[i]);
    if(feof(ptr) && i<nLinesToRead)
        printf("\nERROR: encountered unexpected EOF in line %d", i+1);
    if(status != 3) {
        printf("\nERROR: Error reading valid pixels from the disk at line %d with status %d and %d\n", i+1, status, feof(ptr));
        printf("\nEOF is %d\n", EOF);
        exit(FAILURE);
    }
}

The output of this code is

ERROR: encountered unexpected EOF in line 19940
ERROR: encountered unexpected EOF in line 19941
ERROR: Error reading valid pixels from the disk at line 19941 with status -1 and 0

indicating that fscanf is encountering EOF at an unexpected location. Looking at lines 19939 through 19942

202.21 47.23 -453.42
202.21 47.23 -445.81
202.21 47.23 -419.89
202.21 47.41 179.25

I don't see anything weird there.

Has anyone encountered this before?

While you are finding another computer, let me suggest another way to read the file instead of hardwiring a for loop to read X number of lines. Generally when you are reading lines of data, you are better off using line-oriented input methods like fgets or getline to read an entire line at a time into a buffer, and then parse the buffer to get the individual items you need. That way rather than trying to shoehorn your data into a fscanf read, you get the entire line every time, with any failure being limited to a parse of the buffer rather than the read of the file.

Below is a quick bit of code that seems to do what it is you are attempting to do. The only suggestion I would have is that when reading 3 common pieces of data that are associated, you are probably better off creating a struct that contains the 3 members rather than creating 3 separate arrays to hold the data. That will simplify passing the data to functions, etc.. Either way works, so it is up to you. Let me know if you have questions:

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

#define MAXL 48
#define MAXF 20000

int main (int argc, char **argv) {

    if (argc < 2 ) {
        fprintf (stderr, "error: insufficient input, usage: %s number\n", argv[0]);
        return 1;
    }

    FILE *fp = NULL;
    float *x = NULL;
    float *y = NULL;
    float *z = NULL;
    size_t idx = 0;
    char ln[MAXL] = {0};

    /* open file with filename given on command line */
    if (!(fp = fopen (argv[1], "r"))) {
        fprintf (stderr, "error: file open failed '%s'.", argv[1]);
        return 1;
    }

    /* allocate memory for arrays x, y, z (consider a struct) */
    if (!(x = calloc (MAXF, sizeof *x))) {
        fprintf (stderr, "error: virtual memory exhausted");
        return 1;
    }

    if (!(y = calloc (MAXF, sizeof *y))) {
        fprintf (stderr, "error: virtual memory exhausted");
        return 1;
    }

    if (!(z = calloc (MAXF, sizeof *z))) {
        fprintf (stderr, "error: virtual memory exhausted");
        return 1;
    }

    /* read each LINE in file and parse with sscanf for 3 floats */
    while (fgets (ln, MAXL, fp) != NULL)
    {
        if (sscanf (ln, "%f%f%f", &x[idx], &y[idx], &z[idx]) == 3) {
            idx++;
            if (idx == MAXF) {
                fprintf (stderr, "warning: %d lines read.\n", MAXF);
                break;
            }
        }
        else
            printf ("error: line %zu, failed to read 3 floats.\n", idx);
    }

    printf ("\n read '%zu' lines.\n\n", idx);

    size_t i = 0;
    for (i = 19938; i < 19942; i++)
        printf (" line[%zu] : %.2f %.2f %.2f\n", i + 1, x[i], y[i], z[i]);
    printf ("\n");

    free (x);
    free (y);
    free (z);

    fclose (fp);

    return 0;
}

Output

$ ./bin/fgets_sscanf_floats_dyn dat/testFile.txt

 read '19973' lines.

 line[19939] : 202.21 47.23 -453.42
 line[19940] : 202.21 47.23 -445.81
 line[19941] : 202.21 47.23 -419.89
 line[19942] : 202.21 47.41 179.25

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