Emotional Damage
Emotional Damage

Reputation: 148

Reading multiple files with different number of lines

I am trying to read arrays from multiple files, and the array size in each file is different. So what I do is, I try to count the number of lines in the file and then store that as the array size.

For example, I have two .txt files, File_1.txt and File_2.txt which contain the following data:

0.000 300.00
0.054 2623.3
1.000 300.00
0.000 300.00
0.054 2623.3
0.500 1500.0
1.000 300.00

respectively.

Here is the code that I use:

int main()
{
    char filter[1024];
    char filename[60];
    FILE *fp;
    double *T_SR, Z_SR;

    for (int i = 1; i < 3; i++)
    {
        sprintf(filename, "File_%d.txt", i);
        fp = fopen(filename, "r");
        if (fp == NULL)
        {
            exit(1);
        }

        int count = 0;
        for (int j = getc(fp); j != EOF; j = getc(fp))
        {
            if (j == '\n')
            {
                count = count + 1;
            }
        }

        T_SR = (double *)malloc(count * sizeof(double));
        Z_SR = (double *)malloc(count * sizeof(double));

        for (int rows = 0; rows < count; rows++)
        {
            fscanf(fp, "%lf %lf", &Z_SR[rows], &T_SR[rows]);
            printf("%lf %lf\n", Z_SR[rows], T_SR[rows]);
            if (feof(fp))
            {
                break;
            }
        }
    }
}

But instead of printing the given array as output, it prints this:

0.0000 0.0000
0.0000 0.0000

I checked the value of count, it's good. Maybe the problem is simple, but I am not able to find it. Can someone please help?

Upvotes: 2

Views: 129

Answers (3)

chux
chux

Reputation: 153517

I try to count the number of lines in the file and then store that as the array size.

Aside from the key rewind() issue, avoid reading code one way to find line count and another to find the doubles. Far too easy to get a line count that does not match the "line count" of reading two doubles.

Use one approach to find both.

size_t read_SR(size_t count, double *Z_SR, double *T_SR, FILE *inf) {
  char line[100];
  rewind(inf);
  size_t rows;
  while (fgets(line, sizeof line, inf)) {
    double Z, T; 
    if (sscanf(line, "%lf %lf", &Z, &T) != 2) return rows;
    if (rows < count) {
      if (Z_SR) Z_SR[rows] = Z;
      if (T_SR) T_SR[rows] = T;
    }
    rows++;
  }
  return rows;
}  

Usage

// First pass, find size
size_t count = read_SR(0, NULL, NULL, inf);
double *T_SR = malloc(sizeof *T_SR * count);
double *Z_SR = malloc(sizeof *Z_SR * count);
// 2nd pass, save data
read_SR(count, Z_SR, T_SR, inf);

Upvotes: 2

anastaciu
anastaciu

Reputation: 23802

After you ran the whole file with getc the file indicator will be at the end of the file you must set it back to the beginning before you use fscanf, you can use rewind for that.

rewind(fp); //<--
for (int rows = 0; rows < count; rows++)
{
    //...
}

Aside from that, other problems exist as Jaberwocky pointed out, among others, like a memory leak issue, and the fact that you don't close your files or check malloc return, here's how your code could look like (with comments):

double *T_SR, *Z_SR; // fix the pointer issue
//...
char line[1024]; // make sure it's larger than the largest line in the file

while (fgets(line, sizeof line, fp)) // fixes the count issue
{
    // doesn't count empty lines, if there are any
    if (line[0] != '\n')
    {
         count++;
    }
}
if(count > 0)
{
    T_SR = malloc(count * sizeof *T_SR);
    Z_SR = malloc(count * sizeof *Z_SR);
    if(T_SR == NULL || Z_SR == NULL) // check memory allocation
    {
        perror("malloc");
        return EXIT_FAILURE;
    }

    rewind(fp);
    for(int rows = 0; fscanf(fp, "%lf%lf", &Z_SR[rows], &T_SR[rows]) == 2; rows++)
    {
         printf("%lf %lf\n", Z_SR[rows], T_SR[rows]);
    }
    free(T_SR); // free the memory, avoids memory leaks
    free(Z_SR);
}
fclose(fp); // and close the file
//...

Live demo

Upvotes: 3

Jabberwocky
Jabberwocky

Reputation: 50802

There are several bugs:

  1. The most important one is the rewind issue that has been addressed in anastaciu's anwer.
  2. double * T_SR, Z_SR is wrong, it should be double * T_SR, *Z_SR. I wonder actually if the code you posted is the code you compile.
  3. your line counting method is flawed. If the last line of the file does not end with a \n, the count variable will be 2 and you'll miss the last line.
  4. fscanf returns the number of items read or EOF. If you had check that, you might have found the problem in your code yourself.
  5. the feof check is done too late, if fscanf encounters en EOF you still print the values that have not bee read due to the EOF condition.

Upvotes: 3

Related Questions