fread() problem in c while reading floating point numbers from a file

681 views Asked by At

Libraries used

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

Creating a dataset with random floating-points and printing on a newly created file

void createdataset(int Datasetsize,char * filename)
{
  FILE *f;
  int su;
  float v[Datasetsize];    

  srand((unsigned int)time(NULL));

  for(int i = 1; i<=Datasetsize;i++) 
    *(v+i)=((float)rand()/(float)(RAND_MAX)) * 100;

  f=fopen(filename,"wb");
  su=fwrite(v ,sizeof(float) , Datasetsize , f);
  printf("%d\n",su);
  fclose(f);
}

Reading the newly created file using fread() and displaying the number of successful attempts. It always gives unsuccessful attempts like it reads 120 records from 1000 and the rest are corrupted. I need to resolve this issue.

void loadDataset (int DataSetSize, char *filename, float *v) 
{
  FILE *fp;
  int s;

  fp = fopen( filename , "r" );
  if( fp==NULL) 
    printf("File cant be opened");

  s=fread(v , sizeof(float), DataSetSize, fp );
  printf("%d\n",s);
  for( int i=0; i<DataSetSize; i++)
  {
    printf("\t%f",*(v+i));
  }

  fclose(fp);
}

Main function

void main()  
{ 
    char ch;
    FILE *fp;
    int datasetsize;
    char filein[50];
    char *fi=filein, ds; 

    printf("Enter the size of the datasetsize: ");
    scanf("%d",&datasetsize);

    float v[datasetsize];

    printf("%d\n",datasetsize);
    printf("Enter input file name: ");
    scanf("%s",filein);
    printf("%s\n",filein);
    createdataset(datasetsize,fi);
    loadDataset(datasetsize, fi, v);
}
2

There are 2 answers

0
bruno On

Including conio.h you are under Windows

doing

su=fwrite(v ,sizeof(float) , Datasetsize , f);
...
s=fread(v , sizeof(float), DataSetSize, fp );

you write and read binary, under windows to write and read binary file you need to use "wb" and "rb" so you need to replace

f=fopen(filename,"w");
...
fp = fopen( filename , "r" );

by

f=fopen(filename,"wb");
...
fp = fopen( filename , "rb" );

but see also remarks below


out of that :

In createdataset :

you do not check you was able to open the file, you need to check fp is not NULL, for instance using perror to indicate the reason :

if (fp == NULL)
{
  perror("cannot open file to write"); 
  exit(-1);
}

Also to do

*(v+i)=...

is not very readable to set the array elements, just do

v[i] = ...

In loadDataset you cannot do

if( fp==NULL) 
printf("File cant be opened");

and continue like there is no error, you need to stop the execution of the function doing a return or putting the rest in an else branch, and again you can use perror to indicate the problem :

if (fp == NULL)
{
   perror("cannot open the file to read");
   exit(-1);
}

Also to do

printf("\t%f",*(v+i));

is not very readable to access the array element, just do

printf("\t%f", v[i]);

In main :

scanf("%d",&datasetsize);

if the user does not input a valid int the behavior is undefined after because datasetsize is not set, better to do for instance :

if ((scanf("%d",&datasetsize) != 1) || (datasetsize < 1)) {
  puts("invalid size);
  return -1;
}

Also

char filein[50];
...
scanf("%s",filein);

has an undefined behavior if the user input more than 49 characters, do

 scanf("%49s",filein);

even it is also better to check scanfreturns 1 in case the stdin is redirected in an empty input file

0
Frankie_C On

The answer from Bruno points out the basic problems. As a demo I post the working code here because was not possible in comments:

#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
#include<time.h>
void createdataset(int Datasetsize, char *filename, float *v)
{
    FILE *f;
    int su;

    f = fopen(filename, "wb");
    if (!f)
    {
        printf("Error creating file. Program aborted...\n");
        abort();
    }

    printf("Writing %d entries to file \"%s\".\n", Datasetsize, filename);
    srand((unsigned int)time(NULL));
    for (int i = 1; i <= Datasetsize; i++)
    {
        *(v + i) = ((float)rand() / (float)(RAND_MAX)) * 100;
        printf("\t%f\n",*(v+i));
    }
    su = fwrite(v, sizeof(float), Datasetsize, f);
    printf("Wrote %d floats to file\n", su);
    fclose(f);
}

void loadDataset(int DataSetSize, char *filename, float *v)
{
    FILE *fp;
    int s;
    fp = fopen(filename, "rb");
    if (fp == NULL)
    {
        printf("File cant be opened");
        return;
    }

    s = fread(v, sizeof(float), DataSetSize, fp);
    printf("Read data set composed of %d entries.\n", s);
    for (int i = 0; i < DataSetSize; i++)
    {
        printf("\t%f\n", *(v + i));
    }

    fclose(fp);
}

int main(int argc, char *argv[])
{
    char ch;
    FILE *fp;
    int datasetsize;
    char filein[50];
    char *fi = filein, ds;

    printf("Enter the size of the datasetsize: ");
    scanf("%d", &datasetsize);
    printf("%d\n", datasetsize);

    float v_out[datasetsize];
    float v_in[datasetsize];

    printf("Enter input file name: ");
    scanf("%s", filein);
    printf("%s\n", filein);

    createdataset(datasetsize, fi, v_out);
    loadDataset(datasetsize, fi, v_in);

    int errors=0;
    for (int i=0; i<datasetsize; i++)
        if (v_in[i] != v_out[i])
        {
            printf("Error in/out in position %d, v_in=%f, v_out=%f\n", i, v_in[i], v_out[i]);
            errors++;
        }

    printf("Completed with %d error(s).\n", errors);
}

I fixed prints for a more readable apparence and added a check for errors (even if not fully correct comparing floats).