-1

I've been given a task to read space separated float values from a data.txt file in C.

The file looks like this...

0.329412 0.800000 0.800000 0.290196
0.329412 0.800000 0.800000 0.290196 
0.329412 0.800000 0.800000 0.290196
0.329412 0.800000 0.800000 0.290196 
0.796078 0.800000 0.800000 0.796078 
0.796078 0.800000 0.800000 0.796078 
0.796078 0.800000 0.800000 0.796078 
0.796078 0.800000 0.800000 0.796078 
0.796078 0.800000 0.800000 0.796078 
0.796078 0.800000 0.800000 0.796078 
0.329412 0.800000 0.800000 0.290196 
0.329412 0.800000 0.800000 0.290196 
0.329412 0.800000 0.800000 0.290196 
0.329412 0.800000 0.800000 0.290196 
0.329412 0.800000 0.800000 0.290196 

The middle two rows are constant. The task is to find when the 1st and 4th row are both in the range of 0.7 or above and keep a count of it. This is just a snippet of the file but here they're going above 0.7 for sometime so the count increments by one. The actual file has thousands of lines but only four columns.

I've tried it like this:

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

int main()
{
  float arr[4000][4];
  int i, j, vals =0, count = 0;

  FILE *fpointer;
  char filename[10];
  printf("Enter the name of the file to be read: ");
  scanf("%s",filename);
  fpointer = fopen(filename, "r");
  if (fpointer == NULL)
  {
    printf("Cannot open file \n");
    exit(1);
  }

  while(!feof(fpointer))
  {
    for(i=0; i<4000; i++)
    {
        for(j=0; j<4; j++)
        {
            fscanf(fpointer, " %f ", &arr[i][j]);
        }

        if (arr[i][0] >= 0.7 && arr[i][3] >= 0.7)
            vals += 1;
        else if (arr[i-1][0] >= 0.7 && arr[i-1][3] >= 0.7)
            count += 1;
    }
   }

  printf("number of counts: %d", count);

  fclose(fpointer);
}

But I've been told to read the file line by line and then evaluate instead of storing into a large array as the program might crash if it's a large file.

Can you please assist me in doing so? I have similar larger files and I'm not sure how many lines they have.

Please let me know how can I read the values line by line & evaluate it at the same time.

Thank you in advance.

  • You are already evaluating per line. Just make it `arr[4]` and get rid of the `i` loop. Then I don't understand what you're doing with the previous row with `arr[i-1]` as you don't describe that. And on the first iteration you read out of bounds. The code is a bit of a mess. – Cheatah May 14 '20 at 05:58
  • O_O Why store it in strings? Why not use fwrite to store the floats directly in binary? –  May 14 '20 at 06:45

1 Answers1

4

Take a look to Why is “while ( !feof (file) )” always wrong?

Instead loop while fscanf gives you valid results, and since the central columns are constant you can skip them using the %*f specifier:

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

int main(void)
{
    // char filename[9];
    char filename[128]; // Don't be stingy, use more RAM :)
    FILE *fpointer;

    printf("Enter the name of the file to be read: ");
    scanf("%127s", filename);
    fpointer = fopen(filename, "r");
    if (fpointer == NULL)
    {
        printf("Cannot open file \n");
        exit(EXIT_FAILURE);
    }

    int count = 0;
    float arr[2];

    while (fscanf(fpointer, "%f %*f %*f %f", &arr[0], &arr[1]) == 2)
    {
        if ((arr[0] >= 0.7) && (arr[1] >= 0.7))
        {
            count++;
        }
    }
    printf("number of counts: %d\n", count);
    fclose(fpointer);
    return 0;
}

A safer version (as pointed out by @DavidC.Rankin in comments) using fgets and sscanf:

int count = 0;
char str[256];
float arr[2];

while (fgets(str, sizeof str, fpointer) != NULL)
{
    sscanf(str, "%f %*f %*f %f", &arr[0], &arr[1]);
    if ((arr[0] >= 0.7) && (arr[1] >= 0.7))
    {
        count++;
    }
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
  • 2
    Yep that works. May want to mention the benefit of reading an entire line at a time with `fgets()` and then use `sscanf` with the same format string to avoid a stray character or invalid line causing the read to fail. If the format of the input file can be guaranteed -- then it's a wash... – David C. Rankin May 14 '20 at 06:37
  • @DavidC.Rankin I totally agree, I didn't want to introduce more code than what the OP was using, but I put it as a foot-note – David Ranieri May 14 '20 at 06:41