0

I have 8 files (file%d-%d.dat) each with 2 columns and 1000 rows:

 File1-1     File1-2    File1-3     File1-4
 x1a y1a     x1b y1b    x1c y1c     x1d y1d 
 x2a y2a     x2b y2b    x2c y2c     x2d y2d
 x3a y3a     x3b y3b    x3c y3c     x3d y3d
 .           .          .           .
 .           .          .           .


 File2-1     File2-2    File2-3     File2-4   
 x1e y1e     x1f y1f    x1g y1g     x1h y1h 
 x2e y2e     x2f y2f    x2g y2g     x2h y2h
 x3e y3e     x3f y3f    x3g y3g     x3h y3h
 .           .          .           .
 .           .          .           .

I want to sum the second column of each file File%d-1 row by row and write the sum in a new file: Filesum1; same for File%d-2 and so on, i.e.,

Filesum1                           Filesum2                and so on  ..
x1a+x1e     y1a+y1e                 x1b+x1f   y1b+y1f           .
x2a+x3e     y2a+y2e                 x2b+x2f   y2b+y2f           .
.           .                       .         .
.           .                       .         .                 . 

I created 4 new files:

#include <stdio.h>
int main(void)  
{          
int numfiles=4;
int numfileread=8;
int i,yy1, yy2, x0, x1;

FILE *files[numfiles];
FILE *f[numfileread];

for (int n = 0; n < 4; n++)
{
    char filename[4];
    sprintf(filename, "filesum%d.dat", n);
    files[n] = fopen(filename, "w");
}

Then I've tried this, but it does not work correctly:

for (int n = 0; n < 4; n++)
{
   yy1=0;
   yy2=0;
   for(int r=1;r<4;r++)
   {
       char file[8];
       sprintf(file, "file%d-%d.dat", r, n);
       f[i] = fopen(file, "r");
       fscanf(f," %d  %d",&x0,&x1);
       yy1+=x0;
       yy2+=x1;
       fclose(f);
       i++;
   }
   fprintf(files,"%d %d\n",yy1, yy2);
   fclose(files);
}

If I had the same assignment, but for reading 50 files:

readFile1, readFile2, readFile3, ......., readFile50

How can I change the code?

Stoogy
  • 1,307
  • 3
  • 16
  • 34
Carla
  • 9
  • 4
  • 1
    That probably doesn't *build*, since you're passing the wrong type to `fclose()` for instance. Make it compile first, then update with the code that actually builds. – unwind Feb 19 '19 at 10:01
  • 1
    Can you add what is "not working"? Do you get a wrong result, a segfault,.. ? – Stoogy Feb 19 '19 at 10:02
  • Aren't you complicating things here? In each pass, you have three files: The two input files and the output file with the sums. That should be easy to handle. Then you have four independent passes where you create `Filename1` to `Filename4`. – M Oehm Feb 19 '19 at 10:09
  • Any particular reason you're doing this in C and not with, say, a shell one liner? `paste -d ' ' File1-1 File2-1 | awk '{ print $1+$3, $2+$4 }' > Filesum1` or something? – Shawn Feb 19 '19 at 11:38
  • @Shawn Because I had to read 50 files, so I need to loops. – Carla Feb 20 '19 at 09:30
  • @MOehm No, bacause I semplified the problem with few files, but I had to read 50 file. – Carla Feb 20 '19 at 09:33
  • @Stoogy the errors are: error: cannot convert ‘FILE** {aka _IO_FILE**}’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to ‘int fscanf(FILE*, const char*, ...)’ fscanf(f," %d %d",&x0,&x1); error: cannot convert ‘FILE** {aka _IO_FILE**}’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to ‘int fprintf(FILE*, const char*, ...)’ fprintf(files,"%d %d\n",yy1, yy2); – Carla Feb 20 '19 at 10:14
  • @Carla Can you edit your question with the new details ? – Stoogy Feb 20 '19 at 10:19
  • Hm. In your example, you sum `File1-1` and `File2-1`; then you sum `File1-2` and `File2-2`. These operations are independent of each other. (I guess that your 50 are the 4 in the example, so that you are going to sum `File1-50` and `File2-50`, but _not_ `File1-1`through `File50-1`.) – M Oehm Feb 20 '19 at 10:24
  • @MOehm they are File1-1 up to File50-1; File1-2 up to File50-2; File1-3 up to File50-3; and so on... – Carla Feb 20 '19 at 10:34
  • @Stoogy I accept your edit , thank you! – Carla Feb 20 '19 at 10:39

2 Answers2

0

There are multiple issue:

  1. This loop will only three times, I think you intended it to run 4 times.

    for(int r=1;r<4;r++)

  2. Char array file does not has sufficient space to hold string "file%d-%d.dat"

  3. fclose(f); needs to be changed to fclose(f[i]);

  4. You need to specify an index for files.

    fprintf(files,"%d %d\n",yy1, yy2);

This is what I came up with. You can try it out.

#include <stdio.h>

int main(){
        FILE *readFile1;
        FILE *readFile2;
        FILE *writeFile;
        char inFile1[32] = {0};
        char inFile2[32] = {0};
        char sumFile[32] = {0};
        int i,xa,xb,ya,yb;
        int ret1;ret2;
        for(i=0;i<4;i++){
                sprintf(inFile1, "File1-%d", i); 
                sprintf(inFile2, "File2-%d", i); 
                sprintf(sumFile, "sumFile%d", i); 
                readFile1 = fopen(inFile1, "r");
                readFile2 = fopen(inFile2, "r");
                writeFile = fopen(sumFile, "w");
                while(1){
                        ret1 = fscanf(readFile1, "%d %d", &xa, &ya);
                        ret2 = fscanf(readFile2, "%d %d", &xb, &yb);
                        if( (ret1 != 2) || (ret2 != 2) )
                                break;
                        fprintf(writeFile, "%d %d", xa+xb, ya+yb);
                }   
                fclose(readFile1);
                fclose(readFile2);
                fclose(writeFile);
        }   
        return 1;
}
Sandy
  • 895
  • 6
  • 17
  • 1
    [Why is “while (!feof(file))” always wrong?](https://stackoverflow.com/questions/5431941/why-is-while-feoffile-always-wrong) – Swordfish Feb 19 '19 at 13:55
  • Declare/define variables as close as possible to where they're used. – Swordfish Feb 19 '19 at 14:00
  • Thank you! If I had the same problem, but if I had to read 50 files, for example: readFile1, readFile2, readFile3, ......., readFile50? How can I change the code? – Carla Feb 19 '19 at 15:45
  • @Carla You just need to structure the outer for loop to suit your needs e.g. if you have to read 50 files and sum them up to output 25 files, you will need to change the for loop to run 25 times instead of 4. – Sandy Feb 20 '19 at 03:49
  • @Sandeep I tried to write it as so as in the code I posted, but there are errors and I do not know how to change it. – Carla Feb 20 '19 at 09:20
  • @Carla can you post the errors? Are the filenames consistent with the code? – Sandy Feb 20 '19 at 10:00
  • @Sandeep the errors are: error: cannot convert ‘FILE** {aka _IO_FILE**}’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to ‘int fscanf(FILE*, const char*, ...)’ fscanf(f," %d %d",&x0,&x1); error: cannot convert ‘FILE** {aka _IO_FILE**}’ to ‘FILE* {aka _IO_FILE*}’ for argument ‘1’ to ‘int fprintf(FILE*, const char*, ...)’ fprintf(files,"%d %d\n",yy1, yy2); ^ – Carla Feb 20 '19 at 10:11
  • @Carla From the error it looks like that `f` is an array of `FILE` type and you are passing array name instead of array element to fscanf. It would help if you can share code. – Sandy Feb 20 '19 at 10:19
0

Okay, so you have a large number of files and want to sum two columns of data over these files. You also know that you will have 1000 rows of data in each file. You could try to keep all files open with an array of file handles and read from them in turn, but that's too complicated. Instead:

  • define an array for each column and initialise it to zero;
  • open one file at a time, read the data, add it to the array and close that file;
  • write the summed data to the results file.

There will always be at most one open file with this solution.

The code would look like this:

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

enum {
    nData = 1000,       // number of rows
    nFiles = 50,        // number of files per block
    nBlocks = 4         // number of blocks
                        // nomenclature: file{file}-{block}.dat
};

int main(void)
{
    for (int j = 0; j < nBlocks; j++) {
        double col1[nData] = {0.0};
        double col2[nData] = {0.0};

        char outn[32];
        FILE *out;

        for (int i = 0; i < nFiles; i++) {
            char fn[32];
            FILE *f;

            snprintf(fn, sizeof(fn), "file%d-%d.dat", i, j);

            f = fopen(fn, "r");
            if (f == NULL) {
                fprintf(stderr, "Could not open '%s'.\n", fn);
                exit(1);
            }

            for (int k = 0; k < nData; k++) {
                char line[80];
                double x, y;

                if (fgets(line, sizeof(line), stdin) == NULL) break;
                if (sscanf(line, "%lf %lf", &x, &y) != 2) continue;

                col1[k] += x;
                col2[k] += y;
            }

            fclose(f);
        }

        snprintf(outn, sizeof(outn), "filesum-%d.dat", j);

        out = fopen(outn, "r");
        if (out == NULL) {
            fprintf(stderr, "Could not write to '%s'.\n", outn);
            exit(1);
        }

        for (int k = 0; k < nData; k++) {
            fprintf(out, " %15g %15g\n", col1[k], col2[k]);
        }

        fclose(out);        
    }

    return 0;
}

Season to taste.

M Oehm
  • 28,726
  • 3
  • 31
  • 42