2

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?

anastaciu
  • 23,467
  • 7
  • 28
  • 53
Emotional Damage
  • 138
  • 1
  • 1
  • 9

3 Answers3

3

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

anastaciu
  • 23,467
  • 7
  • 28
  • 53
  • @UdayCK, I added a possible implementation, fixing the other problems. – anastaciu Apr 22 '21 at 09:21
  • This is very nice. Thanks a lot. But instead of `T_SR` and `Z_SR`, let us say we had many arrays like that. Do I have to hardcode everything? For ex: `if(T_SR==NULL || Z_SR == NULL || CH4_SR == NULL || ....`). Or is there a simpler way? @anastaciu – Emotional Damage Apr 22 '21 at 09:48
  • @UdayCK, if the arrays are individually named and allocated, then yes, but you can have an array of arrays to store all of them there using a pointer to array, in that case only one allocation and deallocation is needed, a [quick google search](https://www.google.com/search?client=firefox-b-d&q=memory+allocation+for+pointer+to+array) rendered me some SO posts that teach how to do this, if you don't find them helpful ask a new question, it looks interesting to me and would be for sure well received. – anastaciu Apr 22 '21 at 10:06
3

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.
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
  • Very helpful suggestions. In fact, I forgot the second asterisk while posting the code on StackOverflow. I understood all the points that you have posted except for the third. I don't understand what you mean when you say if the last line does not end with \n. Can you please elaborate? @Jabberwocky – Emotional Damage Apr 22 '21 at 07:48
  • @UdayCK open your text editor to create a new file, type `123`, don't press Enter and save the file. Now that file contains one line that _does not_ end with a `\n`. Now open that file again in the text editor, put the cursor right after the `3`, press Enter and save the file. Now that file contains one line that _does_ end with a `\n`. – Jabberwocky Apr 22 '21 at 07:52
  • Ok, now I understand what you mean. It prints zero when there is an empty line at the end of the file. Thanks again. @Jabberwocky – Emotional Damage Apr 22 '21 at 07:56
  • To ignore the last line that does not end with `\n`, I made a condition like this. `int last = '\n' ;` and then `if (j == '\n' && last !='\0') count = count + 1 ` . But it still prints the last line. What am I doing wrong? @Jabberwocky – Emotional Damage Apr 22 '21 at 08:34
  • @UdayCK you should ask another question for this specific problem. Like "How to count the number of lines in a file?". Maybe there is already a duplicate. – Jabberwocky Apr 22 '21 at 08:36
  • @UdayCK like here: https://stackoverflow.com/questions/29751837/counting-number-of-lines-in-the-file-in-c. Or just google "Counting number of lines in the file in C" – Jabberwocky Apr 22 '21 at 08:38
2

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);
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256