Search code examples
cio

Errors in file reading in binary mode with language C


I do exercice of 'c primer plus' chapter 13.10-4: Write a program that accepts no or one command line argument. If there is one, interpret it as a filename; if there is no argument, use standard input (stdin) as input. Assume the input is a floating point number. The program is to calculate and report the arithmetic mean of the entered numbers.

result

The part of standard input can work well when excecute visual studio, but when write and read the file with cmd, average value is "nan" enter image description here

enviroment

I use win10, le latest version of Visual Studio

code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
    double ch;
    double numbers[12];
    FILE* fp;
    double average=0;
    int i = 0;
    if (argc==1)
    {
        printf("enter double, end with q\n");
        while (scanf_s("%lf", &ch))
        {
            average += ch;
            printf("%lf\n", ch);
            i++;
        }
    }
    else
    {
        for (int j = 0; j < 12; j++)
            numbers[j] = 10.1 * j;
        fopen_s(&fp, argv[1], "wb");
        fwrite(numbers, sizeof(double), 10, fp);
        fclose(fp);
        if ((fopen_s(&fp, argv[1], "rb")!=0))
        {
            fprintf(stdout,"cant find %s\n", argv[1]);
            exit(EXIT_FAILURE);
        }           
        while (fseek(fp, (long)i * sizeof(double), SEEK_SET)!=0)
        {
            fread(&ch, sizeof(double), 1, fp);
            fprintf(stdout, "ch\n");
            average += ch;
            i++;
        }
        fclose(fp);
    }
    printf("average is %lf\n", average/i);
    return 0;
}

Solution

  • You are using the wrong test for fseek() with

    while (fseek(fp, (long)i * sizeof(double), SEEK_SET)!=0)
    

    The man page states

    Return Value.
    If successful, fseek and _fseeki64 returns 0.

    But even if you change !=0 to ==0 it is still wrong, because the man page also says

    The pointer can also be positioned beyond the end of the file.

    Because file reads are sequential, you can simplify the loop to

    while (fread(&ch, sizeof(double), 1, fp) == 1)
    {
        fprintf(stdout, "ch\n");
        average += ch;
        i++;
    }
    

    You also omitted the essential check for file input: the return value from fread() was ignored.