2

In this code I am trying to read all the data from the file using the fread() function. The problem is that nothing is read in the array. How can fix the error?

#include <stdio.h>

void func(const char *srcFilePath)
{
    FILE *pFile = fopen(srcFilePath, "r");
    float daBuf[30];
   
    if (pFile == NULL)
    {
        perror(srcFilePath);
    } else {
        while (!feof(pFile)) {
            fread(daBuf, sizeof(float), 1, pFile);
        }
    }
    for (int i = 0; i < 5; i++) {
        printf(" daBuf  = %f \n", daBuf[i]);
    }
}

void main() {
    const char inputfile[] = "/home/debian/progdir/input";
    func(inputfile);
}

The input file has values like this:

1.654107,
1.621582,
1.589211,
1.557358,
1.525398,
1.493311,
1.483532,
1.483766,
1.654107,
chqrlie
  • 131,814
  • 10
  • 121
  • 189
stella
  • 23
  • 6
  • 7
    [Why is “while( !feof(file) )” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong) – Some programmer dude Aug 28 '23 at 15:08
  • 2
    As for your problem, you read into `daBuf`, then in the next iteration of the loop you read into the exact same buffer, overwriting the old contents. – Some programmer dude Aug 28 '23 at 15:09
  • 2
    Furthermore, you attempt to print five elements, no matter how many are actually in the buffer. – Some programmer dude Aug 28 '23 at 15:10
  • 3
    Lastly, `fread` reads raw *binary* data. If you have text, you need to use functions that reads the text, and *parses* it into the expected value-type. It's the same issue as the string `"1.2"` is not the same as the floating-point value `1.2`. – Some programmer dude Aug 28 '23 at 15:10
  • 1
    You've got random constants like `30`, `5` in this code, and that's a bad habit to get into. You should have *one* definition that's consistent. – tadman Aug 28 '23 at 15:11
  • I have floating data in the file. I print just 5 numbers, that's just for example. – stella Aug 28 '23 at 15:19
  • 1
    You still did not clarify if the yontents of the input file is text or binary. How do you create the input file or how do you display its contents? – Bodo Aug 28 '23 at 16:22

2 Answers2

1

Your file contains formatted text, so you can use fscanf.

Ensure that you are reading data into a new position in the array every iteration, and that you do not go beyond the bounds of the array.

Use the return value of fscanf to control your loop.

Notice the format string for fscanf is "%f,".

#include <stdio.h>

#define BUFMAX 32

void func(const char *srcFilePath)
{
    FILE *pFile = fopen(srcFilePath, "r");

    if (!pFile) {
        perror(srcFilePath);
        return;
    }

    float daBuf[BUFMAX];
    size_t n = 0;

    while (n < BUFMAX && 1 == fscanf(pFile, "%f,", &daBuf[n]))
        n++;

    if (ferror(pFile))
        perror(srcFilePath);

    fclose(pFile);

    for (size_t i = 0; i < n; i++)
        printf("daBuf[%zu] = %f\n", i, daBuf[i]);
}

int main(void)
{
    const char inputfile[] = "/home/debian/progdir/input";

    func(inputfile);
}
daBuf[0] = 1.654107
daBuf[1] = 1.621582
daBuf[2] = 1.589211
daBuf[3] = 1.557358
daBuf[4] = 1.525398
daBuf[5] = 1.493311
daBuf[6] = 1.483532
daBuf[7] = 1.483766
daBuf[8] = 1.654107

fread is generally intended for binary data, in which case you would open the file with the additional "b" mode.

Here is an example, if your file contained binary data:

#include <stdio.h>

#define BUFMAX 32

void func(const char *srcFilePath)
{
    FILE *pFile = fopen(srcFilePath, "rb");

    if (!pFile) {
        perror(srcFilePath);
        return;
    }

    float daBuf[BUFMAX];
    size_t n = fread(daBuf, sizeof *daBuf, BUFMAX, pFile);

    if (ferror(pFile))
        perror(srcFilePath);

    fclose(pFile);

    for (size_t i = 0; i < n; i++)
        printf("daBuf[%zu] = %f\n", i, daBuf[i]);
}

