1

My data is as follows:

0.05 1.3
0.09 1.8
0.12 1.9

I create two variables x and y to store them respectively.

    FILE *fp_data;
    double *x;
    double *y;
    int data_size;
    char ch;
    int i;

    fp_data = fopen(path, "r");
    while( ( ch = fgetc(fp_data)) != EOF) if(ch=='\n') ++data_size;

    if (!fp_data)
    {
        printf("Data file cannot open...\n");
        exit(1);
    }
    else
    {   
        x = (double*)malloc(data_size * sizeof(double));
        y = (double*)malloc(data_size * sizeof(double));
        
        printf("\n%d\n\n", data_size);
        
        for (i = 0; i < data_size; ++i)
        {
            fscanf(fp_data, "%lf %lf\n", &x[i], &y[i]);

        }
        
        fclose(fp_data);
        
        for (i = 0; i < data_size; ++i)
        {
            printf("%d- %f %f\n", i, x[i], y[i]);
            
        }
    }

I notice that my results are wrong like:

0.000000 0.000000
0.000000 0.000000
0.000000 0.000000

However, if I remove thewhile( (ch = fgetc(fp_data)) != EOF ) if(ch=='\n') ++data_size; code and set data_size manually, then everything is fine.

Does anyone know what is the problem of the fgetc code?

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
Heng
  • 43
  • 1
  • 6

1 Answers1

0

There are a few errors in your code.

First, you never initialize the data_size variable; this is undefined behaviour: although some compilers/platforms may set the initial value of such 'automatic' variables to zero, you should never rely on that. Solution: explicitly initialize to zero at the time of declaration: int data_size = 0;.

Second, you should check for a failure to open the file before any further operations on the fp_data file pointer (although I cannot find an explicit mention of it in the C Standard, calling fgetc() with a NULL pointer is likely to cause undefined behaviour). By putting that check in the appropriate place, you can dispense with the else conditional block (as your program calls exit(1) if the fopen() call fails).

Third, you need to reset the file pointer to the beginning of the stream after your while ((ch = fgetc(fp_data)) != EOF) ... loop! Otherwise, you will be attempting to read your data from a file that is already at EOF. You can use the rewind() function to do this.

Fourth: Note that the fgetc function returns an int, not a char; using a char type can cause problems in detecting the EOF signal

Other points:

  1. Don't forget to free the allocated memory after use.
  2. Do I cast the result of malloc?
  3. For robustness, use the size_t type for data_size (and i).

Here's a version of your code with the above points address (and commented):

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

char path[] = "test.txt"; // Or whatever!

int main()
{
    FILE* fp_data;
    double* x;
    double* y;
    size_t data_size = 0; // MUST initialize to zero
    int ch; // Note: "fgetc" return an "int" type, not "char"
    size_t i;

    fp_data = fopen(path, "r");
    if (!fp_data) {
        printf("Data file cannot open...\n");
        exit(1);
    }

    while ((ch = fgetc(fp_data)) != EOF) if (ch == '\n') ++data_size;

    rewind(fp_data); // MUST rewind the file to the beginning, before reading the data!

    x = malloc(data_size * sizeof(double));
    y = malloc(data_size * sizeof(double));
    printf("\n%zu\n\n", data_size);
    for (i = 0; i < data_size; ++i) { // Use the "%zu" format for "Size_t" types
        fscanf(fp_data, "%lf %lf\n", &x[i], &y[i]);
    }

    fclose(fp_data);

    for (i = 0; i < data_size; ++i) {
        printf("%zu- %f %f\n", i, x[i], y[i]);
    }

    free(x); // Release allocated memory after use.
    free(y);

    return 0;
}
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83