0

I'm writing a program in C, that is supposed to read arrays of doubles from files of arbitrary length. How to stop it at EOF? I've tried using feof, but then read the discussions:

Why is “while ( !feof (file) )” always wrong?

How does C handle EOF?

Then again they concern strings, not numbers. So when reading a file of the form "4 23.3 2 1.2", how to state the loop condition, so that my array A has all the numbers from the file and nothing more (also the iterator N = length of A)?

Here's the part of my code with feof, which produces one entry too many in A. The reallocation part is based on http://www.cplusplus.com/reference/cstdlib/realloc/ example.

int N = 0;    

double *A = NULL;
double *more_space;
double buff = 0;

FILE *data;
data = fopen(data.dat,"r");

while(feof(data) == 0) {
    fscanf(data, "%lg", &buff);
    more_space = realloc(A, (N+1)*sizeof(double));
    A = more_space;
    A[N] = buff;
    N++;
}
2
  • try reading a large buffer at a time , and than scanfing it... Commented Jan 9, 2014 at 13:46
  • 1
    while(!feof(stream)) { ... } is wrong because of a logic problem, its not specific to strings or numbers. The logical pseudocode should be while (there is more data) { do somewthing with the data } When there is no more data, the loop terminates. Only at that point does it really make sense to check feof. For example, if your loop finished but you didn't make it to the end, maybe there is some invalid data in your file, or maybe a read error occured Commented Jan 9, 2014 at 13:58

5 Answers 5

1

The return value of fscanf is -1 when you hit eof (or other problems) so try while(fscanf(…) >= 0) for your outer loop. (Whether you accept a zero return value or not depends on how you want to handle bad data -- as other posters have pointed out, you will get 0 if no numbers are converted.

I like using the 'greater than or equals' test (instead of testing for ==1) because it doesn't break if you change the scanf format to, say, read two items from the input line. On the other hand, you could argue that it's better to verify that you always read exactly the correct number of arguments, and it's better to have your program 'fail fast' as soon as you change the number of scant arguments, than to have some mysterious failure later on, if you get bad input. It's a matter of style, and whether this is throwaway code for an assignment, or production code..

Sign up to request clarification or add additional context in comments.

4 Comments

All references say it returns EOF, assuming EOF has a particular value like -1 is wrong
@Brandin true, but I'm not sure why you are appending this comment to my post: I didn't say to test against -1, I said to use a greater than 0 (or greater than 1) check. The standard does guarantee that whatever EOF is, it will be negative.. (and any other return values from fscanf are 0 or positive)
its related to the post. Rather than using >= x, personally I like to use an extra parameter in the format say "%f %f %f %c" and then make sure the return value is 3. That way you're sure there is no extra "garbage" after the data you are interested in.
@brandin +1 interesting idea! (the extra %c) -- Now that I've learned something new for the day, I can go take a nap. :^)
1

During the scan, save the results of fscanf()

int cnt;
double d;
while ((cnt = fscanf("%f", &d)) == 1) {
  more_space = realloc(A, (N+1)*sizeof(double));
  if (more_space == NULL) Handle_MemoryError();
  A = more_space;
  A[N] = buff;
  N++;
}
if (cnt == 0) Handle_BadDataError();

Comments

1

Just stop when fscanf tells you there is no more data to be read. Its return value indicates the number of items it read or you get EOF if you reach end of file or there is a read error. Therefore, since you are reading only one item in each call, you will get 1 so long as reading is successful.

while (fscanf(data, "%lg", &buff) == 1) {
    ...
}

You may want to store the return value in a variable to verify whether reading stopped due to end-of-file or because the double parsing failed.

1 Comment

fscanf returns EOF even if the end of the file has not yet been reached. For example if a matching error occurs or if the file can't be read for some other reason.
0

You should do:

while (fscanf(data, "%lg", &buff) == 1)

That way if you hit a "non number" then it'll stop instead of loop infinitely!! ... And fscanf will check for EOF and it'll break the loop for you.

Comments

0

Alternatively to other answers, read the entire file:

int32_t readFile ( char* filename, uint8_t** contentPtr, int32_t* sizePtr)
{
  int32_t ret = 0;
  struct stat st;
  FILE *file = NULL;
  uint8_t* content = NULL;

  memset ( &st, 0, sizeof ( struct stat ) );

  ret = stat( filename, &st );
  if( ret < 0 ) {
     return -1;
  }

  file = fopen64(filename, "rb");
  if ( file == NULL ) {
    return -1;
  }

  content = calloc ( st.st_size+10, sizeof ( uint8_t ) );

  ret = fread ( content, 1, st.st_size, file );
  fclose( file );
  if( ret != st.st_size ) {
    free(content);

    return -1;
  }

  *contentPtr = content;
  if (sizePtr != NULL) {
    *sizePtr = st.st_size;
  }

  return 0;
}

And then process the contents of the buffer with sscanf().

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.