int main(void)
{
    const char inputfile[] = "/home/debian/progdir/input";

    func(inputfile);
}
Oka
  • 23,367
  • 6
  • 42
  • 53
  • 1
    Thank you Oka, but with fread() I got on this output: daBuf[0] = 0.000001 daBuf[1] = 0.000011 daBuf[2] = 0.000000 daBuf[3] = 0.000001 daBuf[4] = 0.000000 daBuf[5] = 0.000043 daBuf[6] = 0.000000 daBuf[7] = 0.000000 daBuf[8] = 0.000000 daBuf[9] = 0.000000 – stella Aug 28 '23 at 15:40
  • fscanf print just the first number in the file. When I print n, I got n=1. – stella Aug 28 '23 at 15:49
  • @stella Answer amended. The format string you use for `fscanf` is specific to the way your text is formatted in the file. If your values are separated by a comma, then you must consume that comma as well. – Oka Aug 28 '23 at 17:17
  • I remove the comma from the input file. fscanf now work correctly but fread() does not work yet :( – stella Aug 28 '23 at 22:05
  • Why can not read correctly with fread(). in fact I can not understand the problem – stella Aug 28 '23 at 22:09
  • 3
    `fread` does not read formatted text. It reads raw bytes - binary data. The *text* `1.654107` is not the same as the binary representation of that floating-point value. If you want to read binary data, you have to first *create* it (with `fwrite`, or various tools). – Oka Aug 29 '23 at 00:34
1

You may be confusing binary representation and ascii representation of number. Here is a small code to generate a binary file using the first 5 data in your input file.

#include <stdio.h>

int main()
{
    float x[5] = {1.654107, 1.621582, 1.589211, 1.557358, 1.525398};
    char outfile[] = "output.bin";
    FILE *fp;

    if (NULL == (fp = (fopen(outfile, "wb")))) {
        perror(outfile);
        exit(1);
    }
    fwrite(x, sizeof(float), 5, fp);
    fclose(fp);

    return 0;
}

If you compile and execute it, a file output.bin will be generated. As you seem to be working on debian, try xxd command to dump the binary file:

$ xxd output.bin
0000000: c7b9 d33f 0090 cf3f 446b cb3f 8257 c73f  ...?...?Dk.?.W.?
0000010: 3e40 c33f                                >@.?

The first 4-byte data c7b9d33f corresponds to the first number 1.654107. (Note the byte order depends on the endianness of the processor architecture.)

In general we don't care what c7b9d33f means because binary data is not human readable. If you are interested in the format, search google for IEEE754. The important thing is fread() and fwrite() are designed to read/write binary data.

Your posted program can be used to read output.bin with some corrections:

#include <stdio.h>

void func(const char *srcFilePath)
{
    int i;
    float daBuf[30];
    FILE *pFile = fopen(srcFilePath, "rb");

    if (pFile == NULL) {
        perror(srcFilePath);
        exit(1);
    }
    fread(daBuf, sizeof(float), 5, pFile);      // read 5 float data in an array
    for (i = 0; i < 5; i++) {
        printf(" daBuf  = %f \n", daBuf[i]);    // print them
    }
}

int main()
{
    const char inputfile[] = "output.bin";
    func(inputfile);
    return 0;
}

Output:

 daBuf  = 1.654107
 daBuf  = 1.621582
 daBuf  = 1.589211
 daBuf  = 1.557358
 daBuf  = 1.525398

You still have a mistake in the usage of fread(). You are passing the fixed address daBuf to fread() in the loop as fread(daBuf, sizeof(float), 1, pFile). It just modifies the first element daBuf[0] repeatedly without assigning other elements. You can read multiple elements of data at once by passing the length as the 3rd argument to fread().

As you may have roughly grasped the binary data, let's go back to ascii data. Try to dump your input (w/o commas) with xxd:

$ xxd input
0000000: 312e 3635 3431 3037 0a31 2e36 3231 3538  1.654107.1.62158
0000010: 320a 312e 3538 3932 3131 0a31 2e35 3537  2.1.589211.1.557
0000020: 3335 380a 312e 3532 3533 3938 0a31 2e34  358.1.525398.1.4
0000030: 3933 3331 310a 312e 3438 3335 3332 0a31  93311.1.483532.1
0000040: 2e34 3833 3736 360a 312e 3635 3431 3037  .483766.1.654107
0000050: 0a                                       .

If you read the file input by using fread(), the first element daBuf[0], for instance, will be assigned to 4-byte data 312e3635, which will be meaningless as a binary representation.

I hope you will have understood why you cannot use fread() to read ascii files.

tshiono
  • 21,248
  • 2
  • 14
  • 22